Merge "atrace: New --prefer_sdk flag" into main am: 5e1cbe0668 am: cb30dd6bdf
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/3042215
Change-Id: I0f5afa67f8abc36d8d1f2aa4f6622bc038f3ec1d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/include/input/Input.h b/include/input/Input.h
index ec08cdd..456977b 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -25,6 +25,7 @@
#include <android/input.h>
#ifdef __linux__
#include <android/os/IInputConstants.h>
+#include <android/os/MotionEventFlag.h>
#endif
#include <android/os/PointerIconType.h>
#include <math.h>
@@ -69,15 +70,17 @@
* actual intent.
*/
AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED =
- android::os::IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED,
+ static_cast<int32_t>(android::os::MotionEventFlag::WINDOW_IS_PARTIALLY_OBSCURED),
+
AMOTION_EVENT_FLAG_HOVER_EXIT_PENDING =
- android::os::IInputConstants::MOTION_EVENT_FLAG_HOVER_EXIT_PENDING,
+ static_cast<int32_t>(android::os::MotionEventFlag::HOVER_EXIT_PENDING),
+
/**
* This flag indicates that the event has been generated by a gesture generator. It
* provides a hint to the GestureDetector to not apply any touch slop.
*/
AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE =
- android::os::IInputConstants::MOTION_EVENT_FLAG_IS_GENERATED_GESTURE,
+ static_cast<int32_t>(android::os::MotionEventFlag::IS_GENERATED_GESTURE),
/**
* This flag indicates that the event will not cause a focus change if it is directed to an
@@ -86,27 +89,27 @@
* into focus.
*/
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE =
- android::os::IInputConstants::MOTION_EVENT_FLAG_NO_FOCUS_CHANGE,
+ static_cast<int32_t>(android::os::MotionEventFlag::NO_FOCUS_CHANGE),
/**
* This event was generated or modified by accessibility service.
*/
AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
- android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT,
+ static_cast<int32_t>(android::os::MotionEventFlag::IS_ACCESSIBILITY_EVENT),
AMOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS =
- android::os::IInputConstants::MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS,
+ static_cast<int32_t>(android::os::MotionEventFlag::TARGET_ACCESSIBILITY_FOCUS),
/* Motion event is inconsistent with previously sent motion events. */
- AMOTION_EVENT_FLAG_TAINTED = android::os::IInputConstants::INPUT_EVENT_FLAG_TAINTED,
+ AMOTION_EVENT_FLAG_TAINTED = static_cast<int32_t>(android::os::MotionEventFlag::TAINTED),
/** Private flag, not used in Java. */
AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION =
- android::os::IInputConstants::MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION,
+ static_cast<int32_t>(android::os::MotionEventFlag::PRIVATE_FLAG_SUPPORTS_ORIENTATION),
/** Private flag, not used in Java. */
- AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = android::os::IInputConstants::
- MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION,
+ AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = static_cast<int32_t>(
+ android::os::MotionEventFlag::PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION),
/** Mask for all private flags that are not used in Java. */
AMOTION_EVENT_PRIVATE_FLAG_MASK = AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h
index 222dac8..9bbaa0c 100644
--- a/include/input/VirtualInputDevice.h
+++ b/include/input/VirtualInputDevice.h
@@ -122,4 +122,11 @@
bool handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime);
};
+class VirtualRotaryEncoder : public VirtualInputDevice {
+public:
+ VirtualRotaryEncoder(android::base::unique_fd fd);
+ virtual ~VirtualRotaryEncoder() override;
+ bool writeScrollEvent(float scrollAmount, std::chrono::nanoseconds eventTime);
+};
+
} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index ff6b558..2699368 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -62,7 +62,7 @@
status_t setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
InputWindowCommands commands, int64_t desiredPresentTime, bool isAutoTimestamp,
const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index af91bb3..5db5394 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1059,7 +1059,8 @@
uncacheBuffer.token = BufferCache::getInstance().getToken();
uncacheBuffer.id = cacheId;
Vector<ComposerState> composerStates;
- status_t status = sf->setTransactionState(FrameTimelineInfo{}, composerStates, {},
+ Vector<DisplayState> displayStates;
+ status_t status = sf->setTransactionState(FrameTimelineInfo{}, composerStates, displayStates,
ISurfaceComposer::eOneWay,
Transaction::getDefaultApplyToken(), {}, systemTime(),
true, {uncacheBuffer}, false, {}, generateId(), {});
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index eb4a802..1ecc216 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -112,7 +112,7 @@
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
InputWindowCommands inputWindowCommands, int64_t desiredPresentTime,
bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffer,
bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 9cf62bc..7ee291d 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -74,6 +74,7 @@
} // namespace android::gui
using android::gui::METADATA_ACCESSIBILITY_ID;
+using android::gui::METADATA_CALLING_UID;
using android::gui::METADATA_DEQUEUE_TIME;
using android::gui::METADATA_GAME_MODE;
using android::gui::METADATA_MOUSE_CURSOR;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 43cd0f8..5e91088 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -636,7 +636,7 @@
status_t setTransactionState(
const FrameTimelineInfo& /*frameTimelineInfo*/, Vector<ComposerState>& /*state*/,
- const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
+ Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/, InputWindowCommands /*inputWindowCommands*/,
int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
const std::vector<client_cache_t>& /*cachedBuffer*/, bool /*hasListenerCallbacks*/,
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index d782f42..c2a7ebb 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -30,6 +30,7 @@
"android/os/InputEventInjectionResult.aidl",
"android/os/InputEventInjectionSync.aidl",
"android/os/InputConfig.aidl",
+ "android/os/MotionEventFlag.aidl",
"android/os/PointerIconType.aidl",
],
}
diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp
index eea06f1..b73ee65 100644
--- a/libs/input/VirtualInputDevice.cpp
+++ b/libs/input/VirtualInputDevice.cpp
@@ -509,4 +509,15 @@
return true;
}
+// --- VirtualRotaryEncoder ---
+VirtualRotaryEncoder::VirtualRotaryEncoder(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+
+VirtualRotaryEncoder::~VirtualRotaryEncoder() {}
+
+bool VirtualRotaryEncoder::writeScrollEvent(float scrollAmount,
+ std::chrono::nanoseconds eventTime) {
+ return writeInputEvent(EV_REL, REL_WHEEL, static_cast<int32_t>(scrollAmount), eventTime) &&
+ writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime);
+}
+
} // namespace android
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index a77dfa5..e23fc94 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -49,130 +49,24 @@
const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
/**
- * This flag indicates that the window that received this motion event is partly
- * or wholly obscured by another visible window above it and the event directly passed through
- * the obscured area.
- *
- * A security sensitive application can check this flag to identify situations in which
- * a malicious application may have covered up part of its content for the purpose
- * of misleading the user or hijacking touches. An appropriate response might be
- * to drop the suspect touches or to take additional precautions to confirm the user's
- * actual intent.
- */
- const int MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1;
-
- /**
- * This flag indicates that the window that received this motion event is partly
- * or wholly obscured by another visible window above it and the event did not directly pass
- * through the obscured area.
- *
- * A security sensitive application can check this flag to identify situations in which
- * a malicious application may have covered up part of its content for the purpose
- * of misleading the user or hijacking touches. An appropriate response might be
- * to drop the suspect touches or to take additional precautions to confirm the user's
- * actual intent.
- *
- * Unlike FLAG_WINDOW_IS_OBSCURED, this is only true if the window that received this event is
- * obstructed in areas other than the touched location.
- */
- const int MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2;
-
- /**
- * This private flag is only set on {@link #ACTION_HOVER_MOVE} events and indicates that
- * this event will be immediately followed by a {@link #ACTION_HOVER_EXIT}. It is used to
- * prevent generating redundant {@link #ACTION_HOVER_ENTER} events.
- * @hide
- */
- const int MOTION_EVENT_FLAG_HOVER_EXIT_PENDING = 0x4;
-
- /**
- * This flag indicates that the event has been generated by a gesture generator. It
- * provides a hint to the GestureDetector to not apply any touch slop.
- *
- * @hide
- */
- const int MOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8;
-
- /**
- * This flag is only set for events with {@link #ACTION_POINTER_UP} and {@link #ACTION_CANCEL}.
- * It indicates that the pointer going up was an unintentional user touch. When FLAG_CANCELED
- * is set, the typical actions that occur in response for a pointer going up (such as click
- * handlers, end of drawing) should be aborted. This flag is typically set when the user was
- * accidentally touching the screen, such as by gripping the device, or placing the palm on the
- * screen.
- *
- * @see #ACTION_POINTER_UP
- * @see #ACTION_CANCEL
+ * Common input event flag used for both motion and key events for a gesture or pointer being
+ * canceled.
*/
const int INPUT_EVENT_FLAG_CANCELED = 0x20;
/**
- * This flag indicates that the event will not cause a focus change if it is directed to an
- * unfocused window, even if it an {@link #ACTION_DOWN}. This is typically used with pointer
- * gestures to allow the user to direct gestures to an unfocused window without bringing the
- * window into focus.
- * @hide
- */
- const int MOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40;
-
- /**
- * This flag indicates that the event has a valid value for AXIS_ORIENTATION.
- *
- * This is a private flag that is not used in Java.
- * @hide
- */
- const int MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION = 0x80;
-
- /**
- * This flag indicates that the pointers' AXIS_ORIENTATION can be used to precisely determine
- * the direction in which the tool is pointing. The value of the orientation axis will be in
- * the range [-pi, pi], which represents a full circle. This is usually supported by devices
- * like styluses.
- *
- * Conversely, AXIS_ORIENTATION cannot be used to tell which direction the tool is pointing
- * when this flag is not set. In this case, the axis value will have a range of [-pi/2, pi/2],
- * which represents half a circle. This is usually the case for devices like touchscreens and
- * touchpads, for which it is difficult to tell which direction along the major axis of the
- * touch ellipse the finger is pointing.
- *
- * This is a private flag that is not used in Java.
- * @hide
- */
- const int MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = 0x100;
-
- /**
- * The input event was generated or modified by accessibility service.
- * Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either
- * set of flags, including in input/Input.h and in android/input.h.
+ * Common input event flag used for both motion and key events, indicating that the event
+ * was generated or modified by accessibility service.
*/
const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
/**
- * Private flag that indicates when the system has detected that this motion event
- * may be inconsistent with respect to the sequence of previously delivered motion events,
- * such as when a pointer move event is sent but the pointer is not down.
- *
- * @hide
- * @see #isTainted
- * @see #setTainted
+ * Common input event flag used for both motion and key events, indicating that the system has
+ * detected this event may be inconsistent with the current event sequence or gesture, such as
+ * when a pointer move event is sent but the pointer is not down.
*/
const int INPUT_EVENT_FLAG_TAINTED = 0x80000000;
- /**
- * Private flag indicating that this event was synthesized by the system and should be delivered
- * to the accessibility focused view first. When being dispatched such an event is not handled
- * by predecessors of the accessibility focused view and after the event reaches that view the
- * flag is cleared and normal event dispatch is performed. This ensures that the platform can
- * click on any view that has accessibility focus which is semantically equivalent to asking the
- * view to perform a click accessibility action but more generic as views not implementing click
- * action correctly can still be activated.
- *
- * @hide
- * @see #isTargetAccessibilityFocus()
- * @see #setTargetAccessibilityFocus(boolean)
- */
- const int MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000;
-
/* The default pointer acceleration value. */
const int DEFAULT_POINTER_ACCELERATION = 3;
diff --git a/libs/input/android/os/MotionEventFlag.aidl b/libs/input/android/os/MotionEventFlag.aidl
new file mode 100644
index 0000000..2093b06
--- /dev/null
+++ b/libs/input/android/os/MotionEventFlag.aidl
@@ -0,0 +1,152 @@
+/**
+ * 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 android.os;
+
+import android.os.IInputConstants;
+
+/**
+ * Flag definitions for MotionEvents.
+ * @hide
+ */
+@Backing(type="int")
+enum MotionEventFlag {
+
+ /**
+ * This flag indicates that the window that received this motion event is partly
+ * or wholly obscured by another visible window above it and the event directly passed through
+ * the obscured area.
+ *
+ * A security sensitive application can check this flag to identify situations in which
+ * a malicious application may have covered up part of its content for the purpose
+ * of misleading the user or hijacking touches. An appropriate response might be
+ * to drop the suspect touches or to take additional precautions to confirm the user's
+ * actual intent.
+ */
+ WINDOW_IS_OBSCURED = 0x1,
+
+ /**
+ * This flag indicates that the window that received this motion event is partly
+ * or wholly obscured by another visible window above it and the event did not directly pass
+ * through the obscured area.
+ *
+ * A security sensitive application can check this flag to identify situations in which
+ * a malicious application may have covered up part of its content for the purpose
+ * of misleading the user or hijacking touches. An appropriate response might be
+ * to drop the suspect touches or to take additional precautions to confirm the user's
+ * actual intent.
+ *
+ * Unlike FLAG_WINDOW_IS_OBSCURED, this is only true if the window that received this event is
+ * obstructed in areas other than the touched location.
+ */
+ WINDOW_IS_PARTIALLY_OBSCURED = 0x2,
+
+ /**
+ * This private flag is only set on {@link #ACTION_HOVER_MOVE} events and indicates that
+ * this event will be immediately followed by a {@link #ACTION_HOVER_EXIT}. It is used to
+ * prevent generating redundant {@link #ACTION_HOVER_ENTER} events.
+ * @hide
+ */
+ HOVER_EXIT_PENDING = 0x4,
+
+ /**
+ * This flag indicates that the event has been generated by a gesture generator. It
+ * provides a hint to the GestureDetector to not apply any touch slop.
+ *
+ * @hide
+ */
+ IS_GENERATED_GESTURE = 0x8,
+
+ /**
+ * This flag is only set for events with {@link #ACTION_POINTER_UP} and {@link #ACTION_CANCEL}.
+ * It indicates that the pointer going up was an unintentional user touch. When FLAG_CANCELED
+ * is set, the typical actions that occur in response for a pointer going up (such as click
+ * handlers, end of drawing) should be aborted. This flag is typically set when the user was
+ * accidentally touching the screen, such as by gripping the device, or placing the palm on the
+ * screen.
+ *
+ * @see #ACTION_POINTER_UP
+ * @see #ACTION_CANCEL
+ */
+ CANCELED = IInputConstants.INPUT_EVENT_FLAG_CANCELED,
+
+ /**
+ * This flag indicates that the event will not cause a focus change if it is directed to an
+ * unfocused window, even if it an {@link #ACTION_DOWN}. This is typically used with pointer
+ * gestures to allow the user to direct gestures to an unfocused window without bringing the
+ * window into focus.
+ * @hide
+ */
+ NO_FOCUS_CHANGE = 0x40,
+
+ /**
+ * This flag indicates that the event has a valid value for AXIS_ORIENTATION.
+ *
+ * This is a private flag that is not used in Java.
+ * @hide
+ */
+ PRIVATE_FLAG_SUPPORTS_ORIENTATION = 0x80,
+
+ /**
+ * This flag indicates that the pointers' AXIS_ORIENTATION can be used to precisely determine
+ * the direction in which the tool is pointing. The value of the orientation axis will be in
+ * the range [-pi, pi], which represents a full circle. This is usually supported by devices
+ * like styluses.
+ *
+ * Conversely, AXIS_ORIENTATION cannot be used to tell which direction the tool is pointing
+ * when this flag is not set. In this case, the axis value will have a range of [-pi/2, pi/2],
+ * which represents half a circle. This is usually the case for devices like touchscreens and
+ * touchpads, for which it is difficult to tell which direction along the major axis of the
+ * touch ellipse the finger is pointing.
+ *
+ * This is a private flag that is not used in Java.
+ * @hide
+ */
+ PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = 0x100,
+
+ /**
+ * The input event was generated or modified by accessibility service.
+ * Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either
+ * set of flags, including in input/Input.h and in android/input.h.
+ */
+ IS_ACCESSIBILITY_EVENT = IInputConstants.INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT,
+
+ /**
+ * Private flag that indicates when the system has detected that this motion event
+ * may be inconsistent with respect to the sequence of previously delivered motion events,
+ * such as when a pointer move event is sent but the pointer is not down.
+ *
+ * @hide
+ * @see #isTainted
+ * @see #setTainted
+ */
+ TAINTED = IInputConstants.INPUT_EVENT_FLAG_TAINTED,
+
+ /**
+ * Private flag indicating that this event was synthesized by the system and should be delivered
+ * to the accessibility focused view first. When being dispatched such an event is not handled
+ * by predecessors of the accessibility focused view and after the event reaches that view the
+ * flag is cleared and normal event dispatch is performed. This ensures that the platform can
+ * click on any view that has accessibility focus which is semantically equivalent to asking the
+ * view to perform a click accessibility action but more generic as views not implementing click
+ * action correctly can still be activated.
+ *
+ * @hide
+ * @see #isTargetAccessibilityFocus()
+ * @see #setTargetAccessibilityFocus(boolean)
+ */
+ TARGET_ACCESSIBILITY_FOCUS = 0x40000000,
+}
diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs
index 564d94d..c46b7bb 100644
--- a/libs/input/rust/input.rs
+++ b/libs/input/rust/input.rs
@@ -19,6 +19,7 @@
use crate::ffi::RustInputDeviceIdentifier;
use bitflags::bitflags;
use inputconstants::aidl::android::os::IInputConstants;
+use inputconstants::aidl::android::os::MotionEventFlag::MotionEventFlag;
use std::fmt;
/// The InputDevice ID.
@@ -193,31 +194,34 @@
bitflags! {
/// MotionEvent flags.
+ /// The source of truth for the flag definitions are the MotionEventFlag AIDL enum.
+ /// The flag values are redefined here as a bitflags API.
#[derive(Debug)]
pub struct MotionFlags: u32 {
/// FLAG_WINDOW_IS_OBSCURED
- const WINDOW_IS_OBSCURED = IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED as u32;
+ const WINDOW_IS_OBSCURED = MotionEventFlag::WINDOW_IS_OBSCURED.0 as u32;
/// FLAG_WINDOW_IS_PARTIALLY_OBSCURED
- const WINDOW_IS_PARTIALLY_OBSCURED = IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED as u32;
+ const WINDOW_IS_PARTIALLY_OBSCURED = MotionEventFlag::WINDOW_IS_PARTIALLY_OBSCURED.0 as u32;
/// FLAG_HOVER_EXIT_PENDING
- const HOVER_EXIT_PENDING = IInputConstants::MOTION_EVENT_FLAG_HOVER_EXIT_PENDING as u32;
+ const HOVER_EXIT_PENDING = MotionEventFlag::HOVER_EXIT_PENDING.0 as u32;
/// FLAG_IS_GENERATED_GESTURE
- const IS_GENERATED_GESTURE = IInputConstants::MOTION_EVENT_FLAG_IS_GENERATED_GESTURE as u32;
+ const IS_GENERATED_GESTURE = MotionEventFlag::IS_GENERATED_GESTURE.0 as u32;
/// FLAG_CANCELED
- const CANCELED = IInputConstants::INPUT_EVENT_FLAG_CANCELED as u32;
+ const CANCELED = MotionEventFlag::CANCELED.0 as u32;
/// FLAG_NO_FOCUS_CHANGE
- const NO_FOCUS_CHANGE = IInputConstants::MOTION_EVENT_FLAG_NO_FOCUS_CHANGE as u32;
+ const NO_FOCUS_CHANGE = MotionEventFlag::NO_FOCUS_CHANGE.0 as u32;
/// PRIVATE_FLAG_SUPPORTS_ORIENTATION
- const PRIVATE_SUPPORTS_ORIENTATION = IInputConstants::MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION as u32;
+ const PRIVATE_FLAG_SUPPORTS_ORIENTATION =
+ MotionEventFlag::PRIVATE_FLAG_SUPPORTS_ORIENTATION.0 as u32;
/// PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION
- const PRIVATE_SUPPORTS_DIRECTIONAL_ORIENTATION =
- IInputConstants::MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION as u32;
+ const PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION =
+ MotionEventFlag::PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION.0 as u32;
/// FLAG_IS_ACCESSIBILITY_EVENT
- const IS_ACCESSIBILITY_EVENT = IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT as u32;
+ const IS_ACCESSIBILITY_EVENT = MotionEventFlag::IS_ACCESSIBILITY_EVENT.0 as u32;
/// FLAG_TAINTED
- const TAINTED = IInputConstants::INPUT_EVENT_FLAG_TAINTED as u32;
+ const TAINTED = MotionEventFlag::TAINTED.0 as u32;
/// FLAG_TARGET_ACCESSIBILITY_FOCUS
- const TARGET_ACCESSIBILITY_FOCUS = IInputConstants::MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS as u32;
+ const TARGET_ACCESSIBILITY_FOCUS = MotionEventFlag::TARGET_ACCESSIBILITY_FOCUS.0 as u32;
}
}
@@ -333,10 +337,24 @@
#[cfg(test)]
mod tests {
use crate::input::SourceClass;
+ use crate::MotionFlags;
use crate::Source;
+ use inputconstants::aidl::android::os::MotionEventFlag::MotionEventFlag;
+
#[test]
fn convert_source_class_pointer() {
let source = Source::from_bits(input_bindgen::AINPUT_SOURCE_CLASS_POINTER).unwrap();
assert!(source.is_from_class(SourceClass::Pointer));
}
+
+ /// Ensure all MotionEventFlag constants are re-defined in rust.
+ #[test]
+ fn all_motion_event_flags_defined() {
+ for flag in MotionEventFlag::enum_values() {
+ assert!(
+ MotionFlags::from_bits(flag.0 as u32).is_some(),
+ "MotionEventFlag value {flag:?} is not redefined as a rust MotionFlags"
+ );
+ }
+ }
}
diff --git a/libs/input/rust/keyboard_classification_config.rs b/libs/input/rust/keyboard_classification_config.rs
new file mode 100644
index 0000000..ab74efb
--- /dev/null
+++ b/libs/input/rust/keyboard_classification_config.rs
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+use crate::input::KeyboardType;
+
+// TODO(b/263559234): Categorize some of these to KeyboardType::None based on ability to produce
+// key events at all. (Requires setup allowing InputDevice to dynamically add/remove
+// KeyboardInputMapper based on blocklist and KeyEvents in case a KeyboardType::None device ends
+// up producing a key event)
+pub static CLASSIFIED_DEVICES: &[(
+ /* vendorId */ u16,
+ /* productId */ u16,
+ KeyboardType,
+ /* is_finalized */ bool,
+)] = &[
+ // HP X4000 Wireless Mouse
+ (0x03f0, 0xa407, KeyboardType::NonAlphabetic, true),
+ // Microsoft Wireless Mobile Mouse 6000
+ (0x045e, 0x0745, KeyboardType::NonAlphabetic, true),
+ // Microsoft Surface Precision Mouse
+ (0x045e, 0x0821, KeyboardType::NonAlphabetic, true),
+ // Microsoft Pro IntelliMouse
+ (0x045e, 0x082a, KeyboardType::NonAlphabetic, true),
+ // Microsoft Bluetooth Mouse
+ (0x045e, 0x082f, KeyboardType::NonAlphabetic, true),
+ // Xbox One Elite Series 2 gamepad
+ (0x045e, 0x0b05, KeyboardType::NonAlphabetic, true),
+ // Logitech T400
+ (0x046d, 0x4026, KeyboardType::NonAlphabetic, true),
+ // Logitech M720 Triathlon (Unifying)
+ (0x046d, 0x405e, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master 2S (Unifying)
+ (0x046d, 0x4069, KeyboardType::NonAlphabetic, true),
+ // Logitech M585 (Unifying)
+ (0x046d, 0x406b, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2 (Unifying)
+ (0x046d, 0x4072, KeyboardType::NonAlphabetic, true),
+ // Logitech Pebble M350
+ (0x046d, 0x4080, KeyboardType::NonAlphabetic, true),
+ // Logitech T630 Ultrathin
+ (0x046d, 0xb00d, KeyboardType::NonAlphabetic, true),
+ // Logitech M558
+ (0x046d, 0xb011, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master (Bluetooth)
+ (0x046d, 0xb012, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2 (Bluetooth)
+ (0x046d, 0xb013, KeyboardType::NonAlphabetic, true),
+ // Logitech M720 Triathlon (Bluetooth)
+ (0x046d, 0xb015, KeyboardType::NonAlphabetic, true),
+ // Logitech M535
+ (0x046d, 0xb016, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master / Anywhere 2 (Bluetooth)
+ (0x046d, 0xb017, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master 2S (Bluetooth)
+ (0x046d, 0xb019, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2S (Bluetooth)
+ (0x046d, 0xb01a, KeyboardType::NonAlphabetic, true),
+ // Logitech M585/M590 (Bluetooth)
+ (0x046d, 0xb01b, KeyboardType::NonAlphabetic, true),
+ // Logitech G603 Lightspeed Gaming Mouse (Bluetooth)
+ (0x046d, 0xb01c, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master (Bluetooth)
+ (0x046d, 0xb01e, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Anywhere 2 (Bluetooth)
+ (0x046d, 0xb01f, KeyboardType::NonAlphabetic, true),
+ // Logitech MX Master 3 (Bluetooth)
+ (0x046d, 0xb023, KeyboardType::NonAlphabetic, true),
+ // Logitech G604 Lightspeed Gaming Mouse (Bluetooth)
+ (0x046d, 0xb024, KeyboardType::NonAlphabetic, true),
+ // Logitech Spotlight Presentation Remote (Bluetooth)
+ (0x046d, 0xb503, KeyboardType::NonAlphabetic, true),
+ // Logitech R500 (Bluetooth)
+ (0x046d, 0xb505, KeyboardType::NonAlphabetic, true),
+ // Logitech M500s
+ (0x046d, 0xc093, KeyboardType::NonAlphabetic, true),
+ // Logitech Spotlight Presentation Remote (USB dongle)
+ (0x046d, 0xc53e, KeyboardType::NonAlphabetic, true),
+ // Elecom Enelo IR LED Mouse 350
+ (0x056e, 0x0134, KeyboardType::NonAlphabetic, true),
+ // Elecom EPRIM Blue LED 5 button mouse 228
+ (0x056e, 0x0141, KeyboardType::NonAlphabetic, true),
+ // Elecom Blue LED Mouse 203
+ (0x056e, 0x0159, KeyboardType::NonAlphabetic, true),
+ // Zebra LS2208 barcode scanner
+ (0x05e0, 0x1200, KeyboardType::NonAlphabetic, true),
+ // RDing FootSwitch1F1
+ (0x0c45, 0x7403, KeyboardType::NonAlphabetic, true),
+ // SteelSeries Sensei RAW Frost Blue
+ (0x1038, 0x1369, KeyboardType::NonAlphabetic, true),
+ // SteelSeries Rival 3 Wired
+ (0x1038, 0x1824, KeyboardType::NonAlphabetic, true),
+ // SteelSeries Rival 3 Wireless (USB dongle)
+ (0x1038, 0x1830, KeyboardType::NonAlphabetic, true),
+ // Yubico.com Yubikey
+ (0x1050, 0x0010, KeyboardType::NonAlphabetic, true),
+ // Yubico.com Yubikey 4 OTP+U2F+CCID
+ (0x1050, 0x0407, KeyboardType::NonAlphabetic, true),
+ // Lenovo USB-C Wired Compact Mouse
+ (0x17ef, 0x6123, KeyboardType::NonAlphabetic, true),
+ // Corsair Katar Pro Wireless (USB dongle)
+ (0x1b1c, 0x1b94, KeyboardType::NonAlphabetic, true),
+ // Corsair Katar Pro Wireless (Bluetooth)
+ (0x1bae, 0x1b1c, KeyboardType::NonAlphabetic, true),
+ // Kensington Pro Fit Full-size
+ (0x1bcf, 0x08a0, KeyboardType::NonAlphabetic, true),
+ // Huion HS64
+ (0x256c, 0x006d, KeyboardType::NonAlphabetic, true),
+ // XP-Pen Star G640
+ (0x28bd, 0x0914, KeyboardType::NonAlphabetic, true),
+ // XP-Pen Artist 12 Pro
+ (0x28bd, 0x091f, KeyboardType::NonAlphabetic, true),
+ // XP-Pen Deco mini7W
+ (0x28bd, 0x0928, KeyboardType::NonAlphabetic, true),
+];
diff --git a/libs/input/rust/keyboard_classifier.rs b/libs/input/rust/keyboard_classifier.rs
index 1063fac..8721ef7 100644
--- a/libs/input/rust/keyboard_classifier.rs
+++ b/libs/input/rust/keyboard_classifier.rs
@@ -35,6 +35,7 @@
//! TODO(b/263559234): Data store implementation to store information about past classification
use crate::input::{DeviceId, InputDevice, KeyboardType};
+use crate::keyboard_classification_config::CLASSIFIED_DEVICES;
use crate::{DeviceClass, ModifierState};
use std::collections::HashMap;
@@ -126,6 +127,14 @@
(KeyboardType::NonAlphabetic, true)
};
}
+
+ // Check in known device list for classification
+ for data in CLASSIFIED_DEVICES.iter() {
+ if device.identifier.vendor == data.0 && device.identifier.product == data.1 {
+ return (data.2, data.3);
+ }
+ }
+
// Any composite device with multiple device classes should be categorized as non-alphabetic
// keyboard initially
if device.classes.contains(DeviceClass::Touch)
@@ -169,6 +178,7 @@
#[cfg(test)]
mod tests {
use crate::input::{DeviceId, InputDevice, KeyboardType};
+ use crate::keyboard_classification_config::CLASSIFIED_DEVICES;
use crate::keyboard_classifier::KeyboardClassifier;
use crate::{DeviceClass, ModifierState, RustInputDeviceIdentifier};
@@ -326,6 +336,17 @@
assert!(!classifier.is_finalized(DEVICE_ID));
}
+ #[test]
+ fn classify_known_devices() {
+ let mut classifier = KeyboardClassifier::new();
+ for device in CLASSIFIED_DEVICES.iter() {
+ classifier
+ .notify_keyboard_changed(create_device_with_vendor_product_ids(device.0, device.1));
+ assert_eq!(classifier.get_keyboard_type(DEVICE_ID), device.2);
+ assert_eq!(classifier.is_finalized(DEVICE_ID), device.3);
+ }
+ }
+
fn create_device(classes: DeviceClass) -> InputDevice {
InputDevice {
device_id: DEVICE_ID,
@@ -342,4 +363,21 @@
classes,
}
}
+
+ fn create_device_with_vendor_product_ids(vendor: u16, product: u16) -> InputDevice {
+ InputDevice {
+ device_id: DEVICE_ID,
+ identifier: RustInputDeviceIdentifier {
+ name: "test_device".to_string(),
+ location: "location".to_string(),
+ unique_id: "unique_id".to_string(),
+ bus: 123,
+ vendor,
+ product,
+ version: 567,
+ descriptor: "descriptor".to_string(),
+ },
+ classes: DeviceClass::Keyboard | DeviceClass::AlphabeticKey | DeviceClass::External,
+ }
+ }
}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 5010475..af8f889 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -18,6 +18,7 @@
mod input;
mod input_verifier;
+mod keyboard_classification_config;
mod keyboard_classifier;
pub use input::{
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index e62640e..5f37125 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -514,7 +514,7 @@
auto shader = parameters.shader;
if (stretchEffect.hasEffect()) {
const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
- if (graphicBuffer && parameters.shader) {
+ if (graphicBuffer && shader) {
shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
}
}
@@ -525,21 +525,26 @@
static_cast<ui::PixelFormat>(targetBuffer->getPixelFormat()))
: std::nullopt;
- if (parameters.display.tonemapStrategy == DisplaySettings::TonemapStrategy::Local) {
- // TODO: Handle color matrix transforms in linear space.
- SkImage* image = parameters.shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr);
- if (image) {
- static MouriMap kMapper;
- const float ratio = getHdrRenderType(parameters.layer.sourceDataspace, format) ==
- HdrRenderType::GENERIC_HDR
- ? 1.0f
- : parameters.layerDimmingRatio;
- return kMapper.mouriMap(getActiveContext(), parameters.shader, ratio);
- }
+ const auto hdrType = getHdrRenderType(parameters.layer.sourceDataspace, format,
+ parameters.layerDimmingRatio);
+
+ const auto usingLocalTonemap =
+ parameters.display.tonemapStrategy == DisplaySettings::TonemapStrategy::Local &&
+ hdrType != HdrRenderType::SDR &&
+ shader->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr);
+
+ if (usingLocalTonemap) {
+ static MouriMap kMapper;
+ const float ratio =
+ hdrType == HdrRenderType::GENERIC_HDR ? 1.0f : parameters.layerDimmingRatio;
+ shader = kMapper.mouriMap(getActiveContext(), shader, ratio);
}
+ // disable tonemapping if we already locally tonemapped
+ auto inputDataspace =
+ usingLocalTonemap ? parameters.outputDataSpace : parameters.layer.sourceDataspace;
auto effect =
- shaders::LinearEffect{.inputDataspace = parameters.layer.sourceDataspace,
+ shaders::LinearEffect{.inputDataspace = inputDataspace,
.outputDataspace = parameters.outputDataSpace,
.undoPremultipliedAlpha = parameters.undoPremultipliedAlpha,
.fakeOutputDataspace = parameters.fakeOutputDataspace};
@@ -555,20 +560,22 @@
mat4 colorTransform = parameters.layer.colorTransform;
- colorTransform *=
- mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
- parameters.layerDimmingRatio, 1.f));
+ if (!usingLocalTonemap) {
+ colorTransform *=
+ mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
+ parameters.layerDimmingRatio, 1.f));
+ }
const auto targetBuffer = parameters.layer.source.buffer.buffer;
const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
- return createLinearEffectShader(parameters.shader, effect, runtimeEffect,
- std::move(colorTransform), parameters.display.maxLuminance,
+ return createLinearEffectShader(shader, effect, runtimeEffect, std::move(colorTransform),
+ parameters.display.maxLuminance,
parameters.display.currentLuminanceNits,
parameters.layer.source.buffer.maxLuminanceNits,
hardwareBuffer, parameters.display.renderIntent);
}
- return parameters.shader;
+ return shader;
}
void SkiaRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index bd50107..a1f917d 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -29,7 +29,6 @@
#include <GrDirectContext.h>
#include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
-#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
#include <android-base/stringprintf.h>
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.h b/libs/renderengine/skia/SkiaVkRenderEngine.h
index 0a2f9b2..d2bb3d5 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.h
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.h
@@ -17,8 +17,6 @@
#ifndef SF_SKIAVKRENDERENGINE_H_
#define SF_SKIAVKRENDERENGINE_H_
-#include <vk/GrVkBackendContext.h>
-
#include "SkiaRenderEngine.h"
#include "VulkanInterface.h"
#include "compat/SkiaGpuContext.h"
diff --git a/libs/renderengine/skia/VulkanInterface.cpp b/libs/renderengine/skia/VulkanInterface.cpp
index 5e756b0..37b69f6 100644
--- a/libs/renderengine/skia/VulkanInterface.cpp
+++ b/libs/renderengine/skia/VulkanInterface.cpp
@@ -32,21 +32,8 @@
namespace renderengine {
namespace skia {
-GrVkBackendContext VulkanInterface::getGaneshBackendContext() {
- 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;
+VulkanBackendContext VulkanInterface::getGaneshBackendContext() {
+ return this->getGraphiteBackendContext();
};
VulkanBackendContext VulkanInterface::getGraphiteBackendContext() {
@@ -57,7 +44,7 @@
backendContext.fQueue = mQueue;
backendContext.fGraphicsQueueIndex = mQueueIndex;
backendContext.fMaxAPIVersion = mApiVersion;
- backendContext.fVkExtensions = &mGrExtensions;
+ backendContext.fVkExtensions = &mVulkanExtensions;
backendContext.fDeviceFeatures2 = mPhysicalDeviceFeatures2;
backendContext.fGetProc = mGrGetProc;
backendContext.fProtectedContext = mIsProtected ? Protected::kYes : Protected::kNo;
@@ -429,11 +416,11 @@
mDeviceExtensionNames.push_back(devExt.extensionName);
}
- mGrExtensions.init(sGetProc, instance, physicalDevice, enabledInstanceExtensionNames.size(),
- enabledInstanceExtensionNames.data(), enabledDeviceExtensionNames.size(),
- enabledDeviceExtensionNames.data());
+ mVulkanExtensions.init(sGetProc, instance, physicalDevice, enabledInstanceExtensionNames.size(),
+ enabledInstanceExtensionNames.data(), enabledDeviceExtensionNames.size(),
+ enabledDeviceExtensionNames.data());
- if (!mGrExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
+ if (!mVulkanExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
BAIL("Vulkan driver doesn't support external semaphore fd");
}
@@ -458,7 +445,7 @@
tailPnext = &mProtectedMemoryFeatures->pNext;
}
- if (mGrExtensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
+ if (mVulkanExtensions.hasExtension(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, 1)) {
mDeviceFaultFeatures = new VkPhysicalDeviceFaultFeaturesEXT;
mDeviceFaultFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
mDeviceFaultFeatures->pNext = nullptr;
@@ -484,7 +471,7 @@
queuePriority,
};
- if (mGrExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
+ if (mVulkanExtensions.hasExtension(VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, 2)) {
queueNextPtr = &queuePriorityCreateInfo;
}
@@ -606,7 +593,7 @@
mQueue = VK_NULL_HANDLE; // Implicitly destroyed by destroying mDevice.
mQueueIndex = 0;
mApiVersion = 0;
- mGrExtensions = skgpu::VulkanExtensions();
+ mVulkanExtensions = skgpu::VulkanExtensions();
mGrGetProc = nullptr;
mIsProtected = false;
mIsRealtimePriority = false;
diff --git a/libs/renderengine/skia/VulkanInterface.h b/libs/renderengine/skia/VulkanInterface.h
index f20b002..d0fe4d1 100644
--- a/libs/renderengine/skia/VulkanInterface.h
+++ b/libs/renderengine/skia/VulkanInterface.h
@@ -16,7 +16,7 @@
#pragma once
-#include <include/gpu/vk/GrVkBackendContext.h>
+#include <include/gpu/vk/VulkanBackendContext.h>
#include <include/gpu/vk/VulkanExtensions.h>
#include <include/gpu/vk/VulkanTypes.h>
@@ -24,10 +24,6 @@
using namespace skgpu;
-namespace skgpu {
-struct VulkanBackendContext;
-} // namespace skgpu
-
namespace android {
namespace renderengine {
namespace skia {
@@ -48,7 +44,8 @@
bool takeOwnership();
void teardown();
- GrVkBackendContext getGaneshBackendContext();
+ // TODO(b/309785258) Combine these into one now that they are the same implementation.
+ VulkanBackendContext getGaneshBackendContext();
VulkanBackendContext getGraphiteBackendContext();
VkSemaphore createExportableSemaphore();
VkSemaphore importSemaphoreFromSyncFd(int syncFd);
@@ -86,7 +83,7 @@
VkQueue mQueue = VK_NULL_HANDLE;
int mQueueIndex = 0;
uint32_t mApiVersion = 0;
- skgpu::VulkanExtensions mGrExtensions;
+ skgpu::VulkanExtensions mVulkanExtensions;
VkPhysicalDeviceFeatures2* mPhysicalDeviceFeatures2 = nullptr;
VkPhysicalDeviceSamplerYcbcrConversionFeatures* mSamplerYcbcrConversionFeatures = nullptr;
VkPhysicalDeviceProtectedMemoryFeatures* mProtectedMemoryFeatures = nullptr;
diff --git a/libs/renderengine/skia/compat/GaneshGpuContext.cpp b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
index b2eae00..b121fe8 100644
--- a/libs/renderengine/skia/compat/GaneshGpuContext.cpp
+++ b/libs/renderengine/skia/compat/GaneshGpuContext.cpp
@@ -25,7 +25,7 @@
#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
#include <include/gpu/gl/GrGLInterface.h>
-#include <include/gpu/vk/GrVkBackendContext.h>
+#include <include/gpu/vk/VulkanBackendContext.h>
#include "../AutoBackendTexture.h"
#include "GaneshBackendTexture.h"
@@ -56,10 +56,10 @@
}
std::unique_ptr<SkiaGpuContext> SkiaGpuContext::MakeVulkan_Ganesh(
- const GrVkBackendContext& grVkBackendContext,
+ const skgpu::VulkanBackendContext& vkBackendContext,
GrContextOptions::PersistentCache& skSLCacheMonitor) {
return std::make_unique<GaneshGpuContext>(
- GrDirectContexts::MakeVulkan(grVkBackendContext, ganeshOptions(skSLCacheMonitor)));
+ GrDirectContexts::MakeVulkan(vkBackendContext, ganeshOptions(skSLCacheMonitor)));
}
GaneshGpuContext::GaneshGpuContext(sk_sp<GrDirectContext> grContext) : mGrContext(grContext) {
diff --git a/libs/renderengine/skia/compat/SkiaGpuContext.h b/libs/renderengine/skia/compat/SkiaGpuContext.h
index 282dfe7..9fa6fb8 100644
--- a/libs/renderengine/skia/compat/SkiaGpuContext.h
+++ b/libs/renderengine/skia/compat/SkiaGpuContext.h
@@ -23,7 +23,6 @@
#include <include/gpu/GrDirectContext.h>
#include <include/gpu/gl/GrGLInterface.h>
#include <include/gpu/graphite/Context.h>
-#include <include/gpu/vk/GrVkBackendContext.h>
#include "include/gpu/vk/VulkanBackendContext.h"
#include "SkiaBackendTexture.h"
@@ -52,10 +51,10 @@
GrContextOptions::PersistentCache& skSLCacheMonitor);
/**
- * grVkBackendContext must remain valid until after SkiaGpuContext is destroyed.
+ * vkBackendContext must remain valid until after SkiaGpuContext is destroyed.
*/
static std::unique_ptr<SkiaGpuContext> MakeVulkan_Ganesh(
- const GrVkBackendContext& grVkBackendContext,
+ const skgpu::VulkanBackendContext& vkBackendContext,
GrContextOptions::PersistentCache& skSLCacheMonitor);
// TODO: b/293371537 - Need shader / pipeline monitoring support in Graphite.
diff --git a/libs/renderengine/skia/filters/MouriMap.cpp b/libs/renderengine/skia/filters/MouriMap.cpp
index 7d8b8a5..cc25fcc 100644
--- a/libs/renderengine/skia/filters/MouriMap.cpp
+++ b/libs/renderengine/skia/filters/MouriMap.cpp
@@ -84,13 +84,13 @@
float3 linear = toLinearSrgb(rgba.rgb) * hdrSdrRatio;
if (localMax <= 1.0) {
- return float4(fromLinearSrgb(linear), 1.0);
+ return float4(fromLinearSrgb(linear), rgba.a);
}
float maxRGB = max(linear.r, max(linear.g, linear.b));
localMax = max(localMax, maxRGB);
float gain = (1 + maxRGB / (localMax * localMax)) / (1 + maxRGB);
- return float4(fromLinearSrgb(linear * gain), 1.0);
+ return float4(fromLinearSrgb(linear * gain), rgba.a);
}
)");
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index 7fa47b4..659666d 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -63,6 +63,8 @@
"libhardware",
"libpermission",
"android.companion.virtual.virtualdevice_aidl-cpp",
+ "libaconfig_storage_read_api_cc",
+ "server_configurable_flags",
],
static_libs: [
diff --git a/libs/sensor/SensorEventQueue.cpp b/libs/sensor/SensorEventQueue.cpp
index 4438d45..84852ea 100644
--- a/libs/sensor/SensorEventQueue.cpp
+++ b/libs/sensor/SensorEventQueue.cpp
@@ -15,31 +15,40 @@
*/
#define LOG_TAG "Sensors"
-
-#include <sensor/SensorEventQueue.h>
-
-#include <algorithm>
-#include <sys/socket.h>
-
-#include <utils/RefBase.h>
-#include <utils/Looper.h>
-
-#include <sensor/Sensor.h>
-#include <sensor/BitTube.h>
-#include <sensor/ISensorEventConnection.h>
+#define ATRACE_TAG ATRACE_TAG_SYSTEM_SERVER
#include <android/sensor.h>
+#include <com_android_hardware_libsensor_flags.h>
+#include <cutils/trace.h>
#include <hardware/sensors-base.h>
+#include <sensor/BitTube.h>
+#include <sensor/ISensorEventConnection.h>
+#include <sensor/Sensor.h>
+#include <sensor/SensorEventQueue.h>
+#include <sensor/SensorManager.h>
+#include <sys/socket.h>
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+
+#include <algorithm>
+#include <cinttypes>
+#include <string>
using std::min;
+namespace libsensor_flags = com::android::hardware::libsensor::flags;
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection)
- : mSensorEventConnection(connection), mRecBuffer(nullptr), mAvailable(0), mConsumed(0),
- mNumAcksToSend(0) {
+SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection,
+ SensorManager& sensorManager)
+ : mSensorEventConnection(connection),
+ mRecBuffer(nullptr),
+ mSensorManager(sensorManager),
+ mAvailable(0),
+ mConsumed(0),
+ mNumAcksToSend(0) {
mRecBuffer = new ASensorEvent[MAX_RECEIVE_BUFFER_EVENT_COUNT];
}
@@ -65,8 +74,8 @@
ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) {
if (mAvailable == 0) {
- ssize_t err = BitTube::recvObjects(mSensorChannel,
- mRecBuffer, MAX_RECEIVE_BUFFER_EVENT_COUNT);
+ ssize_t err =
+ BitTube::recvObjects(mSensorChannel, mRecBuffer, MAX_RECEIVE_BUFFER_EVENT_COUNT);
if (err < 0) {
return err;
}
@@ -75,6 +84,20 @@
}
size_t count = min(numEvents, mAvailable);
memcpy(events, mRecBuffer + mConsumed, count * sizeof(ASensorEvent));
+
+ if (CC_UNLIKELY(ATRACE_ENABLED()) &&
+ libsensor_flags::sensor_event_queue_report_sensor_usage_in_tracing()) {
+ for (size_t i = 0; i < count; i++) {
+ std::optional<std::string_view> sensorName =
+ mSensorManager.getSensorNameByHandle(events->sensor);
+ if (sensorName.has_value()) {
+ char buffer[UINT8_MAX];
+ std::snprintf(buffer, sizeof(buffer), "Sensor event from %s",
+ sensorName.value().data());
+ ATRACE_INSTANT_FOR_TRACK(LOG_TAG, buffer);
+ }
+ }
+ }
mAvailable -= count;
mConsumed += count;
return static_cast<ssize_t>(count);
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 9411e20..3ca6f0f 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -38,6 +38,7 @@
#include <sensor/SensorEventQueue.h>
#include <com_android_hardware_libsensor_flags.h>
+namespace libsensor_flags = com::android::hardware::libsensor::flags;
// ----------------------------------------------------------------------------
namespace android {
@@ -78,6 +79,21 @@
return DEVICE_ID_DEFAULT;
}
+bool findSensorNameInList(int32_t handle, const Vector<Sensor>& sensorList,
+ std::string* outString) {
+ for (auto& sensor : sensorList) {
+ if (sensor.getHandle() == handle) {
+ std::ostringstream oss;
+ oss << sensor.getStringType() << ":" << sensor.getName();
+ if (outString) {
+ *outString = std::move(oss.str());
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace
Mutex SensorManager::sLock;
@@ -355,6 +371,25 @@
return nullptr;
}
+std::optional<std::string_view> SensorManager::getSensorNameByHandle(int32_t handle) {
+ std::lock_guard<std::mutex> lock(mSensorHandleToNameMutex);
+ auto iterator = mSensorHandleToName.find(handle);
+ if (iterator != mSensorHandleToName.end()) {
+ return iterator->second;
+ }
+
+ std::string sensorName;
+ if (!findSensorNameInList(handle, mSensors, &sensorName) &&
+ !findSensorNameInList(handle, mDynamicSensors, &sensorName)) {
+ ALOGW("Cannot find sensor with handle %d", handle);
+ return std::nullopt;
+ }
+
+ mSensorHandleToName[handle] = std::move(sensorName);
+
+ return mSensorHandleToName[handle];
+}
+
sp<SensorEventQueue> SensorManager::createEventQueue(
String8 packageName, int mode, String16 attributionTag) {
sp<SensorEventQueue> queue;
@@ -368,7 +403,7 @@
ALOGE("createEventQueue: connection is NULL.");
return nullptr;
}
- queue = new SensorEventQueue(connection);
+ queue = new SensorEventQueue(connection, *this);
break;
}
return queue;
diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h
index 8c3fde0..0bcaadc 100644
--- a/libs/sensor/include/sensor/SensorEventQueue.h
+++ b/libs/sensor/include/sensor/SensorEventQueue.h
@@ -42,6 +42,7 @@
// ----------------------------------------------------------------------------
class ISensorEventConnection;
+class SensorManager;
class Sensor;
class Looper;
@@ -65,7 +66,8 @@
// Default sensor sample period
static constexpr int32_t SENSOR_DELAY_NORMAL = 200000;
- explicit SensorEventQueue(const sp<ISensorEventConnection>& connection);
+ explicit SensorEventQueue(const sp<ISensorEventConnection>& connection,
+ SensorManager& sensorManager);
virtual ~SensorEventQueue();
virtual void onFirstRef();
@@ -107,6 +109,7 @@
mutable Mutex mLock;
mutable sp<Looper> mLooper;
ASensorEvent* mRecBuffer;
+ SensorManager& mSensorManager;
size_t mAvailable;
size_t mConsumed;
uint32_t mNumAcksToSend;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 49f050a..8d7237d 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -17,22 +17,20 @@
#ifndef ANDROID_GUI_SENSOR_MANAGER_H
#define ANDROID_GUI_SENSOR_MANAGER_H
-#include <map>
-#include <unordered_map>
-
-#include <stdint.h>
-#include <sys/types.h>
-
#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-
+#include <sensor/SensorEventQueue.h>
+#include <stdint.h>
+#include <sys/types.h>
#include <utils/Errors.h>
+#include <utils/String8.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
-#include <utils/String8.h>
-#include <sensor/SensorEventQueue.h>
+#include <map>
+#include <string>
+#include <unordered_map>
// ----------------------------------------------------------------------------
// Concrete types for the NDK
@@ -66,6 +64,7 @@
sp<SensorEventQueue> createEventQueue(
String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16(""));
bool isDataInjectionEnabled();
+ std::optional<std::string_view> getSensorNameByHandle(int32_t handle);
bool isReplayDataInjectionEnabled();
bool isHalBypassReplayDataInjectionEnabled();
int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
@@ -97,6 +96,9 @@
const String16 mOpPackageName;
const int mDeviceId;
std::unordered_map<int, sp<ISensorEventConnection>> mDirectConnection;
+
+ std::mutex mSensorHandleToNameMutex;
+ std::unordered_map<int32_t, std::string> mSensorHandleToName;
int32_t mDirectConnectionHandle;
};
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index e76b648..b2f15b4 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -78,6 +78,7 @@
name: "libinputreader_defaults",
srcs: [":libinputreader_sources"],
shared_libs: [
+ "android.companion.virtualdevice.flags-aconfig-cc-host",
"libbase",
"libcap",
"libcrypto",
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index fe70a51..643499c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -33,6 +33,8 @@
#include <sys/sysmacros.h>
#include <unistd.h>
+#include <android_companion_virtualdevice_flags.h>
+
#define LOG_TAG "EventHub"
// #define LOG_NDEBUG 0
@@ -68,6 +70,8 @@
namespace android {
+namespace vd_flags = android::companion::virtualdevice::flags;
+
using namespace ftl::flag_operators;
static const char* DEVICE_INPUT_PATH = "/dev/input";
@@ -998,26 +1002,23 @@
return *device->configuration;
}
-status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const {
- outAxisInfo->clear();
+std::optional<RawAbsoluteAxisInfo> EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis) const {
if (axis < 0 || axis > ABS_MAX) {
- return NAME_NOT_FOUND;
+ return std::nullopt;
}
std::scoped_lock _l(mLock);
const Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
- return NAME_NOT_FOUND;
+ return std::nullopt;
}
// We can read the RawAbsoluteAxisInfo even if the device is disabled and doesn't have a valid
// fd, because the info is populated once when the device is first opened, and it doesn't change
// throughout the device lifecycle.
auto it = device->absState.find(axis);
if (it == device->absState.end()) {
- return NAME_NOT_FOUND;
+ return std::nullopt;
}
- *outAxisInfo = it->second.info;
- return OK;
+ return it->second.info;
}
bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
@@ -1130,22 +1131,20 @@
return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
}
-status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const {
- *outValue = 0;
+std::optional<int32_t> EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis) const {
if (axis < 0 || axis > ABS_MAX) {
- return NAME_NOT_FOUND;
+ return std::nullopt;
}
std::scoped_lock _l(mLock);
const Device* device = getDeviceLocked(deviceId);
if (device == nullptr || !device->hasValidFd()) {
- return NAME_NOT_FOUND;
+ return std::nullopt;
}
const auto it = device->absState.find(axis);
if (it == device->absState.end()) {
- return NAME_NOT_FOUND;
+ return std::nullopt;
}
- *outValue = it->second.value;
- return OK;
+ return it->second.value;
}
base::Result<std::vector<int32_t>> EventHub::getMtSlotValues(int32_t deviceId, int32_t axis,
@@ -2503,6 +2502,12 @@
}
}
+ // See if the device is a rotary encoder with a single scroll axis and nothing else.
+ if (vd_flags::virtual_rotary() && device->classes == ftl::Flags<InputDeviceClass>(0) &&
+ device->relBitmask.test(REL_WHEEL) && !device->relBitmask.test(REL_HWHEEL)) {
+ device->classes |= InputDeviceClass::ROTARY_ENCODER;
+ }
+
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == ftl::Flags<InputDeviceClass>(0)) {
ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 7cf584d..2a43466 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -21,6 +21,7 @@
#include <filesystem>
#include <functional>
#include <map>
+#include <optional>
#include <ostream>
#include <string>
#include <unordered_map>
@@ -278,8 +279,8 @@
*/
virtual std::optional<PropertyMap> getConfiguration(int32_t deviceId) const = 0;
- virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const = 0;
+ virtual std::optional<RawAbsoluteAxisInfo> getAbsoluteAxisInfo(int32_t deviceId,
+ int axis) const = 0;
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0;
@@ -339,8 +340,7 @@
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
- virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
- int32_t* outValue) const = 0;
+ virtual std::optional<int32_t> getAbsoluteAxisValue(int32_t deviceId, int32_t axis) const = 0;
/* Query Multi-Touch slot values for an axis. Returns error or an 1 indexed array of size
* (slotCount + 1). The value at the 0 index is set to queried axis. */
virtual base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
@@ -511,8 +511,8 @@
std::optional<PropertyMap> getConfiguration(int32_t deviceId) const override final;
- status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const override final;
+ std::optional<RawAbsoluteAxisInfo> getAbsoluteAxisInfo(int32_t deviceId,
+ int axis) const override final;
bool hasRelativeAxis(int32_t deviceId, int axis) const override final;
@@ -559,8 +559,8 @@
int32_t getSwitchState(int32_t deviceId, int32_t sw) const override final;
int32_t getKeyCodeForKeyLocation(int32_t deviceId,
int32_t locationKeyCode) const override final;
- status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
- int32_t* outValue) const override final;
+ std::optional<int32_t> getAbsoluteAxisValue(int32_t deviceId,
+ int32_t axis) const override final;
base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
size_t slotCount) const override final;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 2a7e262..086c26f 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -306,9 +306,12 @@
return mEventHub->getDeviceControllerNumber(mId);
}
inline status_t getAbsoluteAxisInfo(int32_t code, RawAbsoluteAxisInfo* axisInfo) const {
- if (const auto status = mEventHub->getAbsoluteAxisInfo(mId, code, axisInfo); status != OK) {
- return status;
+ std::optional<RawAbsoluteAxisInfo> info = mEventHub->getAbsoluteAxisInfo(mId, code);
+ if (!info.has_value()) {
+ axisInfo->clear();
+ return NAME_NOT_FOUND;
}
+ *axisInfo = *info;
// Validate axis info for InputDevice.
if (axisInfo->valid && axisInfo->minValue == axisInfo->maxValue) {
@@ -379,8 +382,8 @@
return mEventHub->getKeyCodeForKeyLocation(mId, locationKeyCode);
}
inline int32_t getSwitchState(int32_t sw) const { return mEventHub->getSwitchState(mId, sw); }
- inline status_t getAbsoluteAxisValue(int32_t code, int32_t* outValue) const {
- return mEventHub->getAbsoluteAxisValue(mId, code, outValue);
+ inline std::optional<int32_t> getAbsoluteAxisValue(int32_t code) const {
+ return mEventHub->getAbsoluteAxisValue(mId, code);
}
inline base::Result<std::vector<int32_t>> getMtSlotValues(int32_t axis,
size_t slotCount) const {
@@ -432,9 +435,8 @@
}
inline bool hasAbsoluteAxis(int32_t code) const {
- RawAbsoluteAxisInfo info;
- mEventHub->getAbsoluteAxisInfo(mId, code, &info);
- return info.valid;
+ std::optional<RawAbsoluteAxisInfo> info = mEventHub->getAbsoluteAxisInfo(mId, code);
+ return info.has_value() && info->valid;
}
inline bool isKeyPressed(int32_t scanCode) const {
return mEventHub->getScanCodeState(mId, scanCode) == AKEY_STATE_DOWN;
@@ -442,11 +444,6 @@
inline bool isKeyCodePressed(int32_t keyCode) const {
return mEventHub->getKeyCodeState(mId, keyCode) == AKEY_STATE_DOWN;
}
- inline int32_t getAbsoluteAxisValue(int32_t code) const {
- int32_t value;
- mEventHub->getAbsoluteAxisValue(mId, code, &value);
- return value;
- }
inline bool isDeviceEnabled() { return mEventHub->isDeviceEnabled(mId); }
inline status_t enableDevice() { return mEventHub->enableDevice(mId); }
inline status_t disableDevice() { return mEventHub->disableDevice(mId); }
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 27ff52f..20fd359 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -84,12 +84,18 @@
}
}
if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
- std::optional<DisplayViewport> internalViewport =
- config.getDisplayViewportByType(ViewportType::INTERNAL);
- if (internalViewport) {
- mOrientation = internalViewport->orientation;
+ if (getDeviceContext().getAssociatedViewport()) {
+ mDisplayId = getDeviceContext().getAssociatedViewport()->displayId;
+ mOrientation = getDeviceContext().getAssociatedViewport()->orientation;
} else {
- mOrientation = ui::ROTATION_0;
+ mDisplayId = ui::LogicalDisplayId::INVALID;
+ std::optional<DisplayViewport> internalViewport =
+ config.getDisplayViewportByType(ViewportType::INTERNAL);
+ if (internalViewport) {
+ mOrientation = internalViewport->orientation;
+ } else {
+ mOrientation = ui::ROTATION_0;
+ }
}
}
return out;
@@ -124,8 +130,6 @@
// Send motion event.
if (scrolled) {
int32_t metaState = getContext()->getGlobalMetaState();
- // This is not a pointer, so it's not associated with a display.
- ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID;
if (mOrientation == ui::ROTATION_180) {
scroll = -scroll;
@@ -147,7 +151,7 @@
out.push_back(
NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+ mDisplayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
metaState, /*buttonState=*/0, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
&pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
index 14c540b..7e80415 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
@@ -47,6 +47,7 @@
int32_t mSource;
float mScalingFactor;
ui::Rotation mOrientation;
+ ui::LogicalDisplayId mDisplayId = ui::LogicalDisplayId::INVALID;
std::unique_ptr<SlopController> mSlopController;
explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext,
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index a383490..81ec24e 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -931,7 +931,7 @@
mSource |= AINPUT_SOURCE_STYLUS;
}
} else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) {
- mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
+ mSource = AINPUT_SOURCE_TOUCH_NAVIGATION | AINPUT_SOURCE_TOUCHPAD;
mDeviceMode = DeviceMode::NAVIGATION;
} else {
ALOGW("Touch device '%s' has invalid parameters or configuration. The device will be "
diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
index 4919068..8dc6e4d 100644
--- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
+++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp
@@ -139,13 +139,11 @@
if (!mUsingSlotsProtocol) {
return;
}
- int32_t initialSlot;
- if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot);
- status == OK) {
- mCurrentSlot = initialSlot;
+ if (const std::optional<int32_t> initialSlot = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT);
+ initialSlot.has_value()) {
+ mCurrentSlot = initialSlot.value();
} else {
- ALOGE("Could not retrieve current multi-touch slot index. status=%s",
- statusToString(status).c_str());
+ ALOGE("Could not retrieve current multi-touch slot index");
}
}
diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp
index 2b82ddf..4cf9243 100644
--- a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp
+++ b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.cpp
@@ -26,13 +26,13 @@
}
void SingleTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) {
- mAbsX = deviceContext.getAbsoluteAxisValue(ABS_X);
- mAbsY = deviceContext.getAbsoluteAxisValue(ABS_Y);
- mAbsPressure = deviceContext.getAbsoluteAxisValue(ABS_PRESSURE);
- mAbsToolWidth = deviceContext.getAbsoluteAxisValue(ABS_TOOL_WIDTH);
- mAbsDistance = deviceContext.getAbsoluteAxisValue(ABS_DISTANCE);
- mAbsTiltX = deviceContext.getAbsoluteAxisValue(ABS_TILT_X);
- mAbsTiltY = deviceContext.getAbsoluteAxisValue(ABS_TILT_Y);
+ mAbsX = deviceContext.getAbsoluteAxisValue(ABS_X).value_or(0);
+ mAbsY = deviceContext.getAbsoluteAxisValue(ABS_Y).value_or(0);
+ mAbsPressure = deviceContext.getAbsoluteAxisValue(ABS_PRESSURE).value_or(0);
+ mAbsToolWidth = deviceContext.getAbsoluteAxisValue(ABS_TOOL_WIDTH).value_or(0);
+ mAbsDistance = deviceContext.getAbsoluteAxisValue(ABS_DISTANCE).value_or(0);
+ mAbsTiltX = deviceContext.getAbsoluteAxisValue(ABS_TILT_X).value_or(0);
+ mAbsTiltY = deviceContext.getAbsoluteAxisValue(ABS_TILT_Y).value_or(0);
}
void SingleTouchMotionAccumulator::clearAbsoluteAxes() {
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index cf0d46a..bddf43e 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -76,6 +76,7 @@
"PointerChoreographer_test.cpp",
"PreferStylusOverTouch_test.cpp",
"PropertyProvider_test.cpp",
+ "RotaryEncoderInputMapper_test.cpp",
"SlopController_test.cpp",
"SyncQueue_test.cpp",
"TimerProvider_test.cpp",
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index daa000f..12736c8 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -16,6 +16,8 @@
#include "FakeEventHub.h"
+#include <optional>
+
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
#include <linux/input-event-codes.h>
@@ -263,18 +265,16 @@
return device->configuration;
}
-status_t FakeEventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const {
+std::optional<RawAbsoluteAxisInfo> FakeEventHub::getAbsoluteAxisInfo(int32_t deviceId,
+ int axis) const {
Device* device = getDevice(deviceId);
if (device) {
ssize_t index = device->absoluteAxes.indexOfKey(axis);
if (index >= 0) {
- *outAxisInfo = device->absoluteAxes.valueAt(index);
- return OK;
+ return device->absoluteAxes.valueAt(index);
}
}
- outAxisInfo->clear();
- return -1;
+ return std::nullopt;
}
bool FakeEventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
@@ -417,18 +417,15 @@
return AKEY_STATE_UNKNOWN;
}
-status_t FakeEventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
- int32_t* outValue) const {
+std::optional<int32_t> FakeEventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis) const {
Device* device = getDevice(deviceId);
if (device) {
ssize_t index = device->absoluteAxisValue.indexOfKey(axis);
if (index >= 0) {
- *outValue = device->absoluteAxisValue.valueAt(index);
- return OK;
+ return device->absoluteAxisValue.valueAt(index);
}
}
- *outValue = 0;
- return -1;
+ return std::nullopt;
}
void FakeEventHub::setMtSlotValues(int32_t deviceId, int32_t axis,
diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h
index f07b344..c2c875f 100644
--- a/services/inputflinger/tests/FakeEventHub.h
+++ b/services/inputflinger/tests/FakeEventHub.h
@@ -168,8 +168,8 @@
InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override;
int32_t getDeviceControllerNumber(int32_t) const override;
std::optional<PropertyMap> getConfiguration(int32_t deviceId) const override;
- status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const override;
+ std::optional<RawAbsoluteAxisInfo> getAbsoluteAxisInfo(int32_t deviceId,
+ int axis) const override;
bool hasRelativeAxis(int32_t deviceId, int axis) const override;
bool hasInputProperty(int32_t, int) const override;
bool hasMscEvent(int32_t deviceId, int mscEvent) const override final;
@@ -187,7 +187,7 @@
std::optional<RawLayoutInfo> getRawLayoutInfo(int32_t deviceId) const override;
int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override;
int32_t getSwitchState(int32_t deviceId, int32_t sw) const override;
- status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const override;
+ std::optional<int32_t> getAbsoluteAxisValue(int32_t deviceId, int32_t axis) const override;
int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override;
// Return true if the device has non-empty key layout.
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
index d2cb0ac..6099c91 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -16,6 +16,7 @@
#include "FakeInputReaderPolicy.h"
+#include <android-base/properties.h>
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
@@ -24,6 +25,12 @@
namespace android {
+namespace {
+
+static const int HW_TIMEOUT_MULTIPLIER = base::GetIntProperty("ro.hw_timeout_multiplier", 1);
+
+} // namespace
+
void FakeInputReaderPolicy::assertInputDevicesChanged() {
waitForInputDevices([](bool devicesChanged) {
if (!devicesChanged) {
@@ -241,9 +248,11 @@
base::ScopedLockAssertion assumeLocked(mLock);
const bool devicesChanged =
- mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
- return mInputDevicesChanged;
- });
+ mDevicesChangedCondition.wait_for(lock,
+ ADD_INPUT_DEVICE_TIMEOUT * HW_TIMEOUT_MULTIPLIER,
+ [this]() REQUIRES(mLock) {
+ return mInputDevicesChanged;
+ });
ASSERT_NO_FATAL_FAILURE(processDevicesChanged(devicesChanged));
mInputDevicesChanged = false;
}
diff --git a/services/inputflinger/tests/HardwareProperties_test.cpp b/services/inputflinger/tests/HardwareProperties_test.cpp
index 8dfa8c8..643fab6 100644
--- a/services/inputflinger/tests/HardwareProperties_test.cpp
+++ b/services/inputflinger/tests/HardwareProperties_test.cpp
@@ -48,24 +48,20 @@
static constexpr int32_t EVENTHUB_ID = 1;
void setupValidAxis(int axis, int32_t min, int32_t max, int32_t resolution) {
- EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, axis, testing::_))
- .WillRepeatedly([=](int32_t, int32_t, RawAbsoluteAxisInfo* outAxisInfo) {
- outAxisInfo->valid = true;
- outAxisInfo->minValue = min;
- outAxisInfo->maxValue = max;
- outAxisInfo->flat = 0;
- outAxisInfo->fuzz = 0;
- outAxisInfo->resolution = resolution;
- return OK;
- });
+ EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, axis))
+ .WillRepeatedly(Return(std::optional<RawAbsoluteAxisInfo>{{
+ .valid = true,
+ .minValue = min,
+ .maxValue = max,
+ .flat = 0,
+ .fuzz = 0,
+ .resolution = resolution,
+ }}));
}
void setupInvalidAxis(int axis) {
- EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, axis, testing::_))
- .WillRepeatedly([=](int32_t, int32_t, RawAbsoluteAxisInfo* outAxisInfo) {
- outAxisInfo->valid = false;
- return -1;
- });
+ EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, axis))
+ .WillRepeatedly(Return(std::nullopt));
}
void setProperty(int property, bool value) {
diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp
index b5c9232..19bc5be 100644
--- a/services/inputflinger/tests/InputMapperTest.cpp
+++ b/services/inputflinger/tests/InputMapperTest.cpp
@@ -57,16 +57,16 @@
void InputMapperUnitTest::setupAxis(int axis, bool valid, int32_t min, int32_t max,
int32_t resolution) {
- EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, axis, _))
- .WillRepeatedly([=](int32_t, int32_t, RawAbsoluteAxisInfo* outAxisInfo) {
- outAxisInfo->valid = valid;
- outAxisInfo->minValue = min;
- outAxisInfo->maxValue = max;
- outAxisInfo->flat = 0;
- outAxisInfo->fuzz = 0;
- outAxisInfo->resolution = resolution;
- return valid ? OK : -1;
- });
+ EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, axis))
+ .WillRepeatedly(Return(valid ? std::optional<RawAbsoluteAxisInfo>{{
+ .valid = true,
+ .minValue = min,
+ .maxValue = max,
+ .flat = 0,
+ .fuzz = 0,
+ .resolution = resolution,
+ }}
+ : std::nullopt));
}
void InputMapperUnitTest::expectScanCodes(bool present, std::set<int> scanCodes) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index fe238f3..fa9d263 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6245,7 +6245,7 @@
SingleTouchInputMapper& mapper = constructAndAddMapper<SingleTouchInputMapper>();
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
- ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mapper.getSources());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION | AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
}
TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsChangedToTouchNavigation_updatesDeviceType) {
@@ -6268,7 +6268,7 @@
InputReaderConfiguration::Change::DEVICE_TYPE /*changes*/);
// Check whether device type update was successful.
- ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mDevice->getSources());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION | AINPUT_SOURCE_TOUCHPAD, mDevice->getSources());
}
TEST_F(SingleTouchInputMapperTest, HoverEventsOutsidePhysicalFrameAreIgnored) {
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 16d3193..bacc6d4 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -91,8 +91,8 @@
MOCK_METHOD(InputDeviceIdentifier, getDeviceIdentifier, (int32_t deviceId), (const));
MOCK_METHOD(int32_t, getDeviceControllerNumber, (int32_t deviceId), (const));
MOCK_METHOD(std::optional<PropertyMap>, getConfiguration, (int32_t deviceId), (const));
- MOCK_METHOD(status_t, getAbsoluteAxisInfo,
- (int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo), (const));
+ MOCK_METHOD(std::optional<RawAbsoluteAxisInfo>, getAbsoluteAxisInfo,
+ (int32_t deviceId, int axis), (const));
MOCK_METHOD(bool, hasRelativeAxis, (int32_t deviceId, int axis), (const));
MOCK_METHOD(bool, hasInputProperty, (int32_t deviceId, int property), (const));
MOCK_METHOD(bool, hasMscEvent, (int32_t deviceId, int mscEvent), (const));
@@ -131,7 +131,7 @@
MOCK_METHOD(int32_t, getKeyCodeState, (int32_t deviceId, int32_t keyCode), (const, override));
MOCK_METHOD(int32_t, getSwitchState, (int32_t deviceId, int32_t sw), (const, override));
- MOCK_METHOD(status_t, getAbsoluteAxisValue, (int32_t deviceId, int32_t axis, int32_t* outValue),
+ MOCK_METHOD(std::optional<int32_t>, getAbsoluteAxisValue, (int32_t deviceId, int32_t axis),
(const, override));
MOCK_METHOD(base::Result<std::vector<int32_t>>, getMtSlotValues,
(int32_t deviceId, int32_t axis, size_t slotCount), (const, override));
diff --git a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
index b5f8971..d4d3c38 100644
--- a/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
+++ b/services/inputflinger/tests/MultiTouchInputMapper_test.cpp
@@ -99,11 +99,8 @@
setupAxis(ABS_MT_TOOL_TYPE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
// reset current slot at the beginning
- EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, _))
- .WillRepeatedly([](int32_t, int32_t, int32_t* outValue) {
- *outValue = 0;
- return OK;
- });
+ EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT))
+ .WillRepeatedly(Return(0));
// mark all slots not in use
mockSlotValues({});
@@ -211,11 +208,8 @@
const auto pointerCoordsBeforeReset = std::get<NotifyMotionArgs>(args.back()).pointerCoords;
// On buffer overflow mapper will be reset and MT slots data will be repopulated
- EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, _))
- .WillRepeatedly([=](int32_t, int32_t, int32_t* outValue) {
- *outValue = 1;
- return OK;
- });
+ EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT))
+ .WillRepeatedly(Return(1));
mockSlotValues(
{{1, {Point{x1, y1}, FIRST_TRACKING_ID}}, {2, {Point{x2, y2}, SECOND_TRACKING_ID}}});
diff --git a/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
new file mode 100644
index 0000000..94cfc32
--- /dev/null
+++ b/services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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 "RotaryEncoderInputMapper.h"
+
+#include <list>
+#include <string>
+#include <tuple>
+#include <variant>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <input/DisplayViewport.h>
+#include <linux/input-event-codes.h>
+#include <linux/input.h>
+#include <utils/Timers.h>
+
+#include "InputMapperTest.h"
+#include "InputReaderBase.h"
+#include "InterfaceMocks.h"
+#include "NotifyArgs.h"
+#include "TestEventMatchers.h"
+#include "ui/Rotation.h"
+
+#define TAG "RotaryEncoderInputMapper_test"
+
+namespace android {
+
+using testing::AllOf;
+using testing::Return;
+using testing::VariantWith;
+constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
+constexpr ui::LogicalDisplayId SECONDARY_DISPLAY_ID = ui::LogicalDisplayId{DISPLAY_ID.val() + 1};
+constexpr int32_t DISPLAY_WIDTH = 480;
+constexpr int32_t DISPLAY_HEIGHT = 800;
+
+namespace {
+
+DisplayViewport createViewport() {
+ DisplayViewport v;
+ v.orientation = ui::Rotation::Rotation0;
+ v.logicalRight = DISPLAY_HEIGHT;
+ v.logicalBottom = DISPLAY_WIDTH;
+ v.physicalRight = DISPLAY_HEIGHT;
+ v.physicalBottom = DISPLAY_WIDTH;
+ v.deviceWidth = DISPLAY_HEIGHT;
+ v.deviceHeight = DISPLAY_WIDTH;
+ v.isActive = true;
+ return v;
+}
+
+DisplayViewport createPrimaryViewport() {
+ DisplayViewport v = createViewport();
+ v.displayId = DISPLAY_ID;
+ v.uniqueId = "local:1";
+ return v;
+}
+
+DisplayViewport createSecondaryViewport() {
+ DisplayViewport v = createViewport();
+ v.displayId = SECONDARY_DISPLAY_ID;
+ v.uniqueId = "local:2";
+ v.type = ViewportType::EXTERNAL;
+ return v;
+}
+
+/**
+ * A fake InputDeviceContext that allows the associated viewport to be specified for the mapper.
+ *
+ * This is currently necessary because InputMapperUnitTest doesn't register the mappers it creates
+ * with the InputDevice object, meaning that InputDevice::isIgnored becomes true, and the input
+ * device doesn't set its associated viewport when it's configured.
+ *
+ * TODO(b/319217713): work out a way to avoid this fake.
+ */
+class ViewportFakingInputDeviceContext : public InputDeviceContext {
+public:
+ ViewportFakingInputDeviceContext(InputDevice& device, int32_t eventHubId,
+ std::optional<DisplayViewport> viewport)
+ : InputDeviceContext(device, eventHubId), mAssociatedViewport(viewport) {}
+
+ ViewportFakingInputDeviceContext(InputDevice& device, int32_t eventHubId)
+ : ViewportFakingInputDeviceContext(device, eventHubId, createPrimaryViewport()) {}
+
+ std::optional<DisplayViewport> getAssociatedViewport() const override {
+ return mAssociatedViewport;
+ }
+
+ void setViewport(const std::optional<DisplayViewport>& viewport) {
+ mAssociatedViewport = viewport;
+ }
+
+private:
+ std::optional<DisplayViewport> mAssociatedViewport;
+};
+
+} // namespace
+
+/**
+ * Unit tests for RotaryEncoderInputMapper.
+ */
+class RotaryEncoderInputMapperTest : public InputMapperUnitTest {
+protected:
+ void SetUp() override { SetUpWithBus(BUS_USB); }
+ void SetUpWithBus(int bus) override {
+ InputMapperUnitTest::SetUpWithBus(bus);
+
+ EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL))
+ .WillRepeatedly(Return(false));
+ }
+};
+
+TEST_F(RotaryEncoderInputMapperTest, ConfigureDisplayIdWithAssociatedViewport) {
+ DisplayViewport primaryViewport = createPrimaryViewport();
+ DisplayViewport secondaryViewport = createSecondaryViewport();
+ mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
+
+ // Set up the secondary display as the associated viewport of the mapper.
+ createDevice();
+ ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
+ mMapper = createInputMapper<RotaryEncoderInputMapper>(deviceContext, mReaderConfiguration);
+
+ std::list<NotifyArgs> args;
+ // Ensure input events are generated for the secondary display.
+ args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
+ WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+ WithDisplayId(SECONDARY_DISPLAY_ID)))));
+}
+
+TEST_F(RotaryEncoderInputMapperTest, ConfigureDisplayIdNoAssociatedViewport) {
+ // Set up the default display.
+ mFakePolicy->clearViewports();
+ mFakePolicy->addDisplayViewport(createPrimaryViewport());
+
+ // Set up the mapper with no associated viewport.
+ createDevice();
+ mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration);
+
+ // Ensure input events are generated without display ID
+ std::list<NotifyArgs> args;
+ args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 1);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_SCROLL),
+ WithSource(AINPUT_SOURCE_ROTARY_ENCODER),
+ WithDisplayId(ui::LogicalDisplayId::INVALID)))));
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/tests/TestConstants.h b/services/inputflinger/tests/TestConstants.h
index ad48b0f..082bbb8 100644
--- a/services/inputflinger/tests/TestConstants.h
+++ b/services/inputflinger/tests/TestConstants.h
@@ -24,6 +24,9 @@
using std::chrono_literals::operator""ms;
+// Timeout for waiting for an input device to be added and processed
+static constexpr std::chrono::duration ADD_INPUT_DEVICE_TIMEOUT = 500ms;
+
// Timeout for waiting for an expected event
static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
index 2b62dd1..1afb4f0 100644
--- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp
+++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
@@ -103,11 +103,8 @@
setupAxis(ABS_MT_DISTANCE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
setupAxis(ABS_MT_TOOL_TYPE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
- EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, testing::_))
- .WillRepeatedly([](int32_t eventHubId, int32_t, int32_t* outValue) {
- *outValue = 0;
- return OK;
- });
+ EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT))
+ .WillRepeatedly(Return(0));
EXPECT_CALL(mMockEventHub, getMtSlotValues(EVENTHUB_ID, testing::_, testing::_))
.WillRepeatedly([]() -> base::Result<std::vector<int32_t>> {
return base::ResultError("Axis not supported", NAME_NOT_FOUND);
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index ff425dd..6dea540 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -17,6 +17,7 @@
#include <map>
#include <memory>
+#include <optional>
#include <EventHub.h>
#include <InputDevice.h>
@@ -119,16 +120,26 @@
void setAbsoluteAxisInfo(int32_t deviceId, int axis, const RawAbsoluteAxisInfo& axisInfo) {
mAxes[deviceId][axis] = axisInfo;
}
- status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const override {
+ std::optional<RawAbsoluteAxisInfo> getAbsoluteAxisInfo(int32_t deviceId,
+ int axis) const override {
if (auto deviceAxesIt = mAxes.find(deviceId); deviceAxesIt != mAxes.end()) {
const std::map<int, RawAbsoluteAxisInfo>& deviceAxes = deviceAxesIt->second;
if (auto axisInfoIt = deviceAxes.find(axis); axisInfoIt != deviceAxes.end()) {
- *outAxisInfo = axisInfoIt->second;
- return OK;
+ return axisInfoIt->second;
}
}
- return mFdp->ConsumeIntegral<status_t>();
+ if (mFdp->ConsumeBool()) {
+ return std::optional<RawAbsoluteAxisInfo>({
+ .valid = mFdp->ConsumeBool(),
+ .minValue = mFdp->ConsumeIntegral<int32_t>(),
+ .maxValue = mFdp->ConsumeIntegral<int32_t>(),
+ .flat = mFdp->ConsumeIntegral<int32_t>(),
+ .fuzz = mFdp->ConsumeIntegral<int32_t>(),
+ .resolution = mFdp->ConsumeIntegral<int32_t>(),
+ });
+ } else {
+ return std::nullopt;
+ }
}
bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); }
bool hasInputProperty(int32_t deviceId, int property) const override {
@@ -197,9 +208,12 @@
int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override {
return mFdp->ConsumeIntegral<int32_t>();
}
- status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
- int32_t* outValue) const override {
- return mFdp->ConsumeIntegral<status_t>();
+ std::optional<int32_t> getAbsoluteAxisValue(int32_t deviceId, int32_t axis) const override {
+ if (mFdp->ConsumeBool()) {
+ return mFdp->ConsumeIntegral<int32_t>();
+ } else {
+ return std::nullopt;
+ }
}
base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
size_t slotCount) const override {
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
index f6f104e..b2dc89b 100644
--- a/services/sensorservice/aidl/fuzzer/Android.bp
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -26,6 +26,11 @@
"libfakeservicemanager",
"libcutils",
"liblog",
+ "libsensor_flags_c_lib",
+ ],
+ shared_libs: [
+ "libaconfig_storage_read_api_cc",
+ "server_configurable_flags",
],
srcs: [
"fuzzer.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 5b9a102..b40aea4 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1102,7 +1102,7 @@
}
ftl::Future<std::monostate> Output::presentFrameAndReleaseLayersAsync(bool flushEvenWhenDisabled) {
- return ftl::Future<bool>(std::move(mHwComposerAsyncWorker->send([&]() {
+ return ftl::Future<bool>(std::move(mHwComposerAsyncWorker->send([this, flushEvenWhenDisabled]() {
presentFrameAndReleaseLayers(flushEvenWhenDisabled);
return true;
})))
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index ca53a0d..a4ffd51 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -317,6 +317,21 @@
}
}
+void updateMetadataAndGameMode(LayerSnapshot& snapshot, const RequestedLayerState& requested,
+ const LayerSnapshotBuilder::Args& args,
+ const LayerSnapshot& parentSnapshot) {
+ if (snapshot.changes.test(RequestedLayerState::Changes::GameMode)) {
+ snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE)
+ ? requested.gameMode
+ : parentSnapshot.gameMode;
+ }
+ updateMetadata(snapshot, requested, args);
+ if (args.includeMetadata) {
+ snapshot.layerMetadata = parentSnapshot.layerMetadata;
+ snapshot.layerMetadata.merge(requested.metadata);
+ }
+}
+
void clearChanges(LayerSnapshot& snapshot) {
snapshot.changes.clear();
snapshot.clientChanges = 0;
@@ -762,6 +777,11 @@
RequestedLayerState::Changes::Input)) {
updateInput(snapshot, requested, parentSnapshot, path, args);
}
+ if (forceUpdate ||
+ (args.includeMetadata &&
+ snapshot.changes.test(RequestedLayerState::Changes::Metadata))) {
+ updateMetadataAndGameMode(snapshot, requested, args, parentSnapshot);
+ }
return;
}
@@ -801,15 +821,8 @@
}
}
- if (forceUpdate || snapshot.changes.test(RequestedLayerState::Changes::GameMode)) {
- snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE)
- ? requested.gameMode
- : parentSnapshot.gameMode;
- updateMetadata(snapshot, requested, args);
- if (args.includeMetadata) {
- snapshot.layerMetadata = parentSnapshot.layerMetadata;
- snapshot.layerMetadata.merge(requested.metadata);
- }
+ if (forceUpdate || snapshot.changes.test(RequestedLayerState::Changes::Metadata)) {
+ updateMetadataAndGameMode(snapshot, requested, args, parentSnapshot);
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eFixedTransformHintChanged ||
@@ -1178,6 +1191,15 @@
}
}
+void LayerSnapshotBuilder::forEachSnapshot(const Visitor& visitor,
+ const ConstPredicate& predicate) {
+ for (int i = 0; i < mNumInterestingSnapshots; i++) {
+ std::unique_ptr<LayerSnapshot>& snapshot = mSnapshots.at((size_t)i);
+ if (!predicate(*snapshot)) continue;
+ visitor(snapshot);
+ }
+}
+
void LayerSnapshotBuilder::forEachInputSnapshot(const ConstVisitor& visitor) const {
for (int i = mNumInterestingSnapshots - 1; i >= 0; i--) {
LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 1cec018..dbbad76 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -86,6 +86,11 @@
// Visit each visible snapshot in z-order and move the snapshot if needed
void forEachVisibleSnapshot(const Visitor& visitor);
+ typedef std::function<bool(const LayerSnapshot& snapshot)> ConstPredicate;
+ // Visit each snapshot that satisfies the predicate and move the snapshot if needed with visible
+ // snapshots in z-order
+ void forEachSnapshot(const Visitor& visitor, const ConstPredicate& predicate);
+
// Visit each snapshot interesting to input reverse z-order
void forEachInputSnapshot(const ConstVisitor& visitor) const;
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 3e8d740..c3c2999 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -328,6 +328,7 @@
changes |= RequestedLayerState::Changes::GameMode;
}
}
+ changes |= RequestedLayerState::Changes::Metadata;
}
if (clientState.what & layer_state_t::eFrameRateChanged) {
const auto compatibility =
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 846727b..be5ffbc 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -1641,7 +1641,7 @@
case FrameRateCategory::Normal:
return FpsRange{60_Hz, 120_Hz};
case FrameRateCategory::Low:
- return FpsRange{30_Hz, 120_Hz};
+ return FpsRange{48_Hz, 120_Hz};
case FrameRateCategory::HighHint:
case FrameRateCategory::NoPreference:
case FrameRateCategory::Default:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 60681a2..e669261 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -123,19 +123,22 @@
promotePacesetterDisplay(pacesetterIdOpt);
}
-void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
+void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
+ PhysicalDisplayId activeDisplayId) {
auto schedulePtr =
std::make_shared<VsyncSchedule>(selectorPtr->getActiveMode().modePtr, mFeatures,
[this](PhysicalDisplayId id, bool enable) {
onHardwareVsyncRequest(id, enable);
});
- registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr));
+ registerDisplayInternal(displayId, std::move(selectorPtr), std::move(schedulePtr),
+ activeDisplayId);
}
void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
RefreshRateSelectorPtr selectorPtr,
- VsyncSchedulePtr schedulePtr) {
+ VsyncSchedulePtr schedulePtr,
+ PhysicalDisplayId activeDisplayId) {
demotePacesetterDisplay();
auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) {
@@ -145,7 +148,7 @@
std::move(schedulePtr), mFeatures)
.second;
- return std::make_pair(promotePacesetterDisplayLocked(), isNew);
+ return std::make_pair(promotePacesetterDisplayLocked(activeDisplayId), isNew);
}();
applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
@@ -158,7 +161,9 @@
dispatchHotplug(displayId, Hotplug::Connected);
}
-void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) {
+void Scheduler::unregisterDisplay(PhysicalDisplayId displayId, PhysicalDisplayId activeDisplayId) {
+ LOG_ALWAYS_FATAL_IF(displayId == activeDisplayId, "Cannot unregister the active display!");
+
dispatchHotplug(displayId, Hotplug::Disconnected);
demotePacesetterDisplay();
@@ -173,7 +178,7 @@
// headless virtual display.)
LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");
- pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
+ pacesetterVsyncSchedule = promotePacesetterDisplayLocked(activeDisplayId);
}
applyNewVsyncSchedule(std::move(pacesetterVsyncSchedule));
}
@@ -1113,8 +1118,10 @@
.emitEvent = !choice.consideredSignals.idle});
}
- frameRateOverridesChanged = updateFrameRateOverridesLocked(consideredSignals, modeOpt->fps);
-
+ if (!FlagManager::getInstance().vrr_bugfix_dropped_frame()) {
+ frameRateOverridesChanged =
+ updateFrameRateOverridesLocked(consideredSignals, modeOpt->fps);
+ }
if (mPolicy.modeOpt != modeOpt) {
mPolicy.modeOpt = modeOpt;
refreshRateChanged = true;
@@ -1129,6 +1136,12 @@
if (refreshRateChanged) {
mSchedulerCallback.requestDisplayModes(std::move(modeRequests));
}
+
+ if (FlagManager::getInstance().vrr_bugfix_dropped_frame()) {
+ std::scoped_lock lock(mPolicyLock);
+ frameRateOverridesChanged =
+ updateFrameRateOverridesLocked(consideredSignals, mPolicy.modeOpt->fps);
+ }
if (frameRateOverridesChanged) {
mSchedulerCallback.triggerOnFrameRateOverridesChanged();
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ccaa05f..1a4aa79 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -101,9 +101,16 @@
using ConstVsyncSchedulePtr = std::shared_ptr<const VsyncSchedule>;
using VsyncSchedulePtr = std::shared_ptr<VsyncSchedule>;
- void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr) REQUIRES(kMainThreadContext)
+ // After registration/unregistration, `activeDisplayId` is promoted to pacesetter. Note that the
+ // active display is never unregistered, since hotplug disconnect never happens for activatable
+ // displays, i.e. a foldable's internal displays or otherwise the (internal or external) primary
+ // display.
+ // TODO: b/255635821 - Remove active display parameters.
+ void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr,
+ PhysicalDisplayId activeDisplayId) REQUIRES(kMainThreadContext)
EXCLUDES(mDisplayLock);
- void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
+ void unregisterDisplay(PhysicalDisplayId, PhysicalDisplayId activeDisplayId)
+ REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
void run();
@@ -390,8 +397,9 @@
// the caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
void demotePacesetterDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);
- void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr)
- REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
+ void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr,
+ PhysicalDisplayId activeDisplayId) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock);
struct Policy;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index dd3c4b0..0644aca 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -360,7 +360,11 @@
purgeTimelines(now);
for (auto& timeline : mTimelines) {
- if (timeline.validUntil() && timeline.validUntil()->ns() > vsync) {
+ const bool isVsyncValid = FlagManager::getInstance().vrr_bugfix_24q4()
+ ? timeline.isWithin(TimePoint::fromNs(vsync)) ==
+ VsyncTimeline::VsyncOnTimeline::Unique
+ : timeline.validUntil() && timeline.validUntil()->ns() > vsync;
+ if (isVsyncValid) {
return timeline.isVSyncInPhase(model, vsync, frameRate);
}
}
@@ -395,8 +399,14 @@
mLastCommittedVsync = TimePoint::fromNs(0);
} else {
- mTimelines.back().freeze(
- TimePoint::fromNs(mLastCommittedVsync.ns() + mIdealPeriod.ns() / 2));
+ if (FlagManager::getInstance().vrr_bugfix_24q4()) {
+ // We need to freeze the timeline at the committed vsync so that we don't
+ // overshoot the deadline.
+ mTimelines.back().freeze(mLastCommittedVsync);
+ } else {
+ mTimelines.back().freeze(
+ TimePoint::fromNs(mLastCommittedVsync.ns() + mIdealPeriod.ns() / 2));
+ }
}
mTimelines.emplace_back(mLastCommittedVsync, mIdealPeriod, renderRate);
purgeTimelines(TimePoint::fromNs(mClock->now()));
@@ -611,7 +621,10 @@
while (mTimelines.size() > 1) {
const auto validUntilOpt = mTimelines.front().validUntil();
- if (validUntilOpt && *validUntilOpt < now) {
+ const bool isTimelineOutDated = FlagManager::getInstance().vrr_bugfix_24q4()
+ ? mTimelines.front().isWithin(now) == VsyncTimeline::VsyncOnTimeline::Outside
+ : validUntilOpt && *validUntilOpt < now;
+ if (isTimelineOutDated) {
mTimelines.pop_front();
} else {
break;
@@ -660,9 +673,12 @@
vsyncTime += missedVsync.fixup.ns();
ATRACE_FORMAT_INSTANT("lastFrameMissed");
} else if (mightBackpressure && lastVsyncOpt) {
- // lastVsyncOpt is based on the old timeline before we shifted it. we should correct it
- // first before trying to use it.
- lastVsyncOpt = snapToVsyncAlignedWithRenderRate(model, *lastVsyncOpt);
+ if (!FlagManager::getInstance().vrr_bugfix_24q4()) {
+ // lastVsyncOpt does not need to be corrected with the new rate, and
+ // it should be used as is to avoid skipping a frame when changing rates are
+ // aligned at vsync time.
+ lastVsyncOpt = snapToVsyncAlignedWithRenderRate(model, *lastVsyncOpt);
+ }
const auto vsyncDiff = vsyncTime - *lastVsyncOpt;
if (vsyncDiff <= minFramePeriodOpt->ns() - threshold) {
// avoid a duplicate vsync
@@ -681,7 +697,10 @@
}
ATRACE_FORMAT_INSTANT("vsync in %.2fms", float(vsyncTime - TimePoint::now().ns()) / 1e6f);
- if (mValidUntil && vsyncTime > mValidUntil->ns()) {
+ const bool isVsyncInvalid = FlagManager::getInstance().vrr_bugfix_24q4()
+ ? isWithin(TimePoint::fromNs(vsyncTime)) == VsyncOnTimeline::Outside
+ : mValidUntil && vsyncTime > mValidUntil->ns();
+ if (isVsyncInvalid) {
ATRACE_FORMAT_INSTANT("no longer valid for vsync in %.2f",
static_cast<float>(vsyncTime - TimePoint::now().ns()) / 1e6f);
return std::nullopt;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 8ce61d8..66a7d71 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -106,6 +106,24 @@
void shiftVsyncSequence(Duration phase);
void setRenderRate(std::optional<Fps> renderRateOpt) { mRenderRateOpt = renderRateOpt; }
+ enum class VsyncOnTimeline {
+ Unique, // Within timeline, not shared with next timeline.
+ Shared, // Within timeline, shared with next timeline.
+ Outside, // Outside of the timeline.
+ };
+ VsyncOnTimeline isWithin(TimePoint vsync) {
+ const auto threshold = mIdealPeriod.ns() / 2;
+ if (!mValidUntil || vsync.ns() < mValidUntil->ns() - threshold) {
+ // if mValidUntil is absent then timeline is not frozen and
+ // vsync should be unique to that timeline.
+ return VsyncOnTimeline::Unique;
+ }
+ if (vsync.ns() > mValidUntil->ns() + threshold) {
+ return VsyncOnTimeline::Outside;
+ }
+ return VsyncOnTimeline::Shared;
+ }
+
private:
nsecs_t snapToVsyncAlignedWithRenderRate(Model model, nsecs_t vsync);
VsyncSequence getVsyncSequenceLocked(Model, nsecs_t vsync);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 596ec12..fd4bd11 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3855,7 +3855,8 @@
ftl::FakeGuard guard(kMainThreadContext);
// For hotplug reconnect, renew the registration since display modes have been reloaded.
- mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
+ mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector(),
+ mActiveDisplayId);
}
if (display->isVirtual()) {
@@ -3894,7 +3895,7 @@
if (display->isVirtual()) {
releaseVirtualDisplay(display->getVirtualId());
} else {
- mScheduler->unregisterDisplay(display->getPhysicalId());
+ mScheduler->unregisterDisplay(display->getPhysicalId(), mActiveDisplayId);
}
}
@@ -4506,7 +4507,8 @@
getFactory(), activeRefreshRate, *mTimeStats);
// The pacesetter must be registered before EventThread creation below.
- mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector());
+ mScheduler->registerDisplay(display->getPhysicalId(), display->holdRefreshRateSelector(),
+ mActiveDisplayId);
if (FlagManager::getInstance().vrr_config()) {
mScheduler->setRenderRate(display->getPhysicalId(), activeMode.fps,
/*applyImmediately*/ true);
@@ -5167,7 +5169,7 @@
status_t SurfaceFlinger::setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp,
const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId,
@@ -5182,7 +5184,7 @@
composerState.state.sanitize(permissions);
}
- for (DisplayState display : displays) {
+ for (DisplayState& display : displays) {
display.sanitize(permissions);
}
@@ -6389,15 +6391,23 @@
return NO_ERROR;
}
- // Traversal of drawing state must happen on the main thread.
- // Otherwise, SortedVector may have shared ownership during concurrent
- // traversals, which can result in use-after-frees.
+ // Collect debug data from main thread
std::string compositionLayers;
mScheduler
->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
dumpVisibleFrontEnd(compositionLayers);
})
.get();
+ // get window info listener data without the state lock
+ auto windowInfosDebug = mWindowInfosListenerInvoker->getDebugInfo();
+ compositionLayers.append("Window Infos:\n");
+ StringAppendF(&compositionLayers, " max send vsync id: %" PRId64 "\n",
+ ftl::to_underlying(windowInfosDebug.maxSendDelayVsyncId));
+ StringAppendF(&compositionLayers, " max send delay (ns): %" PRId64 " ns\n",
+ windowInfosDebug.maxSendDelayDuration);
+ StringAppendF(&compositionLayers, " unsent messages: %zu\n",
+ windowInfosDebug.pendingMessageCount);
+ compositionLayers.append("\n");
dumpAll(args, compositionLayers, result);
write(fd, result.c_str(), result.size());
return NO_ERROR;
@@ -6980,15 +6990,6 @@
result.append(mTimeStats->miniDump());
result.append("\n");
-
- result.append("Window Infos:\n");
- auto windowInfosDebug = mWindowInfosListenerInvoker->getDebugInfo();
- StringAppendF(&result, " max send vsync id: %" PRId64 "\n",
- ftl::to_underlying(windowInfosDebug.maxSendDelayVsyncId));
- StringAppendF(&result, " max send delay (ns): %" PRId64 " ns\n",
- windowInfosDebug.maxSendDelayDuration);
- StringAppendF(&result, " unsent messages: %zu\n", windowInfosDebug.pendingMessageCount);
- result.append("\n");
}
mat4 SurfaceFlinger::calculateColorMatrix(float saturation) {
@@ -9335,7 +9336,9 @@
std::vector<std::pair<Layer*, LayerFE*>> layers;
if (mLayerLifecycleManagerEnabled) {
nsecs_t currentTime = systemTime();
- mLayerSnapshotBuilder.forEachVisibleSnapshot(
+ const bool needsMetadata = mCompositionEngine->getFeatureFlags().test(
+ compositionengine::Feature::kSnapshotLayerMetadata);
+ mLayerSnapshotBuilder.forEachSnapshot(
[&](std::unique_ptr<frontend::LayerSnapshot>& snapshot) FTL_FAKE_GUARD(
kMainThreadContext) {
if (cursorOnly &&
@@ -9358,6 +9361,12 @@
layerFE->mSnapshot = std::move(snapshot);
refreshArgs.layers.push_back(layerFE);
layers.emplace_back(legacyLayer.get(), layerFE.get());
+ },
+ [needsMetadata](const frontend::LayerSnapshot& snapshot) {
+ return snapshot.isVisible ||
+ (needsMetadata &&
+ snapshot.changes.test(
+ frontend::RequestedLayerState::Changes::Metadata));
});
}
if (!mLayerLifecycleManagerEnabled) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ee541c4..7762bbe 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -559,7 +559,7 @@
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
status_t setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
InputWindowCommands inputWindowCommands, int64_t desiredPresentTime,
bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers,
bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 2e3273c..a56bb51 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -136,6 +136,7 @@
DUMP_READ_ONLY_FLAG(vulkan_renderengine);
DUMP_READ_ONLY_FLAG(renderable_buffer_usage);
DUMP_READ_ONLY_FLAG(vrr_bugfix_24q4);
+ DUMP_READ_ONLY_FLAG(vrr_bugfix_dropped_frame);
DUMP_READ_ONLY_FLAG(restore_blur_step);
DUMP_READ_ONLY_FLAG(dont_skip_on_early_ro);
DUMP_READ_ONLY_FLAG(protected_if_client);
@@ -242,6 +243,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(dont_skip_on_early_ro, "")
FLAG_MANAGER_READ_ONLY_FLAG(protected_if_client, "")
FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_24q4, "");
+FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_dropped_frame, "")
FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, "");
FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite")
FLAG_MANAGER_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed, "");
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index ab7a474..8799295 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -73,6 +73,7 @@
bool screenshot_fence_preservation() const;
bool vulkan_renderengine() const;
bool vrr_bugfix_24q4() const;
+ bool vrr_bugfix_dropped_frame() const;
bool renderable_buffer_usage() const;
bool restore_blur_step() const;
bool dont_skip_on_early_ro() const;
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index f4d4ee9..919ec17 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -136,4 +136,15 @@
}
} # vrr_bugfix_24q4
+flag {
+ name: "vrr_bugfix_dropped_frame"
+ namespace: "core_graphics"
+ description: "bug fix for VRR dropped frame"
+ bug: "343603085"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} # vrr_bugfix_dropped_frame
+
# IMPORTANT - please keep alphabetize to reduce merge conflicts
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index ebe11fb..d355e72 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -26,6 +26,7 @@
#include <private/android_filesystem_config.h>
#include <private/gui/ComposerServiceAIDL.h>
#include <ui/DisplayMode.h>
+#include <ui/DisplayState.h>
#include <ui/DynamicDisplayInfo.h>
#include <utils/String8.h>
#include <functional>
@@ -276,7 +277,7 @@
TEST_F(CredentialsTest, CaptureLayersTest) {
setupBackgroundSurface();
sp<GraphicBuffer> outBuffer;
- std::function<status_t()> condition = [=]() {
+ std::function<status_t()> condition = [=, this]() {
LayerCaptureArgs captureArgs;
captureArgs.layerHandle = mBGSurfaceControl->getHandle();
captureArgs.sourceCrop = {0, 0, 1, 1};
@@ -396,6 +397,56 @@
}
}
+TEST_F(CredentialsTest, DisplayTransactionPermissionTest) {
+ const auto display = getFirstDisplayToken();
+
+ ui::DisplayState displayState;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState));
+ const ui::Rotation initialOrientation = displayState.orientation;
+
+ // Set display orientation from an untrusted process. This should fail silently.
+ {
+ UIDFaker f{AID_BIN};
+ Transaction transaction;
+ Rect layerStackRect;
+ Rect displayRect;
+ transaction.setDisplayProjection(display, initialOrientation + ui::ROTATION_90,
+ layerStackRect, displayRect);
+ transaction.apply(/*synchronous=*/true);
+ }
+
+ // Verify that the display orientation did not change.
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState));
+ ASSERT_EQ(initialOrientation, displayState.orientation);
+
+ // Set display orientation from a trusted process.
+ {
+ UIDFaker f{AID_SYSTEM};
+ Transaction transaction;
+ Rect layerStackRect;
+ Rect displayRect;
+ transaction.setDisplayProjection(display, initialOrientation + ui::ROTATION_90,
+ layerStackRect, displayRect);
+ transaction.apply(/*synchronous=*/true);
+ }
+
+ // Verify that the display orientation did change.
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState));
+ ASSERT_EQ(initialOrientation + ui::ROTATION_90, displayState.orientation);
+
+ // Reset orientation
+ {
+ UIDFaker f{AID_SYSTEM};
+ Transaction transaction;
+ Rect layerStackRect;
+ Rect displayRect;
+ transaction.setDisplayProjection(display, initialOrientation, layerStackRect, displayRect);
+ transaction.apply(/*synchronous=*/true);
+ }
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayState(display, &displayState));
+ ASSERT_EQ(initialOrientation, displayState.orientation);
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 8b9ac93..54d4659 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -291,13 +291,106 @@
transactions.back().states.front().layerId = 1;
transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
mLifecycleManager.applyTransactions(transactions);
- EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::GameMode);
+ EXPECT_EQ(mLifecycleManager.getGlobalChanges(),
+ RequestedLayerState::Changes::GameMode | RequestedLayerState::Changes::Metadata);
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
EXPECT_EQ(getSnapshot(1)->clientChanges, layer_state_t::eMetadataChanged);
EXPECT_EQ(static_cast<int32_t>(getSnapshot(1)->gameMode), 42);
EXPECT_EQ(static_cast<int32_t>(getSnapshot(11)->gameMode), 42);
}
+TEST_F(LayerSnapshotTest, UpdateMetadata) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
+ // This test focuses on metadata used by ARC++ to ensure LayerMetadata is updated correctly,
+ // and not using stale data.
+ transactions.back().states.front().state.metadata = LayerMetadata();
+ transactions.back().states.front().state.metadata.setInt32(METADATA_OWNER_UID, 123);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_WINDOW_TYPE, 234);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_TASK_ID, 345);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_MOUSE_CURSOR, 456);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_ACCESSIBILITY_ID, 567);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_OWNER_PID, 678);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_CALLING_UID, 789);
+
+ transactions.back().states.front().layerId = 1;
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
+
+ mLifecycleManager.applyTransactions(transactions);
+ EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Metadata);
+
+ // Setting includeMetadata=true to ensure metadata update is applied to LayerSnapshot
+ LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = true,
+ .displays = mFrontEndDisplayInfos,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = true,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {}};
+ update(mSnapshotBuilder, args);
+
+ EXPECT_EQ(getSnapshot(1)->clientChanges, layer_state_t::eMetadataChanged);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_OWNER_UID, -1), 123);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_WINDOW_TYPE, -1), 234);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_TASK_ID, -1), 345);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_MOUSE_CURSOR, -1), 456);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_ACCESSIBILITY_ID, -1), 567);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_OWNER_PID, -1), 678);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_CALLING_UID, -1), 789);
+}
+
+TEST_F(LayerSnapshotTest, UpdateMetadataOfHiddenLayers) {
+ hideLayer(1);
+
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
+ // This test focuses on metadata used by ARC++ to ensure LayerMetadata is updated correctly,
+ // and not using stale data.
+ transactions.back().states.front().state.metadata = LayerMetadata();
+ transactions.back().states.front().state.metadata.setInt32(METADATA_OWNER_UID, 123);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_WINDOW_TYPE, 234);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_TASK_ID, 345);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_MOUSE_CURSOR, 456);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_ACCESSIBILITY_ID, 567);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_OWNER_PID, 678);
+ transactions.back().states.front().state.metadata.setInt32(METADATA_CALLING_UID, 789);
+
+ transactions.back().states.front().layerId = 1;
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
+
+ mLifecycleManager.applyTransactions(transactions);
+ EXPECT_EQ(mLifecycleManager.getGlobalChanges(),
+ RequestedLayerState::Changes::Metadata | RequestedLayerState::Changes::Visibility |
+ RequestedLayerState::Changes::VisibleRegion |
+ RequestedLayerState::Changes::AffectsChildren);
+
+ // Setting includeMetadata=true to ensure metadata update is applied to LayerSnapshot
+ LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = true,
+ .displays = mFrontEndDisplayInfos,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = true,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {}};
+ update(mSnapshotBuilder, args);
+
+ EXPECT_EQ(static_cast<int64_t>(getSnapshot(1)->clientChanges),
+ layer_state_t::eMetadataChanged | layer_state_t::eFlagsChanged);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_OWNER_UID, -1), 123);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_WINDOW_TYPE, -1), 234);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_TASK_ID, -1), 345);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_MOUSE_CURSOR, -1), 456);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_ACCESSIBILITY_ID, -1), 567);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_OWNER_PID, -1), 678);
+ EXPECT_EQ(getSnapshot(1)->layerMetadata.getInt32(METADATA_CALLING_UID, -1), 789);
+}
+
TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotes) {
// ROOT
// ├── 1
@@ -1304,6 +1397,17 @@
EXPECT_TRUE(foundInputLayer);
}
+TEST_F(LayerSnapshotTest, ForEachSnapshotsWithPredicate) {
+ std::vector<uint32_t> visitedUniqueSequences;
+ mSnapshotBuilder.forEachSnapshot(
+ [&](const std::unique_ptr<frontend::LayerSnapshot>& snapshot) {
+ visitedUniqueSequences.push_back(snapshot->uniqueSequence);
+ },
+ [](const frontend::LayerSnapshot& snapshot) { return snapshot.uniqueSequence == 111; });
+ EXPECT_EQ(visitedUniqueSequences.size(), 1u);
+ EXPECT_EQ(visitedUniqueSequences[0], 111u);
+}
+
TEST_F(LayerSnapshotTest, canOccludePresentation) {
setFlags(12, layer_state_t::eCanOccludePresentation, layer_state_t::eCanOccludePresentation);
LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index cf9a7d3..06c4e30 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1562,7 +1562,7 @@
// When frame rates get an equal score, the lower is chosen, unless there are Max votes.
{0_Hz, FrameRateCategory::High, 90_Hz},
{0_Hz, FrameRateCategory::Normal, 60_Hz},
- {0_Hz, FrameRateCategory::Low, 30_Hz},
+ {0_Hz, FrameRateCategory::Low, 60_Hz},
{0_Hz, FrameRateCategory::NoPreference, 60_Hz},
// Cases that have both desired frame rate and frame rate category requirements.
@@ -1609,6 +1609,77 @@
}
}
+TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_120_vrr) {
+ if (GetParam() != Config::FrameRateOverride::Enabled) {
+ return;
+ }
+
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+ // Device with VRR config mode
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+
+ struct Case {
+ // Params
+ Fps desiredFrameRate = 0_Hz;
+ FrameRateCategory frameRateCategory = FrameRateCategory::Default;
+
+ // Expected result
+ Fps expectedFrameRate = 0_Hz;
+ };
+
+ // Prepare a table with the vote and the expected refresh rate
+ const std::initializer_list<Case> testCases = {
+ // Cases that only have frame rate category requirements, but no desired frame rate.
+ // When frame rates get an equal score, the lower is chosen, unless there are Max votes.
+ {0_Hz, FrameRateCategory::High, 120_Hz},
+ {0_Hz, FrameRateCategory::Normal, 60_Hz},
+ {0_Hz, FrameRateCategory::Low, 48_Hz},
+ {0_Hz, FrameRateCategory::NoPreference, 120_Hz},
+
+ // Cases that have both desired frame rate and frame rate category requirements.
+ {24_Hz, FrameRateCategory::High, 120_Hz},
+ {30_Hz, FrameRateCategory::High, 120_Hz},
+ {12_Hz, FrameRateCategory::Normal, 60_Hz},
+ {24_Hz, FrameRateCategory::Low, 48_Hz},
+ {30_Hz, FrameRateCategory::NoPreference, 30_Hz},
+
+ // Cases that only have desired frame rate.
+ {30_Hz, FrameRateCategory::Default, 30_Hz},
+ };
+
+ for (auto testCase : testCases) {
+ std::vector<LayerRequirement> layers;
+ ALOGI("**** %s: Testing desiredFrameRate=%s, frameRateCategory=%s", __func__,
+ to_string(testCase.desiredFrameRate).c_str(),
+ ftl::enum_string(testCase.frameRateCategory).c_str());
+
+ if (testCase.desiredFrameRate.isValid()) {
+ std::stringstream ss;
+ ss << to_string(testCase.desiredFrameRate) << "ExplicitDefault";
+ LayerRequirement layer = {.name = ss.str(),
+ .vote = LayerVoteType::ExplicitDefault,
+ .desiredRefreshRate = testCase.desiredFrameRate,
+ .weight = 1.f};
+ layers.push_back(layer);
+ }
+
+ if (testCase.frameRateCategory != FrameRateCategory::Default) {
+ std::stringstream ss;
+ ss << "ExplicitCategory (" << ftl::enum_string(testCase.frameRateCategory) << ")";
+ LayerRequirement layer = {.name = ss.str(),
+ .vote = LayerVoteType::ExplicitCategory,
+ .frameRateCategory = testCase.frameRateCategory,
+ .weight = 1.f};
+ layers.push_back(layer);
+ }
+
+ EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers).fps)
+ << "Did not get expected frame rate for frameRate="
+ << to_string(testCase.desiredFrameRate)
+ << " category=" << ftl::enum_string(testCase.frameRateCategory);
+ }
+}
+
TEST_P(RefreshRateSelectorTest,
getBestFrameRateMode_withFrameRateCategoryMultiLayers_30_60_90_120) {
auto selector = createSelector(makeModes(kMode30, kMode60, kMode90, kMode120), kModeId60);
@@ -2140,14 +2211,14 @@
// These layers may switch modes because smoothSwitchOnly=false.
{FrameRateCategory::Default, false, 120_Hz, kModeId120},
{FrameRateCategory::NoPreference, false, 120_Hz, kModeId120},
- {FrameRateCategory::Low, false, 30_Hz, kModeId60},
+ {FrameRateCategory::Low, false, 60_Hz, kModeId60},
{FrameRateCategory::Normal, false, 60_Hz, kModeId60},
{FrameRateCategory::High, false, 120_Hz, kModeId120},
// These layers cannot change mode due to smoothSwitchOnly, and will definitely use
// active mode (120Hz).
{FrameRateCategory::NoPreference, true, 120_Hz, kModeId120},
- {FrameRateCategory::Low, true, 40_Hz, kModeId120},
+ {FrameRateCategory::Low, true, 120_Hz, kModeId120},
{FrameRateCategory::Normal, true, 120_Hz, kModeId120},
{FrameRateCategory::High, true, 120_Hz, kModeId120},
};
@@ -2207,13 +2278,13 @@
{FrameRateCategory::Default, false, 120_Hz},
// TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate.
{FrameRateCategory::NoPreference, false, 120_Hz},
- {FrameRateCategory::Low, false, 30_Hz},
+ {FrameRateCategory::Low, false, 48_Hz},
{FrameRateCategory::Normal, false, 60_Hz},
{FrameRateCategory::High, false, 120_Hz},
{FrameRateCategory::Default, true, 120_Hz},
// TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate.
{FrameRateCategory::NoPreference, true, 120_Hz},
- {FrameRateCategory::Low, true, 30_Hz},
+ {FrameRateCategory::Low, true, 48_Hz},
{FrameRateCategory::Normal, true, 60_Hz},
{FrameRateCategory::High, true, 120_Hz},
};
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4fb0690..fc54a8b 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -343,12 +343,15 @@
}
TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) {
+ constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1;
mScheduler->registerDisplay(kDisplayId1,
std::make_shared<RefreshRateSelector>(kDisplay1Modes,
- kDisplay1Mode60->getId()));
+ kDisplay1Mode60->getId()),
+ kActiveDisplayId);
mScheduler->registerDisplay(kDisplayId2,
std::make_shared<RefreshRateSelector>(kDisplay2Modes,
- kDisplay2Mode60->getId()));
+ kDisplay2Mode60->getId()),
+ kActiveDisplayId);
mScheduler->setDisplayPowerMode(kDisplayId1, hal::PowerMode::ON);
mScheduler->setDisplayPowerMode(kDisplayId2, hal::PowerMode::ON);
@@ -411,10 +414,10 @@
{
// The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120
// Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz.
- mScheduler
- ->registerDisplay(kDisplayId3,
- std::make_shared<RefreshRateSelector>(kDisplay3Modes,
- kDisplay3Mode60->getId()));
+ mScheduler->registerDisplay(kDisplayId3,
+ std::make_shared<RefreshRateSelector>(kDisplay3Modes,
+ kDisplay3Mode60->getId()),
+ kActiveDisplayId);
mScheduler->setDisplayPowerMode(kDisplayId3, hal::PowerMode::ON);
const GlobalSignals globalSignals = {.touch = true};
@@ -457,12 +460,15 @@
}
TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) {
+ constexpr PhysicalDisplayId kActiveDisplayId = kDisplayId1;
mScheduler->registerDisplay(kDisplayId1,
std::make_shared<RefreshRateSelector>(kDisplay1Modes,
- kDisplay1Mode60->getId()));
+ kDisplay1Mode60->getId()),
+ kActiveDisplayId);
mScheduler->registerDisplay(kDisplayId2,
std::make_shared<RefreshRateSelector>(kDisplay2Modes,
- kDisplay2Mode60->getId()));
+ kDisplay2Mode60->getId()),
+ kActiveDisplayId);
using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;
@@ -585,7 +591,8 @@
mFlinger.getTimeStats(),
mSchedulerCallback};
- scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker);
+ scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, std::nullopt,
+ vrrTracker);
vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate);
scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate, /*applyImmediately*/ false);
vrrTracker->addVsyncTimestamp(0);
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 198a5de..f063809 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -53,7 +53,7 @@
factory, selectorPtr->getActiveMode().fps, timeStats) {
const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId();
registerDisplay(displayId, std::move(selectorPtr), std::move(controller),
- std::move(tracker));
+ std::move(tracker), displayId);
ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
// Execute task to prevent broken promise exception on destruction.
@@ -85,14 +85,16 @@
void registerDisplay(
PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
+ std::optional<PhysicalDisplayId> activeDisplayIdOpt = {},
std::shared_ptr<VSyncTracker> vsyncTracker = std::make_shared<mock::VSyncTracker>()) {
registerDisplay(displayId, std::move(selectorPtr),
- std::make_unique<mock::VsyncController>(), vsyncTracker);
+ std::make_unique<mock::VsyncController>(), vsyncTracker,
+ activeDisplayIdOpt.value_or(displayId));
}
void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
std::unique_ptr<VsyncController> controller,
- std::shared_ptr<VSyncTracker> tracker) {
+ std::shared_ptr<VSyncTracker> tracker, PhysicalDisplayId activeDisplayId) {
ftl::FakeGuard guard(kMainThreadContext);
Scheduler::registerDisplayInternal(displayId, std::move(selectorPtr),
std::shared_ptr<VsyncSchedule>(
@@ -101,16 +103,12 @@
mock::VSyncDispatch>(),
std::move(controller),
mockRequestHardwareVsync
- .AsStdFunction())));
+ .AsStdFunction())),
+ activeDisplayId);
}
testing::MockFunction<void(PhysicalDisplayId, bool)> mockRequestHardwareVsync;
- void unregisterDisplay(PhysicalDisplayId displayId) {
- ftl::FakeGuard guard(kMainThreadContext);
- Scheduler::unregisterDisplay(displayId);
- }
-
void setDisplayPowerMode(PhysicalDisplayId displayId, hal::PowerMode powerMode) {
ftl::FakeGuard guard(kMainThreadContext);
Scheduler::setDisplayPowerMode(displayId, powerMode);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 007383b..b5b36be 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -528,7 +528,7 @@
auto setTransactionState(
const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers,
bool hasListenerCallbacks, std::vector<ListenerCallbacks>& listenerCallbacks,
@@ -1118,8 +1118,8 @@
if (mFlinger.scheduler() && mSchedulerRegistration) {
mFlinger.scheduler()->registerDisplay(*physicalId,
mCreationArgs.refreshRateSelector,
- std::move(controller),
- std::move(tracker));
+ std::move(controller), std::move(tracker),
+ mFlinger.mutableActiveDisplayId());
}
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 5109ea6..f36a8a6 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -673,6 +673,36 @@
EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 6 * mPeriod));
}
+TEST_F(VSyncPredictorTest, setRenderRateWhenRenderRateGoesDown) {
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+ SET_FLAG_FOR_TEST(flags::vrr_bugfix_24q4, true);
+
+ const int32_t kGroup = 0;
+ const auto kResolution = ui::Size(1920, 1080);
+ const auto vsyncRate = Fps::fromPeriodNsecs(500);
+ const auto minFrameRate = Fps::fromPeriodNsecs(1000);
+ hal::VrrConfig vrrConfig;
+ vrrConfig.minFrameIntervalNs = minFrameRate.getPeriodNsecs();
+ const ftl::NonNull<DisplayModePtr> kMode =
+ ftl::as_non_null(createDisplayModeBuilder(DisplayModeId(0), vsyncRate, kGroup,
+ kResolution, DEFAULT_DISPLAY_ID)
+ .setVrrConfig(std::move(vrrConfig))
+ .build());
+
+ VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), kMode, kHistorySize,
+ kMinimumSamplesForPrediction, kOutlierTolerancePercent};
+
+ Fps frameRate = Fps::fromPeriodNsecs(1000);
+ vrrTracker.setRenderRate(frameRate, /*applyImmediately*/ false);
+ vrrTracker.addVsyncTimestamp(0);
+ EXPECT_EQ(1000, vrrTracker.nextAnticipatedVSyncTimeFrom(700));
+ EXPECT_EQ(2000, vrrTracker.nextAnticipatedVSyncTimeFrom(1000, 1000));
+
+ frameRate = Fps::fromPeriodNsecs(3000);
+ vrrTracker.setRenderRate(frameRate, /*applyImmediately*/ false);
+ EXPECT_TRUE(vrrTracker.isVSyncInPhase(2000, frameRate));
+}
+
TEST_F(VSyncPredictorTest, setRenderRateHighIsAppliedImmediately) {
SET_FLAG_FOR_TEST(flags::vrr_config, true);
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index a9706bc..a3fe33e 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -178,7 +178,7 @@
INIT_PROC(false, instance, GetPhysicalDeviceExternalSemaphoreProperties);
INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties);
INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
- INIT_PROC_EXT(KHR_swapchain, false, instance, GetPhysicalDevicePresentRectanglesKHR);
+ INIT_PROC_EXT(KHR_swapchain, true, instance, GetPhysicalDevicePresentRectanglesKHR);
INIT_PROC(false, instance, GetPhysicalDeviceToolProperties);
// clang-format on
@@ -325,9 +325,9 @@
INIT_PROC(false, dev, BindBufferMemory2);
INIT_PROC(false, dev, BindImageMemory2);
INIT_PROC(false, dev, CmdSetDeviceMask);
- INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupPresentCapabilitiesKHR);
- INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupSurfacePresentModesKHR);
- INIT_PROC_EXT(KHR_swapchain, false, dev, AcquireNextImage2KHR);
+ INIT_PROC_EXT(KHR_swapchain, true, dev, GetDeviceGroupPresentCapabilitiesKHR);
+ INIT_PROC_EXT(KHR_swapchain, true, dev, GetDeviceGroupSurfacePresentModesKHR);
+ INIT_PROC_EXT(KHR_swapchain, true, dev, AcquireNextImage2KHR);
INIT_PROC(false, dev, CmdDispatchBase);
INIT_PROC(false, dev, CreateDescriptorUpdateTemplate);
INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate);
@@ -659,6 +659,8 @@
"vkGetDrmDisplayEXT",
"vkGetInstanceProcAddr",
"vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
+ "vkGetPhysicalDeviceCalibrateableTimeDomainsKHR",
+ "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR",
"vkGetPhysicalDeviceDisplayPlaneProperties2KHR",
"vkGetPhysicalDeviceDisplayProperties2KHR",
"vkGetPhysicalDeviceExternalBufferProperties",
@@ -703,6 +705,7 @@
"vkGetPhysicalDeviceToolProperties",
"vkGetPhysicalDeviceToolPropertiesEXT",
"vkGetPhysicalDeviceVideoCapabilitiesKHR",
+ "vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR",
"vkGetPhysicalDeviceVideoFormatPropertiesKHR",
"vkSubmitDebugUtilsMessageEXT",
};
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 9e67725..00e987f 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1473,23 +1473,14 @@
image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
image_format_properties.pNext = &ahb_usage;
- if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2) {
- VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2(
- pdev, &image_format_info, &image_format_properties);
- if (result != VK_SUCCESS) {
- ALOGE("VkGetPhysicalDeviceImageFormatProperties2 for AHB usage failed: %d", result);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- }
- else {
- VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR(
- pdev, &image_format_info,
- &image_format_properties);
- if (result != VK_SUCCESS) {
- ALOGE("VkGetPhysicalDeviceImageFormatProperties2KHR for AHB usage failed: %d",
- result);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
+ VkResult result = GetPhysicalDeviceImageFormatProperties2(
+ pdev, &image_format_info, &image_format_properties);
+ if (result != VK_SUCCESS) {
+ ALOGE(
+ "VkGetPhysicalDeviceImageFormatProperties2 for AHB usage "
+ "failed: %d",
+ result);
+ return VK_ERROR_SURFACE_LOST_KHR;
}
// Determine if USAGE_FRONT_BUFFER is needed.
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 866c1b7..6b4cbad 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -351,9 +351,50 @@
'external', 'vulkan-headers', 'registry', 'vk.xml')
tree = element_tree.parse(registry)
root = tree.getroot()
+
+ for exts in root.iter('extensions'):
+ for extension in exts.iter('extension'):
+ if 'vulkan' not in extension.get('supported').split(','):
+ # ANDROID_native_buffer is a weird special case -- it's declared in vk.xml as
+ # disabled but we _do_ want to generate plumbing for it in the Android loader.
+ if extension.get('name') != 'VK_ANDROID_native_buffer':
+ print('skip extension disabled or not for vulkan: ' + extension.get('name'))
+ continue
+
+ apiversion = 'VK_VERSION_1_0'
+ if extension.tag == 'extension':
+ extname = extension.get('name')
+ if (extension.get('type') == 'instance' and
+ extension.get('promotedto') is not None):
+ promoted_inst_ext_dict[extname] = \
+ version_2_api_version(extension.get('promotedto'))
+ for req in extension.iter('require'):
+ if req.get('feature') is not None:
+ apiversion = req.get('feature')
+ for commands in req:
+ if commands.tag == 'command':
+ cmd_name = commands.get('name')
+ if cmd_name not in extension_dict:
+ extension_dict[cmd_name] = extname
+ version_dict[cmd_name] = apiversion
+
+ for feature in root.iter('feature'):
+ if 'vulkan' not in feature.get('api').split(','):
+ continue
+
+ apiversion = feature.get('name')
+ for req in feature.iter('require'):
+ for command in req:
+ if command.tag == 'command':
+ cmd_name = command.get('name')
+ version_dict[cmd_name] = apiversion
+
for commands in root.iter('commands'):
for command in commands:
if command.tag == 'command':
+ if command.get('api') == 'vulkansc':
+ continue
+
parameter_list = []
protoset = False
cmd_name = ''
@@ -361,12 +402,18 @@
if command.get('alias') is not None:
alias = command.get('alias')
cmd_name = command.get('name')
- alias_dict[cmd_name] = alias
- command_list.append(cmd_name)
- param_dict[cmd_name] = param_dict[alias].copy()
- return_type_dict[cmd_name] = return_type_dict[alias]
+ # At this stage all valid commands have been added to the version
+ # dict so we can use it to filter valid commands
+ if cmd_name in version_dict:
+ alias_dict[cmd_name] = alias
+ command_list.append(cmd_name)
+ param_dict[cmd_name] = param_dict[alias].copy()
+ return_type_dict[cmd_name] = return_type_dict[alias]
for params in command:
if params.tag == 'param':
+ if params.get('api') == 'vulkansc':
+ # skip SC-only param variant
+ continue
param_type = ''
if params.text is not None and params.text.strip():
param_type = params.text.strip() + ' '
@@ -387,39 +434,13 @@
cmd_type = c.text
if c.tag == 'name':
cmd_name = c.text
- protoset = True
- command_list.append(cmd_name)
- return_type_dict[cmd_name] = cmd_type
+ if cmd_name in version_dict:
+ protoset = True
+ command_list.append(cmd_name)
+ return_type_dict[cmd_name] = cmd_type
if protoset:
param_dict[cmd_name] = parameter_list.copy()
- for exts in root.iter('extensions'):
- for extension in exts:
- apiversion = 'VK_VERSION_1_0'
- if extension.tag == 'extension':
- extname = extension.get('name')
- if (extension.get('type') == 'instance' and
- extension.get('promotedto') is not None):
- promoted_inst_ext_dict[extname] = \
- version_2_api_version(extension.get('promotedto'))
- for req in extension:
- if req.get('feature') is not None:
- apiversion = req.get('feature')
- for commands in req:
- if commands.tag == 'command':
- cmd_name = commands.get('name')
- if cmd_name not in extension_dict:
- extension_dict[cmd_name] = extname
- version_dict[cmd_name] = apiversion
-
- for feature in root.iter('feature'):
- apiversion = feature.get('name')
- for req in feature:
- for command in req:
- if command.tag == 'command':
- cmd_name = command.get('name')
- if cmd_name in command_list:
- version_dict[cmd_name] = apiversion
version_code_set = set()
for version in version_dict.values():
diff --git a/vulkan/scripts/null_generator.py b/vulkan/scripts/null_generator.py
index e9faef6..3624c1d 100644
--- a/vulkan/scripts/null_generator.py
+++ b/vulkan/scripts/null_generator.py
@@ -89,6 +89,8 @@
f.write(gencom.copyright_and_warning(2015))
f.write("""\
+#include <android/hardware_buffer.h>
+
#include <algorithm>
#include "null_driver_gen.h"