Merge "Fix ASystemFont docs." into main am: ef291395cd am: c8721a7dec
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/3142698
Change-Id: I74851b165f0e5d3de24a221ba2ba6878ea7f6d2f
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/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/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/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/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/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/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/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/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/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/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/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/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 60681a2..26e11e5 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));
}
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..5b40acf 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);
@@ -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/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/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..4197cbd 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -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);