Merge "SF: Reject hotplugs on invalid or duplicate ports" into main
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index 83d5967..96d35cd 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -234,6 +234,12 @@
//
bool erase(const key_type& key) { return erase(key, begin()); }
+ // Removes a mapping.
+ //
+ // The last() and end() iterators, as well as those to the erased mapping, are invalidated.
+ //
+ void erase(iterator it) { map_.unstable_erase(it); }
+
// Removes all mappings.
//
// All iterators are invalidated.
diff --git a/include/input/BlockingQueue.h b/include/input/BlockingQueue.h
index f848c82..6e32de6 100644
--- a/include/input/BlockingQueue.h
+++ b/include/input/BlockingQueue.h
@@ -16,6 +16,7 @@
#pragma once
+#include <input/PrintTools.h>
#include <condition_variable>
#include <functional>
#include <list>
@@ -126,11 +127,21 @@
* Primary used for debugging.
* Does not block.
*/
- size_t size() {
+ size_t size() const {
std::scoped_lock lock(mLock);
return mQueue.size();
}
+ bool empty() const {
+ std::scoped_lock lock(mLock);
+ return mQueue.empty();
+ }
+
+ std::string dump(std::string (*toString)(const T&) = constToString) const {
+ std::scoped_lock lock(mLock);
+ return dumpContainer(mQueue, toString);
+ }
+
private:
const std::optional<size_t> mCapacity;
/**
@@ -140,7 +151,7 @@
/**
* Lock for accessing and waiting on elements.
*/
- std::mutex mLock;
+ mutable std::mutex mLock;
std::list<T> mQueue GUARDED_BY(mLock);
};
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index bb45ad2..993ad82 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -263,7 +263,6 @@
"android.utils.IMemory",
"android.utils.IMemoryHeap",
"com.android.car.procfsinspector.IProcfsInspector",
- "com.android.internal.app.IAppOpsCallback",
"com.android.internal.app.IAppOpsService",
"com.android.internal.app.IBatteryStats",
"com.android.internal.os.IResultReceiver",
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 4036551..46651ce 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -26,6 +26,7 @@
],
visibility: [
"//device/google/cuttlefish/shared/minidroid/sample",
+ "//hardware/interfaces/security/see:__subpackages__",
"//packages/modules/Virtualization:__subpackages__",
],
apex_available: [
diff --git a/libs/binder/tests/binderStabilityIntegrationTest.cpp b/libs/binder/tests/binderStabilityIntegrationTest.cpp
index a3fc9cc..cbc4180 100644
--- a/libs/binder/tests/binderStabilityIntegrationTest.cpp
+++ b/libs/binder/tests/binderStabilityIntegrationTest.cpp
@@ -47,6 +47,7 @@
Stability::Level level = Stability::Level::UNDECLARED;
switch (partition) {
+ case Partition::PRODUCT:
case Partition::SYSTEM:
case Partition::SYSTEM_EXT:
level = Stability::Level::SYSTEM;
diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs
index a8acded..16147dd 100644
--- a/libs/debugstore/rust/src/core.rs
+++ b/libs/debugstore/rust/src/core.rs
@@ -48,7 +48,7 @@
///
/// This constant is used as a part of the debug store's data format,
/// allowing for version tracking and compatibility checks.
- const ENCODE_VERSION: u32 = 2;
+ const ENCODE_VERSION: u32 = 3;
/// Creates a new instance of `DebugStore` with specified event limit and maximum delay.
fn new() -> Self {
@@ -123,9 +123,11 @@
impl fmt::Display for DebugStore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Write the debug store header information
let uptime_now = uptimeMillis();
write!(f, "{},{},{}::", Self::ENCODE_VERSION, self.event_store.len(), uptime_now)?;
+ // Join events with a separator
write!(
f,
"{}",
@@ -136,7 +138,10 @@
acc.push_str(&event.to_string());
acc
})
- )
+ )?;
+
+ // Write the debug store footer
+ write!(f, ";;")
}
}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 0848fac..c770db9 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -415,14 +415,12 @@
stat.frameEventStats.dequeueReadyTime);
}
auto currFrameNumber = stat.frameEventStats.frameNumber;
- std::vector<ReleaseCallbackId> staleReleases;
- for (const auto& [key, value]: mSubmitted) {
- if (currFrameNumber > key.framenumber) {
- staleReleases.push_back(key);
+ // Release stale buffers.
+ for (const auto& [key, _] : mSubmitted) {
+ if (currFrameNumber <= key.framenumber) {
+ continue; // not stale.
}
- }
- for (const auto& staleRelease : staleReleases) {
- releaseBufferCallbackLocked(staleRelease,
+ releaseBufferCallbackLocked(key,
stat.previousReleaseFence
? stat.previousReleaseFence
: Fence::NO_FENCE,
@@ -618,7 +616,7 @@
mNumAcquired++;
mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
- mSubmitted[releaseCallbackId] = bufferItem;
+ mSubmitted.emplace_or_replace(releaseCallbackId, bufferItem);
bool needsDisconnect = false;
mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
@@ -851,7 +849,7 @@
void BLASTBufferQueue::onFrameDequeued(const uint64_t bufferId) {
std::lock_guard _lock{mTimestampMutex};
- mDequeueTimestamps[bufferId] = systemTime();
+ mDequeueTimestamps.emplace_or_replace(bufferId, systemTime());
};
void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) {
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index ba50bf8..ab747b9 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -238,7 +238,7 @@
// socket should be atomic across processes.
DisplayEventReceiver::Event event;
event.header =
- DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
+ DisplayEventReceiver::Event::Header{DisplayEventType::DISPLAY_EVENT_NULL,
PhysicalDisplayId::fromPort(0), systemTime()};
injectEvent(event);
}
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 68f10f4..6f23885 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -167,7 +167,7 @@
for (ssize_t i = 0; i < n; i++) {
const DisplayEventReceiver::Event& ev = buf[i];
switch (ev.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ case DisplayEventType::DISPLAY_EVENT_VSYNC:
// Later vsync events will just overwrite the info from earlier
// ones. That's fine, we only care about the most recent.
gotVsync = true;
@@ -183,7 +183,7 @@
ATRACE_INT("RenderRate", fps);
}
break;
- case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ case DisplayEventType::DISPLAY_EVENT_HOTPLUG:
if (ev.hotplug.connectionError == 0) {
dispatchHotplug(ev.header.timestamp, ev.header.displayId,
ev.hotplug.connected);
@@ -192,31 +192,28 @@
ev.hotplug.connectionError);
}
break;
- case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
+ case DisplayEventType::DISPLAY_EVENT_MODE_CHANGE:
dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
break;
- case DisplayEventReceiver::DISPLAY_EVENT_NULL:
+ case DisplayEventType::DISPLAY_EVENT_NULL:
dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
break;
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+ case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
mFrameRateOverrides.emplace_back(ev.frameRateOverride);
break;
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+ case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
std::move(mFrameRateOverrides));
break;
- case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
+ case DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
dispatchHdcpLevelsChanged(ev.header.displayId,
ev.hdcpLevelsChange.connectedLevel,
ev.hdcpLevelsChange.maxLevel);
break;
- case DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION:
+ case DisplayEventType::DISPLAY_EVENT_MODE_REJECTION:
dispatchModeRejected(ev.header.displayId, ev.modeRejection.modeId);
break;
- default:
- ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
- break;
}
}
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 44aac9b..ebfc62f 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -67,7 +67,6 @@
reserved(0),
cornerRadius(0.0f),
clientDrawnCornerRadius(0.0f),
- clientDrawnShadowRadius(0.0f),
backgroundBlurRadius(0),
color(0),
bufferTransform(0),
@@ -143,7 +142,6 @@
SAFE_PARCEL(output.write, colorTransform.asArray(), 16 * sizeof(float));
SAFE_PARCEL(output.writeFloat, cornerRadius);
SAFE_PARCEL(output.writeFloat, clientDrawnCornerRadius);
- SAFE_PARCEL(output.writeFloat, clientDrawnShadowRadius);
SAFE_PARCEL(output.writeUint32, backgroundBlurRadius);
SAFE_PARCEL(output.writeParcelable, metadata);
SAFE_PARCEL(output.writeFloat, bgColor.r);
@@ -279,7 +277,6 @@
SAFE_PARCEL(input.read, &colorTransform, 16 * sizeof(float));
SAFE_PARCEL(input.readFloat, &cornerRadius);
SAFE_PARCEL(input.readFloat, &clientDrawnCornerRadius);
- SAFE_PARCEL(input.readFloat, &clientDrawnShadowRadius);
SAFE_PARCEL(input.readUint32, &backgroundBlurRadius);
SAFE_PARCEL(input.readParcelable, &metadata);
@@ -606,10 +603,6 @@
what |= eClientDrawnCornerRadiusChanged;
clientDrawnCornerRadius = other.clientDrawnCornerRadius;
}
- if (other.what & eClientDrawnShadowsChanged) {
- what |= eClientDrawnShadowsChanged;
- clientDrawnShadowRadius = other.clientDrawnShadowRadius;
- }
if (other.what & eBackgroundBlurRadiusChanged) {
what |= eBackgroundBlurRadiusChanged;
backgroundBlurRadius = other.backgroundBlurRadius;
@@ -824,7 +817,6 @@
CHECK_DIFF(diff, eLayerStackChanged, other, layerStack);
CHECK_DIFF(diff, eCornerRadiusChanged, other, cornerRadius);
CHECK_DIFF(diff, eClientDrawnCornerRadiusChanged, other, clientDrawnCornerRadius);
- CHECK_DIFF(diff, eClientDrawnShadowsChanged, other, clientDrawnShadowRadius);
CHECK_DIFF(diff, eBackgroundBlurRadiusChanged, other, backgroundBlurRadius);
if (other.what & eBlurRegionsChanged) diff |= eBlurRegionsChanged;
if (other.what & eRelativeLayerChanged) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index f964c4d..37ed23b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1687,17 +1687,6 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setClientDrawnShadowRadius(
- const sp<SurfaceControl>& sc, float clientDrawnShadowRadius) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eClientDrawnShadowsChanged;
- s->clientDrawnShadowRadius = clientDrawnShadowRadius;
- return *this;
-}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius(
const sp<SurfaceControl>& sc, int backgroundBlurRadius) {
layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index b97a496..cdc2150 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -20,6 +20,7 @@
#include <optional>
#include <queue>
+#include <ftl/small_map.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
#include <gui/IGraphicBufferConsumer.h>
@@ -36,6 +37,10 @@
namespace android {
+// Sizes determined empirically to avoid allocations during common activity.
+constexpr size_t kSubmittedBuffersMapSizeHint = 8;
+constexpr size_t kDequeueTimestampsMapSizeHint = 32;
+
class BLASTBufferQueue;
class BufferItemConsumer;
@@ -206,7 +211,7 @@
// Keep a reference to the submitted buffers so we can release when surfaceflinger drops the
// buffer or the buffer has been presented and a new buffer is ready to be presented.
- std::unordered_map<ReleaseCallbackId, BufferItem, ReleaseBufferCallbackIdHash> mSubmitted
+ ftl::SmallMap<ReleaseCallbackId, BufferItem, kSubmittedBuffersMapSizeHint> mSubmitted
GUARDED_BY(mMutex);
// Keep a queue of the released buffers instead of immediately releasing
@@ -291,8 +296,8 @@
std::mutex mTimestampMutex;
// Tracks buffer dequeue times by the client. This info is sent to SurfaceFlinger which uses
// it for debugging purposes.
- std::unordered_map<uint64_t /* bufferId */, nsecs_t> mDequeueTimestamps
- GUARDED_BY(mTimestampMutex);
+ ftl::SmallMap<uint64_t /* bufferId */, nsecs_t, kDequeueTimestampsMapSizeHint>
+ mDequeueTimestamps GUARDED_BY(mTimestampMutex);
// Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a
// callback for them.
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index ab6a6b7..f51390a 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -55,20 +55,20 @@
static_cast<uint32_t>(c4);
}
+enum class DisplayEventType : uint32_t {
+ DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
+ DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
+ DISPLAY_EVENT_MODE_CHANGE = fourcc('m', 'o', 'd', 'e'),
+ DISPLAY_EVENT_MODE_REJECTION = fourcc('r', 'e', 'j', 'e'),
+ DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
+ DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
+ DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
+ DISPLAY_EVENT_HDCP_LEVELS_CHANGE = fourcc('h', 'd', 'c', 'p'),
+};
+
// ----------------------------------------------------------------------------
class DisplayEventReceiver {
public:
- enum {
- DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
- DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
- DISPLAY_EVENT_MODE_CHANGE = fourcc('m', 'o', 'd', 'e'),
- DISPLAY_EVENT_MODE_REJECTION = fourcc('r', 'e', 'j', 'e'),
- DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
- DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
- DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
- DISPLAY_EVENT_HDCP_LEVELS_CHANGE = fourcc('h', 'd', 'c', 'p'),
- };
-
struct Event {
// We add __attribute__((aligned(8))) for nsecs_t fields because
// we need to make sure all fields are aligned the same with x86
@@ -77,7 +77,7 @@
// https://en.wikipedia.org/wiki/Data_structure_alignment
struct Header {
- uint32_t type;
+ DisplayEventType type;
PhysicalDisplayId displayId __attribute__((aligned(8)));
nsecs_t timestamp __attribute__((aligned(8)));
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 1002614..d04b861 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -232,7 +232,6 @@
ePictureProfileHandleChanged = 0x80000'00000000,
eAppContentPriorityChanged = 0x100000'00000000,
eClientDrawnCornerRadiusChanged = 0x200000'00000000,
- eClientDrawnShadowsChanged = 0x400000'00000000,
};
layer_state_t();
@@ -276,7 +275,7 @@
layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eColorTransformChanged |
layer_state_t::eCornerRadiusChanged | layer_state_t::eDimmingEnabledChanged |
layer_state_t::eHdrMetadataChanged | layer_state_t::eShadowRadiusChanged |
- layer_state_t::eClientDrawnShadowsChanged | layer_state_t::eStretchChanged |
+ layer_state_t::eStretchChanged |
layer_state_t::ePictureProfileHandleChanged | layer_state_t::eAppContentPriorityChanged;
// Changes which invalidates the layer's visible region in CE.
@@ -336,7 +335,6 @@
matrix22_t matrix;
float cornerRadius;
float clientDrawnCornerRadius;
- float clientDrawnShadowRadius;
uint32_t backgroundBlurRadius;
sp<SurfaceControl> relativeLayerSurfaceControl;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d30a830..10225cc 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -569,10 +569,6 @@
// radius is drawn by the client and not SurfaceFlinger.
Transaction& setClientDrawnCornerRadius(const sp<SurfaceControl>& sc,
float clientDrawnCornerRadius);
- // Sets the client drawn shadow radius for the layer. This indicates that the shadows
- // are drawn by the client and not SurfaceFlinger.
- Transaction& setClientDrawnShadowRadius(const sp<SurfaceControl>& sc,
- float clientDrawnShadowRadius);
Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
int backgroundBlurRadius);
Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index a0d8c53..c35efe2 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -40,7 +40,7 @@
std::unique_lock<decltype(mutex_)> lk(mutex_);
auto check_event = [](auto const& ev) -> bool {
- return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+ return ev.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC;
};
DisplayEventReceiver::Event ev_;
int evs = receiver_.getEvents(&ev_, 1);
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 4e187ed..5bb30db 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -255,3 +255,12 @@
bug: "277261245"
}
+flag {
+ name: "prevent_merging_input_pointer_devices"
+ namespace: "desktop_input"
+ description: "Prevent merging input sub-devices that provide pointer input streams"
+ bug: "389689566"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs
index 6eb2d73..35ba04f 100644
--- a/libs/input/rust/input.rs
+++ b/libs/input/rust/input.rs
@@ -50,7 +50,7 @@
bitflags! {
/// Source of the input device or input events.
- #[derive(Debug, PartialEq)]
+ #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Source: u32 {
// Constants from SourceClass, added here for compatibility reasons
/// SourceClass::Button
@@ -101,7 +101,7 @@
/// A rust enum representation of a MotionEvent action.
#[repr(u32)]
-#[derive(Eq, PartialEq)]
+#[derive(Clone, Copy, Eq, PartialEq)]
pub enum MotionAction {
/// ACTION_DOWN
Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN,
@@ -132,9 +132,15 @@
/// ACTION_SCROLL
Scroll = input_bindgen::AMOTION_EVENT_ACTION_SCROLL,
/// ACTION_BUTTON_PRESS
- ButtonPress = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ ButtonPress {
+ /// The button being pressed.
+ action_button: MotionButton,
+ } = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
/// ACTION_BUTTON_RELEASE
- ButtonRelease = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
+ ButtonRelease {
+ /// The button being released.
+ action_button: MotionButton,
+ } = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
}
impl fmt::Display for MotionAction {
@@ -153,14 +159,20 @@
MotionAction::Scroll => write!(f, "SCROLL"),
MotionAction::HoverEnter => write!(f, "HOVER_ENTER"),
MotionAction::HoverExit => write!(f, "HOVER_EXIT"),
- MotionAction::ButtonPress => write!(f, "BUTTON_PRESS"),
- MotionAction::ButtonRelease => write!(f, "BUTTON_RELEASE"),
+ MotionAction::ButtonPress { action_button } => {
+ write!(f, "BUTTON_PRESS({action_button:?})")
+ }
+ MotionAction::ButtonRelease { action_button } => {
+ write!(f, "BUTTON_RELEASE({action_button:?})")
+ }
}
}
}
-impl From<u32> for MotionAction {
- fn from(action: u32) -> Self {
+impl MotionAction {
+ /// Creates a [`MotionAction`] from an `AMOTION_EVENT_ACTION_…` constant and an action button
+ /// (which should be empty for all actions except `BUTTON_PRESS` and `…_RELEASE`).
+ pub fn from_code(action: u32, action_button: MotionButton) -> Self {
let (action_masked, action_index) = MotionAction::breakdown_action(action);
match action_masked {
input_bindgen::AMOTION_EVENT_ACTION_DOWN => MotionAction::Down,
@@ -178,14 +190,16 @@
input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE => MotionAction::HoverMove,
input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT => MotionAction::HoverExit,
input_bindgen::AMOTION_EVENT_ACTION_SCROLL => MotionAction::Scroll,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => MotionAction::ButtonPress,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => MotionAction::ButtonRelease,
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => {
+ MotionAction::ButtonPress { action_button }
+ }
+ input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => {
+ MotionAction::ButtonRelease { action_button }
+ }
_ => panic!("Unknown action: {}", action),
}
}
-}
-impl MotionAction {
fn breakdown_action(action: u32) -> (u32, usize) {
let action_masked = action & input_bindgen::AMOTION_EVENT_ACTION_MASK;
let index = (action & input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
@@ -219,7 +233,7 @@
/// 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)]
+ #[derive(Clone, Copy, Debug)]
pub struct MotionFlags: u32 {
/// FLAG_WINDOW_IS_OBSCURED
const WINDOW_IS_OBSCURED = MotionEventFlag::WINDOW_IS_OBSCURED.0 as u32;
diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs
index 6d94316..f87dd41 100644
--- a/libs/input/rust/input_verifier.rs
+++ b/libs/input/rust/input_verifier.rs
@@ -22,26 +22,50 @@
use std::collections::HashMap;
use std::collections::HashSet;
-fn verify_event(
- action: MotionAction,
- action_button: MotionButton,
- pointer_properties: &[RustPointerProperties],
- flags: &MotionFlags,
- verify_buttons: bool,
-) -> Result<(), String> {
- let pointer_count = pointer_properties.len();
+/// Represents a movement or state change event from a pointer device. The Rust equivalent of the
+/// C++ NotifyMotionArgs struct.
+#[derive(Clone, Copy)]
+pub struct NotifyMotionArgs<'a> {
+ /// The ID of the device that emitted the event.
+ pub device_id: DeviceId,
+
+ /// The type of device that emitted the event.
+ pub source: Source,
+
+ /// The type of event that took place.
+ pub action: MotionAction,
+
+ /// The properties of each of the pointers involved in the event.
+ pub pointer_properties: &'a [RustPointerProperties],
+
+ /// Flags applied to the event.
+ pub flags: MotionFlags,
+
+ /// The set of buttons that were pressed at the time of the event.
+ ///
+ /// We allow DOWN events to include buttons in their state for which BUTTON_PRESS events haven't
+ /// been sent yet. In that case, the DOWN should be immediately followed by BUTTON_PRESS events
+ /// for those buttons, building up to a button state matching that of the DOWN. For example, if
+ /// the user presses the primary and secondary buttons at exactly the same time, we'd expect
+ /// this sequence:
+ ///
+ /// | Action | Action button | Button state |
+ /// |----------------|---------------|------------------------|
+ /// | `HOVER_EXIT` | - | - |
+ /// | `DOWN` | - | `PRIMARY`, `SECONDARY` |
+ /// | `BUTTON_PRESS` | `PRIMARY` | `PRIMARY` |
+ /// | `BUTTON_PRESS` | `SECONDARY` | `PRIMARY`, `SECONDARY` |
+ /// | `MOVE` | - | `PRIMARY`, `SECONDARY` |
+ pub button_state: MotionButton,
+}
+
+/// Verifies the properties of an event that should always be true, regardless of the current state.
+fn verify_event(event: NotifyMotionArgs<'_>, verify_buttons: bool) -> Result<(), String> {
+ let pointer_count = event.pointer_properties.len();
if pointer_count < 1 {
- return Err(format!("Invalid {} event: no pointers", action));
+ return Err(format!("Invalid {} event: no pointers", event.action));
}
- if action_button != MotionButton::empty()
- && action != MotionAction::ButtonPress
- && action != MotionAction::ButtonRelease
- {
- return Err(format!(
- "Invalid {action} event: has action button {action_button:?} but is not a button action"
- ));
- }
- match action {
+ match event.action {
MotionAction::Down
| MotionAction::HoverEnter
| MotionAction::HoverExit
@@ -49,32 +73,39 @@
| MotionAction::Up => {
if pointer_count != 1 {
return Err(format!(
- "Invalid {action} event: there are {pointer_count} pointers in the event",
+ "Invalid {} event: there are {} pointers in the event",
+ event.action, pointer_count
));
}
}
MotionAction::Cancel => {
- if !flags.contains(MotionFlags::CANCELED) {
+ if !event.flags.contains(MotionFlags::CANCELED) {
return Err(format!(
- "For ACTION_CANCEL, must set FLAG_CANCELED. Received flags: {flags:#?}",
+ "For ACTION_CANCEL, must set FLAG_CANCELED. Received flags: {:#?}",
+ event.flags
));
}
}
MotionAction::PointerDown { action_index } | MotionAction::PointerUp { action_index } => {
if action_index >= pointer_count {
- return Err(format!("Got {action}, but event has {pointer_count} pointer(s)"));
+ return Err(format!(
+ "Got {}, but event has {} pointer(s)",
+ event.action, pointer_count
+ ));
}
}
- MotionAction::ButtonPress | MotionAction::ButtonRelease => {
+ MotionAction::ButtonPress { action_button }
+ | MotionAction::ButtonRelease { action_button } => {
if verify_buttons {
let button_count = action_button.iter().count();
if button_count != 1 {
return Err(format!(
- "Invalid {action} event: must specify a single action button, not \
- {button_count} action buttons"
+ "Invalid {} event: must specify a single action button, not {} action \
+ buttons",
+ event.action, button_count
));
}
}
@@ -92,59 +123,43 @@
button_state: MotionButton,
/// The set of "pending buttons", which were seen in the last DOWN event's button state but
- /// for which we haven't seen BUTTON_PRESS events yet.
- ///
- /// We allow DOWN events to include buttons in their state for which BUTTON_PRESS events haven't
- /// been sent yet. In that case, the DOWN should be immediately followed by BUTTON_PRESS events
- /// for those buttons, building up to a button state matching that of the DOWN. For example, if
- /// the user presses the primary and secondary buttons at exactly the same time, we'd expect
- /// this sequence:
- ///
- /// | Action | Action button | Button state |
- /// |----------------|---------------|------------------------|
- /// | `HOVER_EXIT` | - | - |
- /// | `DOWN` | - | `PRIMARY`, `SECONDARY` |
- /// | `BUTTON_PRESS` | `PRIMARY` | `PRIMARY` |
- /// | `BUTTON_PRESS` | `SECONDARY` | `PRIMARY`, `SECONDARY` |
- /// | `MOVE` | - | `PRIMARY`, `SECONDARY` |
+ /// for which we haven't seen BUTTON_PRESS events yet (see [`NotifyMotionArgs::button_state`]).
pending_buttons: MotionButton,
}
impl ButtonVerifier {
- pub fn process_action(
- &mut self,
- action: MotionAction,
- action_button: MotionButton,
- button_state: MotionButton,
- ) -> Result<(), String> {
+ pub fn process_event(&mut self, event: NotifyMotionArgs<'_>) -> Result<(), String> {
if !self.pending_buttons.is_empty() {
// We just saw a DOWN with some additional buttons in its state, so it should be
// immediately followed by ButtonPress events for those buttons.
- if action != MotionAction::ButtonPress || !self.pending_buttons.contains(action_button)
- {
- return Err(format!(
- "After DOWN event, expected BUTTON_PRESS event(s) for {:?}, but got {} with \
- action button {:?}",
- self.pending_buttons, action, action_button
- ));
- } else {
- self.pending_buttons -= action_button;
- }
- }
- let expected_state = match action {
- MotionAction::Down => {
- if self.button_state - button_state != MotionButton::empty() {
+ match event.action {
+ MotionAction::ButtonPress { action_button }
+ if self.pending_buttons.contains(action_button) =>
+ {
+ self.pending_buttons -= action_button;
+ }
+ _ => {
return Err(format!(
- "DOWN event button state is missing {:?}",
- self.button_state - button_state
+ "After DOWN event, expected BUTTON_PRESS event(s) for {:?}, but got {}",
+ self.pending_buttons, event.action
));
}
- self.pending_buttons = button_state - self.button_state;
+ }
+ }
+ let expected_state = match event.action {
+ MotionAction::Down => {
+ if self.button_state - event.button_state != MotionButton::empty() {
+ return Err(format!(
+ "DOWN event button state is missing {:?}",
+ self.button_state - event.button_state
+ ));
+ }
+ self.pending_buttons = event.button_state - self.button_state;
// We've already checked that the state isn't missing any already-down buttons, and
// extra buttons are valid on DOWN actions, so bypass the expected state check.
- button_state
+ event.button_state
}
- MotionAction::ButtonPress => {
+ MotionAction::ButtonPress { action_button } => {
if self.button_state.contains(action_button) {
return Err(format!(
"Duplicate BUTTON_PRESS; button state already contains {action_button:?}"
@@ -152,24 +167,25 @@
}
self.button_state | action_button
}
- MotionAction::ButtonRelease => {
+ MotionAction::ButtonRelease { action_button } => {
if !self.button_state.contains(action_button) {
return Err(format!(
- "Invalid BUTTON_RELEASE; button state doesn't contain {action_button:?}"
+ "Invalid BUTTON_RELEASE; button state doesn't contain {action_button:?}",
));
}
self.button_state - action_button
}
_ => self.button_state,
};
- if button_state != expected_state {
+ if event.button_state != expected_state {
return Err(format!(
- "Expected {action} button state to be {expected_state:?}, but was {button_state:?}"
+ "Expected {} button state to be {:?}, but was {:?}",
+ event.action, expected_state, event.button_state
));
}
// DOWN events can have pending buttons, so don't update the state for them.
- if action != MotionAction::Down {
- self.button_state = button_state;
+ if event.action != MotionAction::Down {
+ self.button_state = event.button_state;
}
Ok(())
}
@@ -205,78 +221,61 @@
/// Process a pointer movement event from an InputDevice.
/// If the event is not valid, we return an error string that describes the issue.
- #[allow(clippy::too_many_arguments)]
- pub fn process_movement(
- &mut self,
- device_id: DeviceId,
- source: Source,
- action: u32,
- action_button: MotionButton,
- pointer_properties: &[RustPointerProperties],
- flags: MotionFlags,
- button_state: MotionButton,
- ) -> Result<(), String> {
- if !source.is_from_class(SourceClass::Pointer) {
+ pub fn process_movement(&mut self, event: NotifyMotionArgs<'_>) -> Result<(), String> {
+ if !event.source.is_from_class(SourceClass::Pointer) {
// Skip non-pointer sources like MOUSE_RELATIVE for now
return Ok(());
}
if self.should_log {
info!(
"Processing {} for device {:?} ({} pointer{}) on {}",
- MotionAction::from(action).to_string(),
- device_id,
- pointer_properties.len(),
- if pointer_properties.len() == 1 { "" } else { "s" },
+ event.action,
+ event.device_id,
+ event.pointer_properties.len(),
+ if event.pointer_properties.len() == 1 { "" } else { "s" },
self.name
);
}
- verify_event(
- action.into(),
- action_button,
- pointer_properties,
- &flags,
- self.verify_buttons,
- )?;
+ verify_event(event, self.verify_buttons)?;
if self.verify_buttons {
- self.button_verifier_by_device.entry(device_id).or_default().process_action(
- action.into(),
- action_button,
- button_state,
- )?;
+ self.button_verifier_by_device
+ .entry(event.device_id)
+ .or_default()
+ .process_event(event)?;
}
- match action.into() {
+ match event.action {
MotionAction::Down => {
- if self.touching_pointer_ids_by_device.contains_key(&device_id) {
+ if self.touching_pointer_ids_by_device.contains_key(&event.device_id) {
return Err(format!(
"{}: Invalid DOWN event - pointers already down for device {:?}: {:?}",
- self.name, device_id, self.touching_pointer_ids_by_device
+ self.name, event.device_id, self.touching_pointer_ids_by_device
));
}
- let it = self.touching_pointer_ids_by_device.entry(device_id).or_default();
- it.insert(pointer_properties[0].id);
+ let it = self.touching_pointer_ids_by_device.entry(event.device_id).or_default();
+ it.insert(event.pointer_properties[0].id);
}
MotionAction::PointerDown { action_index } => {
- if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
+ if !self.touching_pointer_ids_by_device.contains_key(&event.device_id) {
return Err(format!(
"{}: Received POINTER_DOWN but no pointers are currently down \
for device {:?}",
- self.name, device_id
+ self.name, event.device_id
));
}
- let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
- if it.len() != pointer_properties.len() - 1 {
+ let it = self.touching_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
+ if it.len() != event.pointer_properties.len() - 1 {
return Err(format!(
"{}: There are currently {} touching pointers, but the incoming \
POINTER_DOWN event has {}",
self.name,
it.len(),
- pointer_properties.len()
+ event.pointer_properties.len()
));
}
- let pointer_id = pointer_properties[action_index].id;
+ let pointer_id = event.pointer_properties[action_index].id;
if it.contains(&pointer_id) {
return Err(format!(
"{}: Pointer with id={} already present found in the properties",
@@ -286,7 +285,7 @@
it.insert(pointer_id);
}
MotionAction::Move => {
- if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
+ if !self.ensure_touching_pointers_match(event.device_id, event.pointer_properties) {
return Err(format!(
"{}: ACTION_MOVE touching pointers don't match",
self.name
@@ -294,49 +293,49 @@
}
}
MotionAction::PointerUp { action_index } => {
- if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
+ if !self.ensure_touching_pointers_match(event.device_id, event.pointer_properties) {
return Err(format!(
"{}: ACTION_POINTER_UP touching pointers don't match",
self.name
));
}
- let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
- let pointer_id = pointer_properties[action_index].id;
+ let it = self.touching_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
+ let pointer_id = event.pointer_properties[action_index].id;
it.remove(&pointer_id);
}
MotionAction::Up => {
- if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
+ if !self.touching_pointer_ids_by_device.contains_key(&event.device_id) {
return Err(format!(
"{} Received ACTION_UP but no pointers are currently down for device {:?}",
- self.name, device_id
+ self.name, event.device_id
));
}
- let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
+ let it = self.touching_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
if it.len() != 1 {
return Err(format!(
"{}: Got ACTION_UP, but we have pointers: {:?} for device {:?}",
- self.name, it, device_id
+ self.name, it, event.device_id
));
}
- let pointer_id = pointer_properties[0].id;
+ let pointer_id = event.pointer_properties[0].id;
if !it.contains(&pointer_id) {
return Err(format!(
"{}: Got ACTION_UP, but pointerId {} is not touching. Touching pointers:\
{:?} for device {:?}",
- self.name, pointer_id, it, device_id
+ self.name, pointer_id, it, event.device_id
));
}
- self.touching_pointer_ids_by_device.remove(&device_id);
+ self.touching_pointer_ids_by_device.remove(&event.device_id);
}
MotionAction::Cancel => {
- if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
+ if !self.ensure_touching_pointers_match(event.device_id, event.pointer_properties) {
return Err(format!(
"{}: Got ACTION_CANCEL, but the pointers don't match. \
Existing pointers: {:?}",
self.name, self.touching_pointer_ids_by_device
));
}
- self.touching_pointer_ids_by_device.remove(&device_id);
+ self.touching_pointer_ids_by_device.remove(&event.device_id);
}
/*
* The hovering protocol currently supports a single pointer only, because we do not
@@ -345,41 +344,41 @@
* eventually supported.
*/
MotionAction::HoverEnter => {
- if self.hovering_pointer_ids_by_device.contains_key(&device_id) {
+ if self.hovering_pointer_ids_by_device.contains_key(&event.device_id) {
return Err(format!(
"{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\
{:?}",
- self.name, device_id, self.hovering_pointer_ids_by_device
+ self.name, event.device_id, self.hovering_pointer_ids_by_device
));
}
- let it = self.hovering_pointer_ids_by_device.entry(device_id).or_default();
- it.insert(pointer_properties[0].id);
+ let it = self.hovering_pointer_ids_by_device.entry(event.device_id).or_default();
+ it.insert(event.pointer_properties[0].id);
}
MotionAction::HoverMove => {
// For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER.
// If there was no prior HOVER_ENTER, just start a new hovering pointer.
- let it = self.hovering_pointer_ids_by_device.entry(device_id).or_default();
- it.insert(pointer_properties[0].id);
+ let it = self.hovering_pointer_ids_by_device.entry(event.device_id).or_default();
+ it.insert(event.pointer_properties[0].id);
}
MotionAction::HoverExit => {
- if !self.hovering_pointer_ids_by_device.contains_key(&device_id) {
+ if !self.hovering_pointer_ids_by_device.contains_key(&event.device_id) {
return Err(format!(
"{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}",
- self.name, device_id
+ self.name, event.device_id
));
}
- let pointer_id = pointer_properties[0].id;
- let it = self.hovering_pointer_ids_by_device.get_mut(&device_id).unwrap();
+ let pointer_id = event.pointer_properties[0].id;
+ let it = self.hovering_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
it.remove(&pointer_id);
if !it.is_empty() {
return Err(format!(
"{}: Removed hovering pointer {}, but pointers are still\
hovering for device {:?}: {:?}",
- self.name, pointer_id, device_id, it
+ self.name, pointer_id, event.device_id, it
));
}
- self.hovering_pointer_ids_by_device.remove(&device_id);
+ self.hovering_pointer_ids_by_device.remove(&event.device_id);
}
_ => return Ok(()),
}
@@ -421,11 +420,25 @@
mod tests {
use crate::input::MotionButton;
use crate::input_verifier::InputVerifier;
+ use crate::input_verifier::NotifyMotionArgs;
use crate::DeviceId;
+ use crate::MotionAction;
use crate::MotionFlags;
use crate::RustPointerProperties;
use crate::Source;
+ const BASE_POINTER_PROPERTIES: [RustPointerProperties; 1] = [RustPointerProperties { id: 0 }];
+ const BASE_EVENT: NotifyMotionArgs = NotifyMotionArgs {
+ device_id: DeviceId(1),
+ source: Source::Touchscreen,
+ action: MotionAction::Down,
+ pointer_properties: &BASE_POINTER_PROPERTIES,
+ flags: MotionFlags::empty(),
+ button_state: MotionButton::empty(),
+ };
+ const BASE_MOUSE_EVENT: NotifyMotionArgs =
+ NotifyMotionArgs { source: Source::Mouse, ..BASE_EVENT };
+
#[test]
/**
* Send a DOWN event with 2 pointers and ensure that it's marked as invalid.
@@ -436,15 +449,11 @@
let pointer_properties =
Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ pointer_properties: &pointer_properties,
+ ..BASE_EVENT
+ })
.is_err());
}
@@ -454,37 +463,25 @@
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ pointer_properties: &pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Move,
+ pointer_properties: &pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_UP,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Up,
+ pointer_properties: &pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
}
@@ -494,56 +491,38 @@
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ pointer_properties: &pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
// POINTER 1 DOWN
let two_pointer_properties =
Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
- | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- MotionButton::empty(),
- &two_pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::PointerDown { action_index: 1 },
+ pointer_properties: &two_pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
// POINTER 0 UP
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP
- | (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- MotionButton::empty(),
- &two_pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::PointerUp { action_index: 0 },
+ pointer_properties: &two_pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
// ACTION_UP for pointer id=1
let pointer_1_properties = Vec::from([RustPointerProperties { id: 1 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_UP,
- MotionButton::empty(),
- &pointer_1_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Up,
+ pointer_properties: &pointer_1_properties,
+ ..BASE_EVENT
+ })
.is_ok());
}
@@ -551,61 +530,40 @@
fn multi_device_stream() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ device_id: DeviceId(1),
+ action: MotionAction::Down,
+ ..BASE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ device_id: DeviceId(1),
+ action: MotionAction::Move,
+ ..BASE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(2),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ device_id: DeviceId(2),
+ action: MotionAction::Down,
+ ..BASE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(2),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ device_id: DeviceId(2),
+ action: MotionAction::Move,
+ ..BASE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_UP,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ device_id: DeviceId(1),
+ action: MotionAction::Up,
+ ..BASE_EVENT
+ })
.is_ok());
}
@@ -613,28 +571,19 @@
fn action_cancel() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ flags: MotionFlags::empty(),
+ ..BASE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::CANCELED,
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Cancel,
+ flags: MotionFlags::CANCELED,
+ ..BASE_EVENT
+ })
.is_ok());
}
@@ -642,28 +591,11 @@
fn invalid_action_cancel() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::Down, ..BASE_EVENT })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(), // forgot to set FLAG_CANCELED
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::Cancel, ..BASE_EVENT })
.is_err());
}
@@ -671,17 +603,8 @@
fn invalid_up() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_UP,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::Up, ..BASE_EVENT })
.is_err());
}
@@ -689,53 +612,20 @@
fn correct_hover_sequence() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::HoverMove, ..BASE_EVENT })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::HoverExit, ..BASE_EVENT })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
.is_ok());
}
@@ -743,29 +633,12 @@
fn double_hover_enter() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
.is_err());
}
@@ -775,17 +648,13 @@
fn relative_mouse_move() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(2),
- Source::MouseRelative,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ device_id: DeviceId(2),
+ source: Source::MouseRelative,
+ action: MotionAction::Move,
+ ..BASE_EVENT
+ })
.is_ok());
}
@@ -796,42 +665,29 @@
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ pointer_properties: &pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
// POINTER 1 DOWN
let two_pointer_properties =
Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
- | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- MotionButton::empty(),
- &two_pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::PointerDown { action_index: 1 },
+ pointer_properties: &two_pointer_properties,
+ ..BASE_EVENT
+ })
.is_ok());
// MOVE event with 1 pointer missing (the pointer with id = 1). It should be rejected
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Touchscreen,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Move,
+ pointer_properties: &pointer_properties,
+ ..BASE_EVENT
+ })
.is_err());
}
@@ -839,17 +695,12 @@
fn correct_button_press() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
}
@@ -857,17 +708,12 @@
fn button_press_without_action_button() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::empty() },
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -875,17 +721,14 @@
fn button_press_with_multiple_action_buttons() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Back | MotionButton::Forward,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back | MotionButton::Forward,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress {
+ action_button: MotionButton::Back | MotionButton::Forward
+ },
+ button_state: MotionButton::Back | MotionButton::Forward,
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -893,17 +736,12 @@
fn button_press_without_action_button_in_state() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -911,64 +749,19 @@
fn button_release_with_action_button_in_state() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
- .is_err());
- }
-
- #[test]
- fn nonbutton_action_with_action_button() {
- let mut verifier =
- InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
- assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
- .is_err());
- }
-
- #[test]
- fn nonbutton_action_with_action_button_and_state() {
- let mut verifier =
- InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
- assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonRelease { action_button: MotionButton::Primary },
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -976,28 +769,19 @@
fn nonbutton_action_with_button_state_change() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::HoverEnter,
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::HoverMove,
+ button_state: MotionButton::Back,
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -1005,39 +789,26 @@
fn nonbutton_action_missing_button_state() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::HoverEnter,
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Back,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Back },
+ button_state: MotionButton::Back,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::HoverMove,
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -1045,40 +816,27 @@
fn up_without_button_release() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
// This UP event shouldn't change the button state; a BUTTON_RELEASE before it should.
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_UP,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Up,
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -1086,28 +844,19 @@
fn button_press_for_already_pressed_button() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Back,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Back },
+ button_state: MotionButton::Back,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Back,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Back },
+ button_state: MotionButton::Back,
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -1115,17 +864,12 @@
fn button_release_for_unpressed_button() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
- MotionButton::Back,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonRelease { action_button: MotionButton::Back },
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -1133,28 +877,19 @@
fn correct_multiple_button_presses_without_down() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Back,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Back },
+ button_state: MotionButton::Back,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Forward,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back | MotionButton::Forward,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Forward },
+ button_state: MotionButton::Back | MotionButton::Forward,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
}
@@ -1162,52 +897,35 @@
fn correct_down_with_button_press() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary | MotionButton::Secondary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ button_state: MotionButton::Primary | MotionButton::Secondary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Secondary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary | MotionButton::Secondary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Secondary },
+ button_state: MotionButton::Primary | MotionButton::Secondary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
// Also check that the MOVE afterwards is OK, as that's where errors would be raised if not
// enough BUTTON_PRESSes were sent.
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary | MotionButton::Secondary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Move,
+ button_state: MotionButton::Primary | MotionButton::Secondary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
}
@@ -1215,29 +933,20 @@
fn down_with_button_state_change_not_followed_by_button_press() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
// The DOWN event itself is OK, but it needs to be immediately followed by a BUTTON_PRESS.
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Move,
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -1245,41 +954,28 @@
fn down_with_button_state_change_not_followed_by_enough_button_presses() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary | MotionButton::Secondary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ button_state: MotionButton::Primary | MotionButton::Secondary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
// The DOWN event itself is OK, but it needs to be immediately followed by two
// BUTTON_PRESSes, one for each button.
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Primary,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_MOVE,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Primary,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Move,
+ button_state: MotionButton::Primary,
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
@@ -1287,28 +983,19 @@
fn down_missing_already_pressed_button() {
let mut verifier =
InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
- let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS,
- MotionButton::Back,
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::Back,
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::ButtonPress { action_button: MotionButton::Back },
+ button_state: MotionButton::Back,
+ ..BASE_MOUSE_EVENT
+ })
.is_ok());
assert!(verifier
- .process_movement(
- DeviceId(1),
- Source::Mouse,
- input_bindgen::AMOTION_EVENT_ACTION_DOWN,
- MotionButton::empty(),
- &pointer_properties,
- MotionFlags::empty(),
- MotionButton::empty(),
- )
+ .process_movement(NotifyMotionArgs {
+ action: MotionAction::Down,
+ button_state: MotionButton::empty(),
+ ..BASE_MOUSE_EVENT
+ })
.is_err());
}
}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 6db4356..7638559 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -27,7 +27,7 @@
DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionButton,
MotionFlags, Source,
};
-pub use input_verifier::InputVerifier;
+pub use input_verifier::{InputVerifier, NotifyMotionArgs};
pub use keyboard_classifier::KeyboardClassifier;
#[cxx::bridge(namespace = "android::input")]
@@ -133,37 +133,46 @@
flags: u32,
button_state: u32,
) -> String {
- let motion_flags = MotionFlags::from_bits(flags);
- if motion_flags.is_none() {
+ let Some(motion_flags) = MotionFlags::from_bits(flags) else {
panic!(
"The conversion of flags 0x{:08x} failed, please check if some flags have not been \
added to MotionFlags.",
flags
);
- }
- let motion_action_button = MotionButton::from_bits(action_button);
- if motion_action_button.is_none() {
+ };
+ let Some(motion_action_button) = MotionButton::from_bits(action_button) else {
panic!(
"The conversion of action button 0x{action_button:08x} failed, please check if some \
buttons need to be added to MotionButton."
);
- }
- let motion_button_state = MotionButton::from_bits(button_state);
- if motion_button_state.is_none() {
+ };
+ let Some(motion_button_state) = MotionButton::from_bits(button_state) else {
panic!(
"The conversion of button state 0x{button_state:08x} failed, please check if some \
buttons need to be added to MotionButton."
);
+ };
+ let motion_action = MotionAction::from_code(action, motion_action_button);
+ if motion_action_button != MotionButton::empty() {
+ match motion_action {
+ MotionAction::ButtonPress { action_button: _ }
+ | MotionAction::ButtonRelease { action_button: _ } => {}
+ _ => {
+ return format!(
+ "Invalid {motion_action} event: has action button {motion_action_button:?} but \
+ is not a button action"
+ );
+ }
+ }
}
- let result = verifier.process_movement(
- DeviceId(device_id),
- Source::from_bits(source).unwrap(),
- action,
- motion_action_button.unwrap(),
+ let result = verifier.process_movement(NotifyMotionArgs {
+ device_id: DeviceId(device_id),
+ source: Source::from_bits(source).unwrap(),
+ action: motion_action,
pointer_properties,
- motion_flags.unwrap(),
- motion_button_state.unwrap(),
- );
+ flags: motion_flags,
+ button_state: motion_button_state,
+ });
match result {
Ok(()) => "".to_string(),
Err(e) => e,
@@ -230,3 +239,44 @@
}
classifier.process_key(DeviceId(device_id), evdev_code, modifier_state.unwrap());
}
+
+#[cfg(test)]
+mod tests {
+ use crate::create_input_verifier;
+ use crate::process_movement;
+ use crate::RustPointerProperties;
+
+ const BASE_POINTER_PROPERTIES: [RustPointerProperties; 1] = [RustPointerProperties { id: 0 }];
+
+ #[test]
+ fn verify_nonbutton_action_with_action_button() {
+ let mut verifier = create_input_verifier("Test".to_string(), /*verify_buttons*/ true);
+ assert!(process_movement(
+ &mut verifier,
+ 1,
+ input_bindgen::AINPUT_SOURCE_MOUSE,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY,
+ &BASE_POINTER_PROPERTIES,
+ 0,
+ 0,
+ )
+ .contains("button action"));
+ }
+
+ #[test]
+ fn verify_nonbutton_action_with_action_button_and_button_state() {
+ let mut verifier = create_input_verifier("Test".to_string(), /*verify_buttons*/ true);
+ assert!(process_movement(
+ &mut verifier,
+ 1,
+ input_bindgen::AINPUT_SOURCE_MOUSE,
+ input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
+ input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY,
+ &BASE_POINTER_PROPERTIES,
+ 0,
+ input_bindgen::AMOTION_EVENT_BUTTON_PRIMARY,
+ )
+ .contains("button action"));
+ }
+}
diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp
index 0eeca54..929f067 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -16,6 +16,7 @@
double_loadable: true,
srcs: [
"aidl/android/content/AttributionSourceState.aidl",
+ "aidl/com/android/internal/app/IAppOpsCallback.aidl",
"aidl/android/permission/IPermissionChecker.aidl",
],
}
@@ -36,7 +37,6 @@
],
srcs: [
"AppOpsManager.cpp",
- "IAppOpsCallback.cpp",
"IAppOpsService.cpp",
"android/permission/PermissionChecker.cpp",
],
diff --git a/libs/permission/IAppOpsCallback.cpp b/libs/permission/IAppOpsCallback.cpp
deleted file mode 100644
index 2b3f462..0000000
--- a/libs/permission/IAppOpsCallback.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AppOpsCallback"
-
-#include <binder/IAppOpsCallback.h>
-
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-#include <utils/String8.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpAppOpsCallback : public BpInterface<IAppOpsCallback>
-{
-public:
- explicit BpAppOpsCallback(const sp<IBinder>& impl)
- : BpInterface<IAppOpsCallback>(impl)
- {
- }
-
- virtual void opChanged(int32_t op, const String16& packageName) {
- Parcel data, reply;
- data.writeInterfaceToken(IAppOpsCallback::getInterfaceDescriptor());
- data.writeInt32(op);
- data.writeString16(packageName);
- remote()->transact(OP_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback")
-
-// ----------------------------------------------------------------------
-
-// NOLINTNEXTLINE(google-default-arguments)
-status_t BnAppOpsCallback::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case OP_CHANGED_TRANSACTION: {
- CHECK_INTERFACE(IAppOpsCallback, data, reply);
- int32_t op = data.readInt32();
- String16 packageName;
- (void)data.readString16(&packageName);
- opChanged(op, packageName);
- return NO_ERROR;
- } break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-} // namespace android
diff --git a/libs/permission/aidl/com/android/internal/app/IAppOpsCallback.aidl b/libs/permission/aidl/com/android/internal/app/IAppOpsCallback.aidl
new file mode 100644
index 0000000..36b19df
--- /dev/null
+++ b/libs/permission/aidl/com/android/internal/app/IAppOpsCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2025 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 com.android.internal.app;
+
+oneway interface IAppOpsCallback {
+ void opChanged(int op, int uid, String packageName, String persistentDeviceId);
+}
diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index 7e179d6..a22c975 100644
--- a/libs/permission/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
@@ -180,10 +180,10 @@
void finishOp(int32_t op, int32_t uid, const String16& callingPackage,
const std::optional<String16>& attributionTag);
void startWatchingMode(int32_t op, const String16& packageName,
- const sp<IAppOpsCallback>& callback);
+ const sp<com::android::internal::app::IAppOpsCallback>& callback);
void startWatchingMode(int32_t op, const String16& packageName, int32_t flags,
- const sp<IAppOpsCallback>& callback);
- void stopWatchingMode(const sp<IAppOpsCallback>& callback);
+ const sp<com::android::internal::app::IAppOpsCallback>& callback);
+ void stopWatchingMode(const sp<com::android::internal::app::IAppOpsCallback>& callback);
int32_t permissionToOpCode(const String16& permission);
void setCameraAudioRestriction(int32_t mode);
diff --git a/libs/permission/include/binder/IAppOpsCallback.h b/libs/permission/include/binder/IAppOpsCallback.h
deleted file mode 100644
index eb76f57..0000000
--- a/libs/permission/include/binder/IAppOpsCallback.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifndef __ANDROID_VNDK__
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IAppOpsCallback : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(AppOpsCallback)
-
- virtual void opChanged(int32_t op, const String16& packageName) = 0;
-
- enum {
- OP_CHANGED_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
- };
-};
-
-// ----------------------------------------------------------------------
-
-class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
-{
-public:
- // NOLINTNEXTLINE(google-default-arguments)
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-} // namespace android
-
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
diff --git a/libs/permission/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h
index 918fcdb..1468fd9 100644
--- a/libs/permission/include/binder/IAppOpsService.h
+++ b/libs/permission/include/binder/IAppOpsService.h
@@ -16,7 +16,8 @@
#pragma once
-#include <binder/IAppOpsCallback.h>
+#include <com/android/internal/app/IAppOpsCallback.h>
+#include <com/android/internal/app/BnAppOpsCallback.h>
#include <binder/IInterface.h>
#include <optional>
@@ -27,6 +28,8 @@
namespace android {
+using IAppOpsCallback = ::com::android::internal::app::IAppOpsCallback;
+
// ----------------------------------------------------------------------
class IAppOpsService : public IInterface
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 17ab29f..e296283 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -7,4 +7,3 @@
lpy@google.com
nscobie@google.com
sallyqi@google.com
-scroggo@google.com
diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
index 897f5cf..ff96b08 100644
--- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
@@ -39,12 +39,36 @@
namespace skia {
KawaseBlurDualFilter::KawaseBlurDualFilter() : BlurFilter() {
- // A shader to sample each vertex of a unit regular heptagon
- // plus the original fragment coordinate.
- SkString blurString(R"(
+ // A shader to sample each vertex of a square, plus the original fragment coordinate,
+ // using a total of 5 samples.
+ SkString lowSampleBlurString(R"(
uniform shader child;
uniform float in_blurOffset;
uniform float in_crossFade;
+ uniform float in_weightedCrossFade;
+
+ const float2 STEP_0 = float2( 0.707106781, 0.707106781);
+ const float2 STEP_1 = float2( 0.707106781, -0.707106781);
+ const float2 STEP_2 = float2(-0.707106781, -0.707106781);
+ const float2 STEP_3 = float2(-0.707106781, 0.707106781);
+
+ half4 main(float2 xy) {
+ half3 c = child.eval(xy).rgb;
+
+ c += child.eval(xy + STEP_0 * in_blurOffset).rgb;
+ c += child.eval(xy + STEP_1 * in_blurOffset).rgb;
+ c += child.eval(xy + STEP_2 * in_blurOffset).rgb;
+ c += child.eval(xy + STEP_3 * in_blurOffset).rgb;
+
+ return half4(c * in_weightedCrossFade, in_crossFade);
+ }
+ )");
+
+ // A shader to sample each vertex of a unit regular heptagon, plus the original fragment
+ // coordinate, using a total of 8 samples.
+ SkString highSampleBlurString(R"(
+ uniform shader child;
+ uniform float in_blurOffset;
const float2 STEP_0 = float2( 1.0, 0.0);
const float2 STEP_1 = float2( 0.623489802, 0.781831482);
@@ -65,39 +89,46 @@
c += child.eval(xy + STEP_5 * in_blurOffset).rgb;
c += child.eval(xy + STEP_6 * in_blurOffset).rgb;
- return half4(c * 0.125 * in_crossFade, in_crossFade);
+ return half4(c * 0.125, 1.0);
}
)");
- auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
- LOG_ALWAYS_FATAL_IF(!blurEffect, "RuntimeShader error: %s", error.c_str());
- mBlurEffect = std::move(blurEffect);
+ auto [lowSampleBlurEffect, error] = SkRuntimeEffect::MakeForShader(lowSampleBlurString);
+ auto [highSampleBlurEffect, error2] = SkRuntimeEffect::MakeForShader(highSampleBlurString);
+ LOG_ALWAYS_FATAL_IF(!lowSampleBlurEffect, "RuntimeShader error: %s", error.c_str());
+ LOG_ALWAYS_FATAL_IF(!highSampleBlurEffect, "RuntimeShader error: %s", error2.c_str());
+ mLowSampleBlurEffect = std::move(lowSampleBlurEffect);
+ mHighSampleBlurEffect = std::move(highSampleBlurEffect);
}
void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface,
const sk_sp<SkImage>& readImage, const float radius,
- const float alpha) const {
+ const float alpha,
+ const sk_sp<SkRuntimeEffect>& blurEffect) const {
const float scale = static_cast<float>(drawSurface->width()) / readImage->width();
SkMatrix blurMatrix = SkMatrix::Scale(scale, scale);
blurInto(drawSurface,
readImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
blurMatrix),
- readImage->width() / static_cast<float>(drawSurface->width()), radius, alpha);
+ radius, alpha, blurEffect);
}
void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface, sk_sp<SkShader> input,
- const float inverseScale, const float radius,
- const float alpha) const {
+ const float radius, const float alpha,
+ const sk_sp<SkRuntimeEffect>& blurEffect) const {
SkPaint paint;
if (radius == 0) {
paint.setShader(std::move(input));
paint.setAlphaf(alpha);
} else {
- SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
+ SkRuntimeShaderBuilder blurBuilder(blurEffect);
blurBuilder.child("child") = std::move(input);
+ if (blurEffect == mLowSampleBlurEffect) {
+ blurBuilder.uniform("in_crossFade") = alpha;
+ blurBuilder.uniform("in_weightedCrossFade") = alpha * 0.2f;
+ }
blurBuilder.uniform("in_blurOffset") = radius;
- blurBuilder.uniform("in_crossFade") = alpha;
paint.setShader(blurBuilder.makeShader(nullptr));
}
paint.setBlendMode(alpha == 1.0f ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
@@ -163,16 +194,19 @@
input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
blurMatrix);
- blurInto(surfaces[0], std::move(sourceShader), kInputScale, kWeights[0] * step, 1.0f);
+ blurInto(surfaces[0], std::move(sourceShader), kWeights[0] * step, 1.0f,
+ mLowSampleBlurEffect);
}
// Next the remaining downscale blur passes.
for (int i = 0; i < filterPasses; i++) {
- blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f);
+ // Blur with the higher sample effect into the smaller buffers, for better visual quality.
+ blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f,
+ i == 0 ? mLowSampleBlurEffect : mHighSampleBlurEffect);
}
// Finally blur+upscale back to our original size.
for (int i = filterPasses - 1; i >= 0; i--) {
blurInto(surfaces[i], surfaces[i + 1]->makeTemporaryImage(), kWeights[4 - i] * step,
- std::min(1.0f, filterDepth - i));
+ std::min(1.0f, filterDepth - i), mLowSampleBlurEffect);
}
return surfaces[0]->makeTemporaryImage();
}
diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
index 6f4adbf..5efda35 100644
--- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
+++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
@@ -41,13 +41,14 @@
const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override;
private:
- sk_sp<SkRuntimeEffect> mBlurEffect;
+ sk_sp<SkRuntimeEffect> mLowSampleBlurEffect;
+ sk_sp<SkRuntimeEffect> mHighSampleBlurEffect;
void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkImage>& readImage,
- const float radius, const float alpha) const;
+ const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;
void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkShader> input,
- const float inverseScale, const float radius, const float alpha) const;
+ const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;
};
} // namespace skia
diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp
index 10218bb..f262158 100644
--- a/libs/renderengine/skia/filters/LutShader.cpp
+++ b/libs/renderengine/skia/filters/LutShader.cpp
@@ -182,8 +182,8 @@
* (R1, G1, B1, 0)
* ...
*/
- SkImageInfo info = SkImageInfo::Make(length /* the number of rgba */ * 4, 1,
- kRGBA_F16_SkColorType, kPremul_SkAlphaType);
+ SkImageInfo info = SkImageInfo::Make(length /* the number of rgba */, 1, kRGBA_F16_SkColorType,
+ kPremul_SkAlphaType);
SkBitmap bitmap;
bitmap.allocPixels(info);
if (!bitmap.installPixels(info, buffer.data(), info.minRowBytes())) {
diff --git a/libs/shaders/OWNERS b/libs/shaders/OWNERS
index 6d91da3..6977a49 100644
--- a/libs/shaders/OWNERS
+++ b/libs/shaders/OWNERS
@@ -1,4 +1,3 @@
alecmouri@google.com
jreck@google.com
sallyqi@google.com
-scroggo@google.com
\ No newline at end of file
diff --git a/libs/tonemap/OWNERS b/libs/tonemap/OWNERS
index 6d91da3..6977a49 100644
--- a/libs/tonemap/OWNERS
+++ b/libs/tonemap/OWNERS
@@ -1,4 +1,3 @@
alecmouri@google.com
jreck@google.com
sallyqi@google.com
-scroggo@google.com
\ No newline at end of file
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
index a0b5fe7..2a85a4b 100644
--- a/libs/ui/OWNERS
+++ b/libs/ui/OWNERS
@@ -2,6 +2,5 @@
alecmouri@google.com
chrisforbes@google.com
jreck@google.com
-lpy@google.com
mathias@google.com
romainguy@google.com
diff --git a/libs/ui/include/ui/ShadowSettings.h b/libs/ui/include/ui/ShadowSettings.h
index 06be6db..c0b83b8 100644
--- a/libs/ui/include/ui/ShadowSettings.h
+++ b/libs/ui/include/ui/ShadowSettings.h
@@ -46,9 +46,6 @@
// Length of the cast shadow. If length is <= 0.f no shadows will be drawn.
float length = 0.f;
- // Length of the cast shadow that is drawn by the client.
- float clientDrawnLength = 0.f;
-
// If true fill in the casting layer is translucent and the shadow needs to fill the bounds.
// Otherwise the shadow will only be drawn around the edges of the casting layer.
bool casterIsTranslucent = false;
@@ -58,7 +55,6 @@
return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor &&
lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos &&
lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length &&
- lhs.clientDrawnLength == rhs.clientDrawnLength &&
lhs.casterIsTranslucent == rhs.casterIsTranslucent;
}
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 5fe9484..0dd9f19 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -134,6 +134,11 @@
if (cnx->egl.eglGetPlatformDisplay) {
std::vector<EGLAttrib> attrs;
+ // These must have the same lifetime as |attrs|, because |attrs| contains pointers to these
+ // variables.
+ std::vector<const char*> enabled; // ANGLE features to enable
+ std::vector<const char*> disabled; // ANGLE features to disable
+
if (attrib_list) {
for (const EGLAttrib* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
attrs.push_back(attr[0]);
@@ -142,9 +147,6 @@
}
if (graphicsenv_flags::feature_overrides()) {
- std::vector<const char*> enabled; // ANGLE features to enable
- std::vector<const char*> disabled; // ANGLE features to disable
-
// Get the list of ANGLE features to enable from Global.Settings.
const auto& eglFeatures = GraphicsEnv::getInstance().getAngleEglFeatures();
for (const std::string& eglFeature : eglFeatures) {
@@ -154,25 +156,24 @@
// Get the list of ANGLE features to enable/disable from gpuservice.
GraphicsEnv::getInstance().getAngleFeatureOverrides(enabled, disabled);
if (!enabled.empty()) {
- enabled.push_back(0);
+ enabled.push_back(nullptr);
attrs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
attrs.push_back(reinterpret_cast<EGLAttrib>(enabled.data()));
}
if (!disabled.empty()) {
- disabled.push_back(0);
+ disabled.push_back(nullptr);
attrs.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
attrs.push_back(reinterpret_cast<EGLAttrib>(disabled.data()));
}
} else {
const auto& eglFeatures = GraphicsEnv::getInstance().getAngleEglFeatures();
- std::vector<const char*> features;
- if (eglFeatures.size() > 0) {
+ if (!eglFeatures.empty()) {
for (const std::string& eglFeature : eglFeatures) {
- features.push_back(eglFeature.c_str());
+ enabled.push_back(eglFeature.c_str());
}
- features.push_back(0);
+ enabled.push_back(nullptr);
attrs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
- attrs.push_back(reinterpret_cast<EGLAttrib>(features.data()));
+ attrs.push_back(reinterpret_cast<EGLAttrib>(enabled.data()));
}
}
diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
index 5c7f344..e96b17a 100644
--- a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
+++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
@@ -2,3 +2,4 @@
class hal
user graphics
group automotive_evs
+ disabled
diff --git a/services/displayservice/DisplayEventReceiver.cpp b/services/displayservice/DisplayEventReceiver.cpp
index 2bb74c2..9927fb6 100644
--- a/services/displayservice/DisplayEventReceiver.cpp
+++ b/services/displayservice/DisplayEventReceiver.cpp
@@ -22,6 +22,7 @@
#include <android/frameworks/displayservice/1.0/BpHwEventCallback.h>
#include <thread>
+#include <ftl/enum.h>
namespace android {
namespace frameworks {
@@ -97,11 +98,11 @@
for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
const FwkReceiver::Event &event = buf[i];
- uint32_t type = event.header.type;
+ android::DisplayEventType type = event.header.type;
uint64_t timestamp = event.header.timestamp;
switch(buf[i].header.type) {
- case FwkReceiver::DISPLAY_EVENT_VSYNC: {
+ case DisplayEventType::DISPLAY_EVENT_VSYNC: {
auto ret = mCallback->onVsync(timestamp, event.vsync.count);
if (!ret.isOk()) {
LOG(ERROR) << "AttachedEvent handleEvent fails on onVsync callback"
@@ -109,7 +110,7 @@
return 0; // remove the callback
}
} break;
- case FwkReceiver::DISPLAY_EVENT_HOTPLUG: {
+ case DisplayEventType::DISPLAY_EVENT_HOTPLUG: {
auto ret = mCallback->onHotplug(timestamp, event.hotplug.connected);
if (!ret.isOk()) {
LOG(ERROR) << "AttachedEvent handleEvent fails on onHotplug callback"
@@ -118,7 +119,8 @@
}
} break;
default: {
- LOG(ERROR) << "AttachedEvent handleEvent unknown type: " << type;
+ LOG(ERROR) << "AttachedEvent handleEvent unknown type: "
+ << ftl::to_underlying(type);
}
}
}
diff --git a/services/displayservice/OWNERS b/services/displayservice/OWNERS
index 7a3e4c2..40164aa 100644
--- a/services/displayservice/OWNERS
+++ b/services/displayservice/OWNERS
@@ -1,2 +1 @@
smoreland@google.com
-lpy@google.com
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 689221f..01287b0 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -7,6 +7,13 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+aconfig_declarations {
+ name: "gpuservice_flags",
+ package: "com.android.frameworks.gpuservice.flags",
+ container: "system",
+ srcs: ["gpuservice_flags.aconfig"],
+}
+
cc_defaults {
name: "gpuservice_defaults",
cflags: [
@@ -20,6 +27,11 @@
}
cc_aconfig_library {
+ name: "gpuservice_multiuser_flags_c_lib",
+ aconfig_declarations: "gpuservice_flags",
+}
+
+cc_aconfig_library {
name: "gpuservice_flags_c_lib",
aconfig_declarations: "graphicsenv_flags",
}
@@ -92,6 +104,9 @@
srcs: [
":libgpuservice_sources",
],
+ shared_libs: [
+ "gpuservice_multiuser_flags_c_lib",
+ ],
}
cc_defaults {
@@ -126,4 +141,7 @@
static_libs: [
"libgpuservice",
],
+ shared_libs: [
+ "gpuservice_multiuser_flags_c_lib",
+ ],
}
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index fadb1fd..f74b4fa 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -24,7 +24,9 @@
#include <binder/IResultReceiver.h>
#include <binder/Parcel.h>
#include <binder/PermissionCache.h>
+#include <com_android_frameworks_gpuservice_flags.h>
#include <cutils/properties.h>
+#include <cutils/multiuser.h>
#include <gpumem/GpuMem.h>
#include <gpuwork/GpuWork.h>
#include <gpustats/GpuStats.h>
@@ -38,6 +40,8 @@
#include <thread>
#include <memory>
+namespace gpuservice_flags = com::android::frameworks::gpuservice::flags;
+
namespace android {
using base::StringAppendF;
@@ -113,11 +117,22 @@
// only system_server with the ACCESS_GPU_SERVICE permission is allowed to set
// persist.graphics.egl
- if (uid != AID_SYSTEM ||
- !PermissionCache::checkPermission(sAccessGpuServicePermission, pid, uid)) {
- ALOGE("Permission Denial: can't set persist.graphics.egl from setAngleAsSystemDriver() "
+ if (gpuservice_flags::multiuser_permission_check()) {
+ // retrieve the appid of Settings app on multiuser builds
+ const int multiuserappid = multiuser_get_app_id(uid);
+ if (multiuserappid != AID_SYSTEM ||
+ !PermissionCache::checkPermission(sAccessGpuServicePermission, pid, uid)) {
+ ALOGE("Permission Denial: can't set persist.graphics.egl from setAngleAsSystemDriver() "
+ "pid=%d, uid=%d\n, multiuserappid=%d", pid, uid, multiuserappid);
+ return;
+ }
+ } else {
+ if (uid != AID_SYSTEM ||
+ !PermissionCache::checkPermission(sAccessGpuServicePermission, pid, uid)) {
+ ALOGE("Permission Denial: can't set persist.graphics.egl from setAngleAsSystemDriver() "
"pid=%d, uid=%d\n", pid, uid);
- return;
+ return;
+ }
}
std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/gpuservice/feature_override/Android.bp b/services/gpuservice/feature_override/Android.bp
index cda67f0..3b5407b 100644
--- a/services/gpuservice/feature_override/Android.bp
+++ b/services/gpuservice/feature_override/Android.bp
@@ -34,9 +34,7 @@
"libbase",
"libgraphicsenv",
"liblog",
- ],
- static_libs: [
- "libprotobuf-cpp-lite-ndk",
+ "libprotobuf-cpp-lite",
],
}
diff --git a/services/gpuservice/gpuservice_flags.aconfig b/services/gpuservice/gpuservice_flags.aconfig
new file mode 100644
index 0000000..be6a7bb
--- /dev/null
+++ b/services/gpuservice/gpuservice_flags.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.frameworks.gpuservice.flags"
+container: "system"
+
+flag {
+ name: "multiuser_permission_check"
+ namespace: "gpu"
+ description: "Whether to consider headless system user mode/multiuser when checking toggleAngleAsSystemDriver permission."
+ bug: "389867658"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/gpuservice/tests/fuzzers/Android.bp b/services/gpuservice/tests/fuzzers/Android.bp
index d4d48c4..7be3253 100644
--- a/services/gpuservice/tests/fuzzers/Android.bp
+++ b/services/gpuservice/tests/fuzzers/Android.bp
@@ -13,6 +13,9 @@
"libgpuservice",
"liblog",
],
+ shared_libs: [
+ "gpuservice_multiuser_flags_c_lib",
+ ],
fuzz_config: {
cc: [
"paulthomson@google.com",
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index d2184d8..0dac24d 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -89,6 +89,7 @@
],
header_libs: ["bpf_headers"],
shared_libs: [
+ "gpuservice_multiuser_flags_c_lib",
"libbase",
"libbinder",
"libbpf_bcc",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 9793800..4c8147d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -798,20 +798,6 @@
return !isFromSource(source, AINPUT_SOURCE_MOUSE);
}
-/**
- * Return true if stylus is currently down anywhere on the specified display, and false otherwise.
- */
-bool isStylusActiveInDisplay(ui::LogicalDisplayId displayId,
- const std::unordered_map<ui::LogicalDisplayId /*displayId*/,
- TouchState>& touchStatesByDisplay) {
- const auto it = touchStatesByDisplay.find(displayId);
- if (it == touchStatesByDisplay.end()) {
- return false;
- }
- const TouchState& state = it->second;
- return state.hasActiveStylus();
-}
-
Result<void> validateWindowInfosUpdate(const gui::WindowInfosUpdate& update) {
std::unordered_set<int32_t> windowIds;
for (const WindowInfo& info : update.windowInfos) {
@@ -985,6 +971,9 @@
resetKeyRepeatLocked();
releasePendingEventLocked();
drainInboundQueueLocked();
+#if defined(__ANDROID__)
+ SurfaceComposerClient::getDefault()->removeWindowInfosListener(mWindowInfoListener);
+#endif
mCommandQueue.clear();
}
@@ -1155,9 +1144,7 @@
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
- if (DEBUG_FOCUS) {
- ALOGD("Dispatch frozen. Waiting some more.");
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "Dispatch frozen. Waiting some more.";
return;
}
@@ -1350,9 +1337,8 @@
// Alternatively, maybe there's a spy window that could handle this event.
const std::vector<sp<WindowInfoHandle>> touchedSpies =
- mWindowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus,
- motionEntry.deviceId,
- mTouchStates.mTouchStatesByDisplay);
+ findTouchedSpyWindowsAt(displayId, x, y, isStylus, motionEntry.deviceId,
+ mWindowInfos);
for (const auto& windowHandle : touchedSpies) {
const std::shared_ptr<Connection> connection =
mConnectionManager.getConnection(windowHandle->getToken());
@@ -1510,16 +1496,16 @@
return outsideTargets;
}
-std::vector<sp<WindowInfoHandle>> InputDispatcher::DispatcherWindowInfo::findTouchedSpyWindowsAt(
+std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAt(
ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) const {
+ const DispatcherWindowInfo& windowInfos) {
// Traverse windows from front to back and gather the touched spy windows.
std::vector<sp<WindowInfoHandle>> spyWindows;
- const auto& windowHandles = getWindowHandlesForDisplay(displayId);
+ const ui::Transform displayTransform = windowInfos.getDisplayTransform(displayId);
+ const auto& windowHandles = windowInfos.getWindowHandlesForDisplay(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
const WindowInfo& info = *windowHandle->getInfo();
- if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus,
- getDisplayTransform(displayId))) {
+ if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, displayTransform)) {
// Skip if the pointer is outside of the window.
continue;
}
@@ -1536,9 +1522,7 @@
const char* reason;
switch (dropReason) {
case DropReason::POLICY:
- if (debugInboundEventDetails()) {
- ALOGD("Dropped event because policy consumed it.");
- }
+ LOG_IF(INFO, debugInboundEventDetails()) << "Dropped event because policy consumed it.";
reason = "inbound event was dropped because the policy consumed it";
break;
case DropReason::DISABLED:
@@ -1652,9 +1636,7 @@
void InputDispatcher::releaseInboundEventLocked(std::shared_ptr<const EventEntry> entry) {
const std::shared_ptr<InjectionState>& injectionState = entry->injectionState;
if (injectionState && injectionState->injectionResult == InputEventInjectionResult::PENDING) {
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("Injected inbound event was dropped.");
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE) << "Injected inbound event was dropped.";
setInjectionResult(*entry, InputEventInjectionResult::FAILED);
}
if (entry == mNextUnblockedEvent) {
@@ -1694,10 +1676,9 @@
bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime,
const DeviceResetEntry& entry) {
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
- entry.deviceId);
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "dispatchDeviceReset - eventTime=" << entry.eventTime
+ << ", deviceId=" << entry.deviceId;
// Reset key repeating in case a keyboard device was disabled or enabled.
if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->deviceId == entry.deviceId) {
@@ -1889,9 +1870,8 @@
} else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
// The key on device 'deviceId' is still down, do not stop key repeat
- if (debugInboundEventDetails()) {
- ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
- }
+ LOG_IF(INFO, debugInboundEventDetails())
+ << "deviceId=" << entry->deviceId << " got KEY_UP as stale";
} else if (!entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
@@ -1988,25 +1968,24 @@
}
void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) {
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%s, "
- "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
- "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
- prefix, entry.eventTime, entry.deviceId, entry.source,
- entry.displayId.toString().c_str(), entry.policyFlags, entry.action, entry.flags,
- entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount, entry.downTime);
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << prefix << "eventTime=" << entry.eventTime << ", deviceId=" << entry.deviceId
+ << ", source=0x" << std::hex << entry.source
+ << ", displayId=" << entry.displayId.toString() << ", policyFlags=0x"
+ << entry.policyFlags << ", action=0x" << entry.action << ", flags=0x" << entry.flags
+ << ", keyCode=0x" << entry.keyCode << ", scanCode=0x" << entry.scanCode
+ << ", metaState=0x" << entry.metaState << ", repeatCount=" << std::dec
+ << entry.repeatCount << ", downTime=" << entry.downTime;
}
void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime,
const std::shared_ptr<const SensorEntry>& entry,
DropReason* dropReason, nsecs_t& nextWakeupTime) {
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
- "source=0x%x, sensorType=%s",
- entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
- ftl::enum_string(entry->sensorType).c_str());
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "notifySensorEvent eventTime=" << entry->eventTime
+ << ", hwTimestamp=" << entry->hwTimestamp << ", deviceId=" << entry->deviceId
+ << ", source=0x" << std::hex << entry->source << std::dec
+ << ", sensorType=" << ftl::enum_string(entry->sensorType);
auto command = [this, entry]() REQUIRES(mLock) {
scoped_unlock unlock(mLock);
@@ -2020,10 +1999,9 @@
}
bool InputDispatcher::flushSensor(int deviceId, InputDeviceSensorType sensorType) {
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId,
- ftl::enum_string(sensorType).c_str());
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "flushSensor deviceId=" << deviceId
+ << ", sensorType=" << ftl::enum_string(sensorType).c_str();
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -2193,9 +2171,7 @@
std::shared_ptr<const EventEntry> eventEntry,
const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("dispatchEventToCurrentInputTargets");
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE) << "dispatchEventToCurrentInputTargets";
processInteractionsLocked(*eventEntry, inputTargets);
@@ -2238,9 +2214,7 @@
}
void InputDispatcher::resetNoFocusedWindowTimeoutLocked() {
- if (DEBUG_FOCUS) {
- ALOGD("Resetting ANR timeouts.");
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "Resetting ANR timeouts.";
// Reset input target wait timeout.
mNoFocusedWindowTimeoutTime = std::nullopt;
@@ -2480,8 +2454,7 @@
}
std::vector<sp<WindowInfoHandle>> newTouchedWindows =
- windowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId,
- mTouchStatesByDisplay);
+ findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, windowInfos);
if (newTouchedWindowHandle != nullptr) {
// Process the foreground window first so that it is the first to receive the event.
newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);
@@ -2494,8 +2467,7 @@
}
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
- if (!canWindowReceiveMotion(windowHandle, entry, connections, windowInfos,
- mTouchStatesByDisplay)) {
+ if (!canWindowReceiveMotion(windowHandle, entry, connections, windowInfos)) {
continue;
}
@@ -2576,11 +2548,10 @@
// If the pointer is not currently down, then ignore the event.
if (!tempTouchState.isDown(entry.deviceId) &&
maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
- if (DEBUG_DROPPED_EVENTS_VERBOSE) {
- LOG(INFO) << "Dropping event because the pointer for device " << entry.deviceId
- << " is not down or we previously dropped the pointer down event in "
- << "display " << displayId << ": " << entry.getDescription();
- }
+ LOG_IF(INFO, DEBUG_DROPPED_EVENTS_VERBOSE)
+ << "Dropping event because the pointer for device " << entry.deviceId
+ << " is not down or we previously dropped the pointer down event in display "
+ << displayId << ": " << entry.getDescription();
return injectionError(InputEventInjectionResult::FAILED);
}
@@ -2618,8 +2589,7 @@
// Do not slide events to the window which can not receive motion event
if (newTouchedWindowHandle != nullptr &&
- !canWindowReceiveMotion(newTouchedWindowHandle, entry, connections, windowInfos,
- mTouchStatesByDisplay)) {
+ !canWindowReceiveMotion(newTouchedWindowHandle, entry, connections, windowInfos)) {
newTouchedWindowHandle = nullptr;
}
@@ -3261,10 +3231,9 @@
return;
}
if (windowDisablingUserActivityInfo != nullptr) {
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("Not poking user activity: disabled by window '%s'.",
- windowDisablingUserActivityInfo->name.c_str());
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE)
+ << "Not poking user activity: disabled by window '"
+ << windowDisablingUserActivityInfo->name << "'.";
return;
}
break;
@@ -3278,10 +3247,9 @@
// the apps, like system shortcuts
if (windowDisablingUserActivityInfo != nullptr &&
keyEntry.interceptKeyResult != KeyEntry::InterceptKeyResult::SKIP) {
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("Not poking user activity: disabled by window '%s'.",
- windowDisablingUserActivityInfo->name.c_str());
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE)
+ << "Not poking user activity: disabled by window '"
+ << windowDisablingUserActivityInfo->name << "'.";
return;
}
break;
@@ -3309,22 +3277,19 @@
ATRACE_NAME_IF(ATRACE_ENABLED(),
StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
connection->getInputChannelName().c_str(), eventEntry->id));
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("channel '%s' ~ prepareDispatchCycle - flags=%s, "
- "globalScaleFactor=%f, pointerIds=%s %s",
- connection->getInputChannelName().c_str(), inputTarget.flags.string().c_str(),
- inputTarget.globalScaleFactor, bitsetToString(inputTarget.getPointerIds()).c_str(),
- inputTarget.getPointerInfoString().c_str());
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE)
+ << "channel '" << connection->getInputChannelName()
+ << "' ~ prepareDispatchCycle - flags=" << inputTarget.flags.string()
+ << ", globalScaleFactor=" << inputTarget.globalScaleFactor
+ << ", pointerIds=" << bitsetToString(inputTarget.getPointerIds()) << " "
+ << inputTarget.getPointerInfoString();
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::Status::NORMAL) {
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
- connection->getInputChannelName().c_str(),
- ftl::enum_string(connection->status).c_str());
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE) << "channel '" << connection->getInputChannelName()
+ << "' ~ Dropping event because the channel status is "
+ << ftl::enum_string(connection->status);
return;
}
@@ -3443,11 +3408,10 @@
if (resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
!connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
motionEntry.displayId)) {
- if (DEBUG_DISPATCH_CYCLE) {
- LOG(DEBUG) << "channel '" << connection->getInputChannelName().c_str()
- << "' ~ enqueueDispatchEntryLocked: filling in missing hover "
- "enter event";
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE)
+ << "channel '" << connection->getInputChannelName().c_str()
+ << "' ~ enqueueDispatchEntryLocked: filling in missing hover enter "
+ "event";
resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
}
@@ -3741,9 +3705,8 @@
ATRACE_NAME_IF(ATRACE_ENABLED(),
StringPrintf("startDispatchCycleLocked(inputChannel=%s)",
connection->getInputChannelName().c_str()));
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE)
+ << "channel '" << connection->getInputChannelName() << "' ~ startDispatchCycle";
while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
std::unique_ptr<DispatchEntry>& dispatchEntry = connection->outboundQueue.front();
@@ -3758,10 +3721,9 @@
case EventEntry::Type::KEY: {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- LOG(INFO) << "Publishing " << *dispatchEntry << " to "
- << connection->getInputChannelName();
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "Publishing " << *dispatchEntry << " to "
+ << connection->getInputChannelName();
// Publish the key event.
status = connection->inputPublisher
@@ -3780,10 +3742,9 @@
}
case EventEntry::Type::MOTION: {
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- LOG(INFO) << "Publishing " << *dispatchEntry << " to "
- << connection->getInputChannelName();
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "Publishing " << *dispatchEntry << " to "
+ << connection->getInputChannelName();
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
status = publishMotionEvent(*connection, *dispatchEntry);
if (status == BAD_VALUE) {
@@ -3856,11 +3817,10 @@
} else {
// Pipe is full and we are waiting for the app to finish process some events
// before sending more events to it.
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
- "waiting for the application to catch up",
- connection->getInputChannelName().c_str());
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE)
+ << "channel '" << connection->getInputChannelName()
+ << "' ~ Could not publish event because the pipe is full, waiting for "
+ "the application to catch up";
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
@@ -3926,10 +3886,9 @@
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection,
uint32_t seq, bool handled, nsecs_t consumeTime) {
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
- connection->getInputChannelName().c_str(), seq, toString(handled));
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE)
+ << "channel '" << connection->getInputChannelName()
+ << "' ~ finishDispatchCycle - seq=" << seq << ", handled=" << toString(handled);
if (connection->status != Connection::Status::NORMAL) {
return;
@@ -3944,10 +3903,8 @@
void InputDispatcher::abortBrokenDispatchCycleLocked(const std::shared_ptr<Connection>& connection,
bool notify) {
- if (DEBUG_DISPATCH_CYCLE) {
- LOG(INFO) << "channel '" << connection->getInputChannelName() << "'~ " << __func__
- << " - notify=" << toString(notify);
- }
+ LOG_IF(INFO, DEBUG_DISPATCH_CYCLE) << "channel '" << connection->getInputChannelName() << "'~ "
+ << __func__ << " - notify=" << toString(notify);
// Clear the dispatch queues.
drainDispatchQueue(connection->outboundQueue);
@@ -4072,13 +4029,17 @@
// Generate cancellations for touched windows first. This is to avoid generating cancellations
// through a non-touched window if there are more than one window for an input channel.
if (cancelPointers) {
- for (const auto& [displayId, touchState] : mTouchStates.mTouchStatesByDisplay) {
- if (options.displayId.has_value() && options.displayId != displayId) {
- continue;
- }
- for (const auto& touchedWindow : touchState.windows) {
- synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
- }
+ if (options.displayId.has_value()) {
+ mTouchStates.forAllTouchedWindowsOnDisplay(
+ options.displayId.value(), [&](const sp<gui::WindowInfoHandle>& windowHandle) {
+ base::ScopedLockAssertion assumeLocked(mLock);
+ synthesizeCancelationEventsForWindowLocked(windowHandle, options);
+ });
+ } else {
+ mTouchStates.forAllTouchedWindows([&](const sp<gui::WindowInfoHandle>& windowHandle) {
+ base::ScopedLockAssertion assumeLocked(mLock);
+ synthesizeCancelationEventsForWindowLocked(windowHandle, options);
+ });
}
}
// Follow up by generating cancellations for all windows, because we don't explicitly track
@@ -4149,12 +4110,11 @@
return;
}
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
- "with reality: %s, mode=%s.",
- connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
- ftl::enum_string(options.mode).c_str());
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "channel '" << connection->getInputChannelName() << "' ~ Synthesized "
+ << cancelationEvents.size()
+ << " cancelation events to bring channel back in sync with reality: " << options.reason
+ << ", mode=" << ftl::enum_string(options.mode) << ".";
std::string reason = std::string("reason=").append(options.reason);
android_log_event_list(LOGTAG_INPUT_CANCEL)
@@ -4271,18 +4231,17 @@
return;
}
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("channel '%s' ~ Synthesized %zu down events to ensure consistent event stream.",
- connection->getInputChannelName().c_str(), downEvents.size());
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "channel '" << connection->getInputChannelName() << "' ~ Synthesized "
+ << downEvents.size() << " down events to ensure consistent event stream.";
- const auto [_, touchedWindowState, displayId] =
- findTouchStateWindowAndDisplay(connection->getToken(),
- mTouchStates.mTouchStatesByDisplay);
- if (touchedWindowState == nullptr) {
+ auto touchedWindowHandleAndDisplay =
+ mTouchStates.findTouchedWindowHandleAndDisplay(connection->getToken());
+ if (!touchedWindowHandleAndDisplay.has_value()) {
LOG(FATAL) << __func__ << ": Touch state is out of sync: No touched window for token";
}
- const auto& windowHandle = touchedWindowState->windowHandle;
+
+ const auto [windowHandle, displayId] = touchedWindowHandleAndDisplay.value();
const bool wasEmpty = connection->outboundQueue.empty();
for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
@@ -4414,15 +4373,15 @@
}
void InputDispatcher::notifyKey(const NotifyKeyArgs& args) {
- ALOGD_IF(debugInboundEventDetails(),
- "notifyKey - id=%" PRIx32 ", eventTime=%" PRId64
- ", deviceId=%d, source=%s, displayId=%s, policyFlags=0x%x, action=%s, flags=0x%x, "
- "keyCode=%s, scanCode=0x%x, metaState=0x%x, "
- "downTime=%" PRId64,
- args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(),
- args.displayId.toString().c_str(), args.policyFlags,
- KeyEvent::actionToString(args.action), args.flags, KeyEvent::getLabel(args.keyCode),
- args.scanCode, args.metaState, args.downTime);
+ LOG_IF(INFO, debugInboundEventDetails())
+ << "notifyKey - id=" << args.id << ", eventTime=" << args.eventTime
+ << ", deviceId=" << args.deviceId
+ << ", source=" << inputEventSourceToString(args.source)
+ << ", displayId=" << args.displayId.toString() << ", policyFlags=0x" << std::hex
+ << args.policyFlags << ", action=" << KeyEvent::actionToString(args.action)
+ << ", flags=0x" << args.flags << ", keyCode=" << KeyEvent::getLabel(args.keyCode)
+ << ", scanCode=0x" << args.scanCode << ", metaState=0x" << args.metaState
+ << ", downTime=" << std::dec << args.downTime;
Result<void> keyCheck = validateKeyEvent(args.action);
if (!keyCheck.ok()) {
LOG(ERROR) << "invalid key event: " << keyCheck.error();
@@ -4632,12 +4591,10 @@
}
void InputDispatcher::notifySensor(const NotifySensorArgs& args) {
- if (debugInboundEventDetails()) {
- ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
- " sensorType=%s",
- args.id, args.eventTime, args.deviceId, args.source,
- ftl::enum_string(args.sensorType).c_str());
- }
+ LOG_IF(INFO, debugInboundEventDetails())
+ << "notifySensor - id=" << args.id << " eventTime=" << args.eventTime
+ << ", deviceId=" << args.deviceId << ", source=0x" << std::hex << args.source
+ << std::dec << ", sensorType=" << ftl::enum_string(args.sensorType);
bool needWake = false;
{ // acquire lock
@@ -4659,10 +4616,9 @@
}
void InputDispatcher::notifyVibratorState(const NotifyVibratorStateArgs& args) {
- if (debugInboundEventDetails()) {
- ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d, isOn=%d", args.eventTime,
- args.deviceId, args.isOn);
- }
+ LOG_IF(INFO, debugInboundEventDetails())
+ << "notifyVibratorState - eventTime=" << args.eventTime << ", device=" << args.deviceId
+ << ", isOn=" << args.isOn;
mPolicy.notifyVibratorState(args.deviceId, args.isOn);
}
@@ -4671,11 +4627,10 @@
}
void InputDispatcher::notifySwitch(const NotifySwitchArgs& args) {
- if (debugInboundEventDetails()) {
- ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
- "switchMask=0x%08x",
- args.eventTime, args.policyFlags, args.switchValues, args.switchMask);
- }
+ LOG_IF(INFO, debugInboundEventDetails())
+ << "notifySwitch - eventTime=" << args.eventTime << ", policyFlags=0x" << std::hex
+ << args.policyFlags << ", switchValues=0x" << std::setfill('0') << std::setw(8)
+ << args.switchValues << ", switchMask=0x" << std::setw(8) << args.switchMask;
uint32_t policyFlags = args.policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
@@ -4684,10 +4639,8 @@
void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
// TODO(b/308677868) Remove device reset from the InputListener interface
- if (debugInboundEventDetails()) {
- ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args.eventTime,
- args.deviceId);
- }
+ LOG_IF(INFO, debugInboundEventDetails())
+ << "notifyDeviceReset - eventTime=" << args.eventTime << ", deviceId=" << args.deviceId;
bool needWake = false;
{ // acquire lock
@@ -4708,10 +4661,9 @@
}
void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) {
- if (debugInboundEventDetails()) {
- ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args.eventTime,
- args.request.isEnable() ? "true" : "false");
- }
+ LOG_IF(INFO, debugInboundEventDetails())
+ << "notifyPointerCaptureChanged - eventTime=%" << args.eventTime
+ << ", enabled=" << toString(args.request.isEnable());
bool needWake = false;
{ // acquire lock
@@ -4771,12 +4723,10 @@
return InputEventInjectionResult::FAILED;
}
- if (debugInboundEventDetails()) {
- LOG(INFO) << __func__ << ": targetUid=" << toString(targetUid, &uidString)
- << ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count()
- << "ms, policyFlags=0x" << std::hex << policyFlags << std::dec
- << ", event=" << *event;
- }
+ LOG_IF(INFO, debugInboundEventDetails())
+ << __func__ << ": targetUid=" << toString(targetUid, &uidString)
+ << ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count()
+ << "ms, policyFlags=0x" << std::hex << policyFlags << std::dec << ", event=" << *event;
nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED;
@@ -4953,9 +4903,7 @@
bool needWake = false;
while (!injectedEntries.empty()) {
- if (DEBUG_INJECTION) {
- LOG(INFO) << "Injecting " << injectedEntries.front()->getDescription();
- }
+ LOG_IF(INFO, DEBUG_INJECTION) << "Injecting " << injectedEntries.front()->getDescription();
needWake |= enqueueInboundEventLocked(std::move(injectedEntries.front()));
injectedEntries.pop();
}
@@ -4981,10 +4929,8 @@
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
- if (DEBUG_INJECTION) {
- ALOGD("injectInputEvent - Timed out waiting for injection result "
- "to become available.");
- }
+ LOG_IF(INFO, DEBUG_INJECTION) << "injectInputEvent - Timed out waiting for "
+ "injection result to become available.";
injectionResult = InputEventInjectionResult::TIMED_OUT;
break;
}
@@ -4995,16 +4941,14 @@
if (injectionResult == InputEventInjectionResult::SUCCEEDED &&
syncMode == InputEventInjectionSync::WAIT_FOR_FINISHED) {
while (injectionState->pendingForegroundDispatches != 0) {
- if (DEBUG_INJECTION) {
- ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
- injectionState->pendingForegroundDispatches);
- }
+ LOG_IF(INFO, DEBUG_INJECTION) << "injectInputEvent - Waiting for "
+ << injectionState->pendingForegroundDispatches
+ << " pending foreground dispatches.";
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
- if (DEBUG_INJECTION) {
- ALOGD("injectInputEvent - Timed out waiting for pending foreground "
- "dispatches to finish.");
- }
+ LOG_IF(INFO, DEBUG_INJECTION)
+ << "injectInputEvent - Timed out waiting for pending foreground "
+ "dispatches to finish.";
injectionResult = InputEventInjectionResult::TIMED_OUT;
break;
}
@@ -5015,10 +4959,8 @@
}
} // release lock
- if (DEBUG_INJECTION) {
- LOG(INFO) << "injectInputEvent - Finished with result "
- << ftl::enum_string(injectionResult);
- }
+ LOG_IF(INFO, DEBUG_INJECTION) << "injectInputEvent - Finished with result "
+ << ftl::enum_string(injectionResult);
return injectionResult;
}
@@ -5064,10 +5006,8 @@
}
InjectionState& injectionState = *entry.injectionState;
- if (DEBUG_INJECTION) {
- LOG(INFO) << "Setting input event injection result to "
- << ftl::enum_string(injectionResult);
- }
+ LOG_IF(INFO, DEBUG_INJECTION) << "Setting input event injection result to "
+ << ftl::enum_string(injectionResult);
if (injectionState.injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
// Log the outcome since the injector did not wait for the injection result.
@@ -5273,11 +5213,10 @@
return dump;
}
-bool InputDispatcher::canWindowReceiveMotion(
+bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion(
const sp<android::gui::WindowInfoHandle>& window,
const android::inputdispatcher::MotionEntry& motionEntry,
- const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStates) {
+ const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos) const {
const WindowInfo& info = *window->getInfo();
// Skip spy window targets that are not valid for targeted injection.
@@ -5331,7 +5270,7 @@
// Ignore touches if stylus is down anywhere on screen
if (info.inputConfig.test(WindowInfo::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH) &&
- isStylusActiveInDisplay(info.displayId, touchStates)) {
+ isStylusActiveInDisplay(info.displayId)) {
LOG(INFO) << "Dropping touch from " << window->getName() << " because stylus is active";
return false;
}
@@ -5495,9 +5434,7 @@
// which might not happen until the next GC.
for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
if (!mWindowInfos.isWindowPresent(oldWindowHandle)) {
- if (DEBUG_FOCUS) {
- ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "Window went away: " << oldWindowHandle->getName();
oldWindowHandle->releaseChannel();
}
}
@@ -5576,10 +5513,9 @@
void InputDispatcher::setFocusedApplication(
ui::LogicalDisplayId displayId,
const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
- if (DEBUG_FOCUS) {
- ALOGD("setFocusedApplication displayId=%s %s", displayId.toString().c_str(),
- inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "setFocusedApplication displayId=" << displayId.toString() << " "
+ << (inputApplicationHandle ? inputApplicationHandle->getName()
+ : "<nullptr>");
{ // acquire lock
std::scoped_lock _l(mLock);
setFocusedApplicationLocked(displayId, inputApplicationHandle);
@@ -5629,9 +5565,7 @@
* display. The display-specified events won't be affected.
*/
void InputDispatcher::setFocusedDisplay(ui::LogicalDisplayId displayId) {
- if (DEBUG_FOCUS) {
- ALOGD("setFocusedDisplay displayId=%s", displayId.toString().c_str());
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "setFocusedDisplay displayId=" << displayId.toString();
{ // acquire lock
std::scoped_lock _l(mLock);
ScopedSyntheticEventTracer traceContext(mTracer);
@@ -5685,9 +5619,8 @@
}
void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
- if (DEBUG_FOCUS) {
- ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "setInputDispatchMode: enabled=" << enabled
+ << ", frozen=" << frozen;
bool changed;
{ // acquire lock
@@ -5717,9 +5650,7 @@
}
void InputDispatcher::setInputFilterEnabled(bool enabled) {
- if (DEBUG_FOCUS) {
- ALOGD("setInputFilterEnabled: enabled=%d", enabled);
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "setInputFilterEnabled: enabled=" << enabled;
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -5741,14 +5672,16 @@
bool needWake = false;
{
std::scoped_lock lock(mLock);
- ALOGD_IF(DEBUG_TOUCH_MODE,
- "Request to change touch mode to %s (calling pid=%s, uid=%s, "
- "hasPermission=%s, target displayId=%s, mTouchModePerDisplay[displayId]=%s)",
- toString(inTouchMode), pid.toString().c_str(), uid.toString().c_str(),
- toString(hasPermission), displayId.toString().c_str(),
- mTouchModePerDisplay.count(displayId) == 0
- ? "not set"
- : std::to_string(mTouchModePerDisplay[displayId]).c_str());
+ LOG_IF(INFO, DEBUG_TOUCH_MODE)
+ << "Request to change touch mode to " << toString(inTouchMode)
+ << " (calling pid=" << pid.toString() << ", uid=" << uid.toString()
+ << ", hasPermission=" << toString(hasPermission)
+ << ", target displayId=" << displayId.toString()
+ << ", mTouchModePerDisplay[displayId]="
+ << (mTouchModePerDisplay.count(displayId) == 0
+ ? "not set"
+ : std::to_string(mTouchModePerDisplay[displayId]))
+ << ")";
auto touchModeIt = mTouchModePerDisplay.find(displayId);
if (touchModeIt != mTouchModePerDisplay.end() && touchModeIt->second == inTouchMode) {
@@ -5798,40 +5731,10 @@
mWindowInfos.setMaximumObscuringOpacityForTouch(opacity);
}
-std::tuple<const TouchState*, const TouchedWindow*, ui::LogicalDisplayId>
-InputDispatcher::findTouchStateWindowAndDisplay(
- const sp<IBinder>& token,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) {
- for (auto& [displayId, state] : touchStatesByDisplay) {
- for (const TouchedWindow& w : state.windows) {
- if (w.windowHandle->getToken() == token) {
- return std::make_tuple(&state, &w, displayId);
- }
- }
- }
- return std::make_tuple(nullptr, nullptr, ui::LogicalDisplayId::DEFAULT);
-}
-
-std::tuple<TouchState*, TouchedWindow*, ui::LogicalDisplayId>
-InputDispatcher::findTouchStateWindowAndDisplay(
- const sp<IBinder>& token,
- std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) {
- auto [constTouchState, constTouchedWindow, displayId] = InputDispatcher::
- findTouchStateWindowAndDisplay(token,
- const_cast<const std::unordered_map<ui::LogicalDisplayId,
- TouchState>&>(
- touchStatesByDisplay));
-
- return std::make_tuple(const_cast<TouchState*>(constTouchState),
- const_cast<TouchedWindow*>(constTouchedWindow), displayId);
-}
-
bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
bool isDragDrop) {
if (fromToken == toToken) {
- if (DEBUG_FOCUS) {
- ALOGD("Trivial transfer to same window.");
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "Trivial transfer to same window.";
return true;
}
@@ -5849,7 +5752,7 @@
return false;
}
- const auto [toWindowHandle, deviceId, pointers, cancellations, pointerDowns] =
+ const auto& [toWindowHandle, deviceId, pointers, cancellations, pointerDowns] =
result.value();
for (const auto& cancellationArgs : cancellations) {
@@ -5914,10 +5817,8 @@
return std::nullopt;
}
- if (DEBUG_FOCUS) {
- ALOGD("%s: fromWindowHandle=%s, toWindowHandle=%s", __func__,
- fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << __func__ << ": fromWindowHandle=" << fromWindowHandle->getName()
+ << ", toWindowHandle=" << toWindowHandle->getName();
// Erase old window.
ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow.targetFlags;
@@ -6020,9 +5921,7 @@
}
void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
- if (DEBUG_FOCUS) {
- ALOGD("Resetting and dropping all events (%s).", reason);
- }
+ LOG_IF(INFO, DEBUG_FOCUS) << "Resetting and dropping all events (" << reason << ").";
ScopedSyntheticEventTracer traceContext(mTracer);
CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS, reason,
@@ -6177,9 +6076,7 @@
};
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
- if (DEBUG_CHANNEL_CREATION) {
- ALOGD("channel '%s' ~ createInputChannel", name.c_str());
- }
+ LOG_IF(INFO, DEBUG_CHANNEL_CREATION) << "channel '" << name << "' ~ createInputChannel";
std::unique_ptr<InputChannel> serverChannel;
std::unique_ptr<InputChannel> clientChannel;
@@ -6295,14 +6192,14 @@
return BAD_VALUE;
}
- ScopedSyntheticEventTracer traceContext(mTracer);
- CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
- "input channel stole pointer stream", traceContext.getTracker());
const auto result = mTouchStates.pilferPointers(token, *requestingConnection);
if (!result.ok()) {
return result.error().code();
}
+ ScopedSyntheticEventTracer traceContext(mTracer);
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
+ "input channel stole pointer stream", traceContext.getTracker());
const auto cancellations = *result;
for (const auto& cancellationArgs : cancellations) {
LOG_ALWAYS_FATAL_IF(cancellationArgs.mode !=
@@ -6730,12 +6627,11 @@
// then cancel the associated fallback key, if any.
if (fallbackKeyCode) {
// Dispatch the unhandled key to the policy with the cancel flag.
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("Unhandled key event: Asking policy to cancel fallback action. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount,
- keyEntry.policyFlags);
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "Unhandled key event: Asking policy to cancel fallback action. keyCode="
+ << keyEntry.keyCode << ", action=" << keyEntry.action
+ << ", repeatCount=" << keyEntry.repeatCount << ", policyFlags=0x" << std::hex
+ << keyEntry.policyFlags;
KeyEvent event = createKeyEvent(keyEntry);
event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
@@ -6772,21 +6668,22 @@
// Then ask the policy what to do with it.
bool initialDown = keyEntry.action == AKEY_EVENT_ACTION_DOWN && keyEntry.repeatCount == 0;
if (!fallbackKeyCode && !initialDown) {
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("Unhandled key event: Skipping unhandled key event processing "
- "since this is not an initial down. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "Unhandled key event: Skipping unhandled key event processing since this is "
+ "not an initial down. keyCode="
+ << originalKeyCode << ", action=" << keyEntry.action
+ << ", repeatCount=" << keyEntry.repeatCount << ", policyFlags=0x" << std::hex
+ << keyEntry.policyFlags;
return {};
}
// Dispatch the unhandled key to the policy.
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("Unhandled key event: Asking policy to perform fallback action. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "Unhandled key event: Asking policy to perform fallback action. keyCode="
+ << keyEntry.keyCode << ", action=" << keyEntry.action
+ << ", repeatCount=" << keyEntry.repeatCount << ", policyFlags=0x" << std::hex
+ << keyEntry.policyFlags;
+ ;
KeyEvent event = createKeyEvent(keyEntry);
mLock.unlock();
@@ -6883,16 +6780,13 @@
newEntry->traceTracker =
mTracer->traceDerivedEvent(*newEntry, *keyEntry.traceTracker);
}
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("Unhandled key event: Dispatching fallback key. "
- "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
- originalKeyCode, *fallbackKeyCode, keyEntry.metaState);
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+ << "Unhandled key event: Dispatching fallback key. originalKeyCode="
+ << originalKeyCode << ", fallbackKeyCode=" << *fallbackKeyCode
+ << ", fallbackMetaState=0x" << std::hex << keyEntry.metaState;
return newEntry;
} else {
- if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("Unhandled key event: No fallback key.");
- }
+ LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS) << "Unhandled key event: No fallback key.";
// Report the key as unhandled, since there is no fallback key.
mReporter->reportUnhandledKey(keyEntry.id);
@@ -7033,7 +6927,7 @@
return;
}
- ALOGD_IF(DEBUG_FOCUS, "Disabling Pointer Capture because the window lost focus.");
+ LOG_IF(INFO, DEBUG_FOCUS) << "Disabling Pointer Capture because the window lost focus.";
if (mCurrentPointerCaptureRequest.isEnable()) {
setPointerCaptureLocked(nullptr);
@@ -7310,6 +7204,12 @@
}
}
+void InputDispatcher::setDisplayTopology(
+ const android::DisplayTopologyGraph& displayTopologyGraph) {
+ std::scoped_lock _l(mLock);
+ mWindowInfos.setDisplayTopology(displayTopologyGraph);
+}
+
InputDispatcher::ConnectionManager::ConnectionManager(const sp<android::Looper>& looper)
: mLooper(looper) {}
@@ -7445,6 +7345,11 @@
mMaximumObscuringOpacityForTouch = opacity;
}
+void InputDispatcher::DispatcherWindowInfo::setDisplayTopology(
+ const DisplayTopologyGraph& displayTopologyGraph) {
+ mTopology = displayTopologyGraph;
+}
+
ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetFlags(
const sp<WindowInfoHandle>& targetWindow, vec2 targetPosition, bool isSplit,
const DispatcherWindowInfo& windowInfos) {
@@ -7492,6 +7397,40 @@
return false;
}
+std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>>
+InputDispatcher::DispatcherTouchState::findTouchedWindowHandleAndDisplay(
+ const sp<android::IBinder>& token) const {
+ for (const auto& [displayId, state] : mTouchStatesByDisplay) {
+ for (const TouchedWindow& w : state.windows) {
+ if (w.windowHandle->getToken() == token) {
+ return std::make_tuple(std::ref(w.windowHandle), displayId);
+ }
+ }
+ }
+ return std::nullopt;
+}
+
+void InputDispatcher::DispatcherTouchState::forAllTouchedWindows(
+ std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
+ for (const auto& [_, state] : mTouchStatesByDisplay) {
+ for (const TouchedWindow& window : state.windows) {
+ f(window.windowHandle);
+ }
+ }
+}
+
+void InputDispatcher::DispatcherTouchState::forAllTouchedWindowsOnDisplay(
+ ui::LogicalDisplayId displayId,
+ std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
+ const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
+ if (touchStateIt == mTouchStatesByDisplay.end()) {
+ return;
+ }
+ for (const TouchedWindow& window : touchStateIt->second.windows) {
+ f(window.windowHandle);
+ }
+}
+
std::string InputDispatcher::DispatcherTouchState::dump() const {
std::string dump;
if (!mTouchStatesByDisplay.empty()) {
@@ -7529,4 +7468,14 @@
return std::nullopt;
}
+bool InputDispatcher::DispatcherTouchState::isStylusActiveInDisplay(
+ ui::LogicalDisplayId displayId) const {
+ const auto it = mTouchStatesByDisplay.find(displayId);
+ if (it == mTouchStatesByDisplay.end()) {
+ return false;
+ }
+ const TouchState& state = it->second;
+ return state.hasActiveStylus();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f214131..e76bd89 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -164,6 +164,8 @@
void setInputMethodConnectionIsActive(bool isActive) override;
+ void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) override;
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -291,6 +293,8 @@
void setMaximumObscuringOpacityForTouch(float opacity);
+ void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph);
+
// Get a reference to window handles by display, return an empty vector if not found.
const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesForDisplay(
ui::LogicalDisplayId displayId) const;
@@ -319,11 +323,6 @@
ui::LogicalDisplayId displayId, float x, float y, bool isStylus = false,
const sp<android::gui::WindowInfoHandle> ignoreWindow = nullptr) const;
- std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAt(
- ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay)
- const;
-
TouchOcclusionInfo computeTouchOcclusionInfo(
const sp<android::gui::WindowInfoHandle>& windowHandle, float x, float y) const;
@@ -346,6 +345,11 @@
std::unordered_map<ui::LogicalDisplayId /*displayId*/, android::gui::DisplayInfo>
mDisplayInfos;
float mMaximumObscuringOpacityForTouch{1.0f};
+
+ // Topology is initialized with default-constructed value, which is an empty topology until
+ // we receive setDisplayTopology call. Meanwhile we will treat every display as an
+ // independent display.
+ DisplayTopologyGraph mTopology;
};
DispatcherWindowInfo mWindowInfos GUARDED_BY(mLock);
@@ -392,6 +396,16 @@
bool isPointerInWindow(const sp<android::IBinder>& token, ui::LogicalDisplayId displayId,
DeviceId deviceId, int32_t pointerId) const;
+ // Find touched windowHandle and display by token.
+ std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>>
+ findTouchedWindowHandleAndDisplay(const sp<IBinder>& token) const;
+
+ void forAllTouchedWindows(std::function<void(const sp<gui::WindowInfoHandle>&)> f) const;
+
+ void forAllTouchedWindowsOnDisplay(
+ ui::LogicalDisplayId displayId,
+ std::function<void(const sp<gui::WindowInfoHandle>&)> f) const;
+
std::string dump() const;
// Updates the touchState for display from WindowInfo,
@@ -415,9 +429,9 @@
void clear();
+ private:
std::unordered_map<ui::LogicalDisplayId, TouchState> mTouchStatesByDisplay;
- private:
std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
findTouchStateWindowAndDisplay(const sp<IBinder>& token);
@@ -429,6 +443,15 @@
ftl::Flags<InputTarget::Flags> newTargetFlags,
const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections);
+ bool canWindowReceiveMotion(const sp<android::gui::WindowInfoHandle>& window,
+ const MotionEntry& motionEntry,
+ const ConnectionManager& connections,
+ const DispatcherWindowInfo& windowInfos) const;
+
+ // Return true if stylus is currently down anywhere on the specified display,
+ // and false otherwise.
+ bool isStylusActiveInDisplay(ui::LogicalDisplayId displayId) const;
+
static std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo(
TouchState& state, ui::LogicalDisplayId displayId,
const DispatcherWindowInfo& windowInfos);
@@ -584,11 +607,6 @@
sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(
ui::LogicalDisplayId displayId) const REQUIRES(mLock);
- static bool canWindowReceiveMotion(
- const sp<android::gui::WindowInfoHandle>& window, const MotionEntry& motionEntry,
- const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStates);
-
// Returns all the input targets (with their respective input channels) from the window handles
// passed as argument.
std::vector<InputTarget> getInputTargetsFromWindowHandlesLocked(
@@ -758,6 +776,10 @@
std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle,
const sp<android::gui::WindowInfoHandle>& windowHandle);
+ static std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAt(
+ ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId,
+ const DispatcherWindowInfo& windowInfos);
+
static bool shouldDropInput(const EventEntry& entry,
const sp<android::gui::WindowInfoHandle>& windowHandle,
const DispatcherWindowInfo& windowInfo);
@@ -855,17 +877,6 @@
const std::shared_ptr<Connection>& connection, DispatchEntry* dispatchEntry,
bool handled) REQUIRES(mLock);
- // Find touched state and touched window by token.
- static std::tuple<TouchState*, TouchedWindow*, ui::LogicalDisplayId>
- findTouchStateWindowAndDisplay(
- const sp<IBinder>& token,
- std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay);
-
- static std::tuple<const TouchState*, const TouchedWindow*, ui::LogicalDisplayId>
- findTouchStateWindowAndDisplay(
- const sp<IBinder>& token,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay);
-
// Statistics gathering.
nsecs_t mLastStatisticPushTime = 0;
std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 463a952..ab039c3 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -24,6 +24,7 @@
#include <android/os/InputEventInjectionSync.h>
#include <gui/InputApplication.h>
#include <gui/WindowInfo.h>
+#include <input/DisplayTopologyGraph.h>
#include <input/InputDevice.h>
#include <input/InputTransport.h>
#include <unordered_map>
@@ -243,6 +244,11 @@
* Notify the dispatcher that the state of the input method connection changed.
*/
virtual void setInputMethodConnectionIsActive(bool isActive) = 0;
+
+ /*
+ * Notify the dispatcher of the latest DisplayTopology.
+ */
+ virtual void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) = 0;
};
} // namespace android
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 013ef86..3c8b6f5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1620,41 +1620,43 @@
const auto& path = *sysfsRootPathOpt;
- std::shared_ptr<const AssociatedDevice> associatedDevice = std::make_shared<AssociatedDevice>(
- AssociatedDevice{.sysfsRootPath = path,
- .batteryInfos = readBatteryConfiguration(path),
- .lightInfos = readLightsConfiguration(path),
- .layoutInfo = readLayoutConfiguration(path)});
-
- bool associatedDeviceChanged = false;
+ std::shared_ptr<const AssociatedDevice> associatedDevice;
for (const auto& [id, dev] : mDevices) {
- if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) {
- if (*associatedDevice != *dev->associatedDevice) {
- associatedDeviceChanged = true;
- dev->associatedDevice = associatedDevice;
- }
- associatedDevice = dev->associatedDevice;
+ if (!dev->associatedDevice || dev->associatedDevice->sysfsRootPath != path) {
+ continue;
}
+ if (!associatedDevice) {
+ // Found matching associated device for the first time.
+ associatedDevice = dev->associatedDevice;
+ // Reload this associated device if needed.
+ const auto reloadedDevice = AssociatedDevice(path);
+ if (reloadedDevice != *dev->associatedDevice) {
+ ALOGI("The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s",
+ path.c_str(), associatedDevice->dump().c_str());
+ associatedDevice = std::make_shared<AssociatedDevice>(std::move(reloadedDevice));
+ }
+ }
+ // Update the associatedDevice.
+ dev->associatedDevice = associatedDevice;
}
- ALOGI_IF(associatedDeviceChanged,
- "The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s",
- path.c_str(), associatedDevice->dump().c_str());
+
+ if (!associatedDevice) {
+ // No existing associated device found for this path, so create a new one.
+ associatedDevice = std::make_shared<AssociatedDevice>(path);
+ }
return associatedDevice;
}
-bool EventHub::AssociatedDevice::isChanged() const {
- std::unordered_map<int32_t, RawBatteryInfo> newBatteryInfos =
- readBatteryConfiguration(sysfsRootPath);
- std::unordered_map<int32_t, RawLightInfo> newLightInfos =
- readLightsConfiguration(sysfsRootPath);
- std::optional<RawLayoutInfo> newLayoutInfo = readLayoutConfiguration(sysfsRootPath);
+EventHub::AssociatedDevice::AssociatedDevice(const std::filesystem::path& sysfsRootPath)
+ : sysfsRootPath(sysfsRootPath),
+ batteryInfos(readBatteryConfiguration(sysfsRootPath)),
+ lightInfos(readLightsConfiguration(sysfsRootPath)),
+ layoutInfo(readLayoutConfiguration(sysfsRootPath)) {}
- if (newBatteryInfos == batteryInfos && newLightInfos == lightInfos &&
- newLayoutInfo == layoutInfo) {
- return false;
- }
- return true;
+std::string EventHub::AssociatedDevice::dump() const {
+ return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(),
+ batteryInfos.size(), lightInfos.size());
}
void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
@@ -2646,33 +2648,56 @@
void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) {
std::scoped_lock _l(mLock);
- // Check in opening devices
- for (auto it = mOpeningDevices.begin(); it != mOpeningDevices.end(); it++) {
- std::unique_ptr<Device>& device = *it;
- if (device->associatedDevice &&
- sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
- std::string::npos &&
- device->associatedDevice->isChanged()) {
- it = mOpeningDevices.erase(it);
- openDeviceLocked(device->path);
+ // Testing whether a sysfs node changed involves several syscalls, so use a cache to avoid
+ // testing the same node multiple times.
+ std::map<std::shared_ptr<const AssociatedDevice>, bool /*changed*/> testedDevices;
+ auto isAssociatedDeviceChanged = [&testedDevices, &sysfsNodePath](const Device& dev) {
+ if (!dev.associatedDevice) {
+ return false;
+ }
+ if (auto testedIt = testedDevices.find(dev.associatedDevice);
+ testedIt != testedDevices.end()) {
+ return testedIt->second;
+ }
+ // Cache miss
+ if (sysfsNodePath.find(dev.associatedDevice->sysfsRootPath.string()) == std::string::npos) {
+ testedDevices.emplace(dev.associatedDevice, false);
+ return false;
+ }
+ auto reloadedDevice = AssociatedDevice(dev.associatedDevice->sysfsRootPath);
+ const bool changed = *dev.associatedDevice != reloadedDevice;
+ testedDevices.emplace(dev.associatedDevice, changed);
+ return changed;
+ };
+
+ std::set<Device*> devicesToClose;
+ std::set<std::string /*path*/> devicesToOpen;
+
+ // Check in opening devices. If its associated device changed,
+ // the device should be removed from mOpeningDevices and needs to be opened again.
+ std::erase_if(mOpeningDevices, [&](const auto& dev) {
+ if (isAssociatedDeviceChanged(*dev)) {
+ devicesToOpen.emplace(dev->path);
+ return true;
+ }
+ return false;
+ });
+
+ // Check in already added device. If its associated device changed,
+ // the device needs to be re-opened.
+ for (const auto& [id, dev] : mDevices) {
+ if (isAssociatedDeviceChanged(*dev)) {
+ devicesToOpen.emplace(dev->path);
+ devicesToClose.emplace(dev.get());
}
}
- // Check in already added device
- std::vector<Device*> devicesToReopen;
- for (const auto& [id, device] : mDevices) {
- if (device->associatedDevice &&
- sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
- std::string::npos &&
- device->associatedDevice->isChanged()) {
- devicesToReopen.push_back(device.get());
- }
- }
- for (const auto& device : devicesToReopen) {
+ for (auto* device : devicesToClose) {
closeDeviceLocked(*device);
- openDeviceLocked(device->path);
}
- devicesToReopen.clear();
+ for (const auto& path : devicesToOpen) {
+ openDeviceLocked(path);
+ }
}
void EventHub::createVirtualKeyboardLocked() {
@@ -2972,9 +2997,4 @@
std::unique_lock<std::mutex> lock(mLock);
}
-std::string EventHub::AssociatedDevice::dump() const {
- return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(),
- batteryInfos.size(), lightInfos.size());
-}
-
} // namespace android
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 207806d..7ab000b 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -62,6 +62,28 @@
identifier1.location == identifier2.location);
}
+/**
+ * Determines if the device classes passed for two devices represent incompatible combinations
+ * that should not be merged into into a single InputDevice.
+ */
+
+bool isCompatibleSubDevice(ftl::Flags<InputDeviceClass> classes1,
+ ftl::Flags<InputDeviceClass> classes2) {
+ if (!com::android::input::flags::prevent_merging_input_pointer_devices()) {
+ return true;
+ }
+
+ const ftl::Flags<InputDeviceClass> pointerFlags =
+ ftl::Flags<InputDeviceClass>{InputDeviceClass::TOUCH, InputDeviceClass::TOUCH_MT,
+ InputDeviceClass::CURSOR, InputDeviceClass::TOUCHPAD};
+
+ // Do not merge devices that both have any type of pointer event.
+ if (classes1.any(pointerFlags) && classes2.any(pointerFlags)) return false;
+
+ // Safe to merge
+ return true;
+}
+
bool isStylusPointerGestureStart(const NotifyMotionArgs& motionArgs) {
const auto actionMasked = MotionEvent::getActionMasked(motionArgs.action);
if (actionMasked != AMOTION_EVENT_ACTION_HOVER_ENTER &&
@@ -271,7 +293,8 @@
}
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
- std::shared_ptr<InputDevice> device = createDeviceLocked(when, eventHubId, identifier);
+ ftl::Flags<InputDeviceClass> classes = mEventHub->getDeviceClasses(eventHubId);
+ std::shared_ptr<InputDevice> device = createDeviceLocked(when, eventHubId, identifier, classes);
mPendingArgs += device->configure(when, mConfig, /*changes=*/{});
mPendingArgs += device->reset(when);
@@ -354,12 +377,16 @@
}
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
- nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier) {
- auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
- const InputDeviceIdentifier identifier2 =
- devicePair.second->getDeviceInfo().getIdentifier();
- return isSubDevice(identifier, identifier2);
- });
+ nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier,
+ ftl::Flags<InputDeviceClass> classes) {
+ auto deviceIt =
+ std::find_if(mDevices.begin(), mDevices.end(), [identifier, classes](auto& devicePair) {
+ const InputDeviceIdentifier identifier2 =
+ devicePair.second->getDeviceInfo().getIdentifier();
+ const ftl::Flags<InputDeviceClass> classes2 = devicePair.second->getClasses();
+ return isSubDevice(identifier, identifier2) &&
+ isCompatibleSubDevice(classes, classes2);
+ });
std::shared_ptr<InputDevice> device;
if (deviceIt != mDevices.end()) {
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 5839b4c..31ac63f 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -619,13 +619,13 @@
private:
// Holds information about the sysfs device associated with the Device.
struct AssociatedDevice {
+ AssociatedDevice(const std::filesystem::path& sysfsRootPath);
// The sysfs root path of the misc device.
std::filesystem::path sysfsRootPath;
std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos;
std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
std::optional<RawLayoutInfo> layoutInfo;
- bool isChanged() const;
bool operator==(const AssociatedDevice&) const = default;
bool operator!=(const AssociatedDevice&) const = default;
std::string dump() const;
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 931766b..0d6e102 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -25,6 +25,7 @@
#include <vector>
#include "EventHub.h"
+#include "InputDevice.h"
#include "InputListener.h"
#include "InputReaderBase.h"
#include "InputReaderContext.h"
@@ -127,7 +128,8 @@
protected:
// These members are protected so they can be instrumented by test cases.
virtual std::shared_ptr<InputDevice> createDeviceLocked(nsecs_t when, int32_t deviceId,
- const InputDeviceIdentifier& identifier)
+ const InputDeviceIdentifier& identifier,
+ ftl::Flags<InputDeviceClass> classes)
REQUIRES(mLock);
// With each iteration of the loop, InputReader reads and processes one incoming message from
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index d9a75a5..43d2378 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1405,6 +1405,68 @@
ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(3), false);
}
+TEST_F(InputReaderTest, MergeableInputDevices) {
+ constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
+
+ // By default, all of the default-created eventhub devices will have the same identifier
+ // (implicitly vid 0, pid 0, etc.), which is why we expect them to be merged.
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::JOYSTICK, nullptr));
+
+ // The two devices will be merged to one input device as they have same identifier, and none are
+ // pointer devices.
+ ASSERT_EQ(1U, mFakePolicy->getInputDevices().size());
+}
+
+TEST_F(InputReaderTest, MergeableDevicesWithTouch) {
+ constexpr int32_t eventHubIds[3] = {END_RESERVED_ID, END_RESERVED_ID + 1, END_RESERVED_ID + 2};
+
+ // By default, all of the default-created eventhub devices will have the same identifier
+ // (implicitly vid 0, pid 0, etc.), which is why we expect them to be merged.
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::TOUCH_MT, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::KEYBOARD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[2], "3rd", InputDeviceClass::GAMEPAD, nullptr));
+
+ // The three devices will be merged to one input device as they have same identifier, and only
+ // one is a pointer device.
+ ASSERT_EQ(1U, mFakePolicy->getInputDevices().size());
+}
+
+TEST_F(InputReaderTest, UnmergeableTouchDevices) {
+ SCOPED_FLAG_OVERRIDE(prevent_merging_input_pointer_devices, true);
+
+ constexpr int32_t eventHubIds[3] = {END_RESERVED_ID, END_RESERVED_ID + 1, END_RESERVED_ID + 2};
+
+ // By default, all of the default-created eventhub devices will have the same identifier
+ // (implicitly vid 0, pid 0, etc.), which is why they can potentially be merged.
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::TOUCH, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::TOUCH_MT, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[2], "2nd", InputDeviceClass::CURSOR, nullptr));
+
+ // The three devices will not be merged, as they have same identifier, but are all pointer
+ // devices.
+ ASSERT_EQ(3U, mFakePolicy->getInputDevices().size());
+}
+
+TEST_F(InputReaderTest, MergeableMixedDevices) {
+ SCOPED_FLAG_OVERRIDE(prevent_merging_input_pointer_devices, true);
+
+ constexpr int32_t eventHubIds[4] = {END_RESERVED_ID, END_RESERVED_ID + 1, END_RESERVED_ID + 2,
+ END_RESERVED_ID + 3};
+
+ // By default, all of the default-created eventhub devices will have the same identifier
+ // (implicitly vid 0, pid 0, etc.), which is why they can potentially be merged.
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::TOUCH, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::TOUCH_MT, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[2], "3rd", InputDeviceClass::DPAD, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[3], "4th", InputDeviceClass::JOYSTICK, nullptr));
+
+ // Non-touch devices can be merged with one of the touch devices, as they have same identifier,
+ // but the two touch devices will not combine with each other. It is not specified which touch
+ // device the non-touch devices merge with.
+ ASSERT_EQ(2U, mFakePolicy->getInputDevices().size());
+}
+
// --- InputReaderIntegrationTest ---
// These tests create and interact with the InputReader only through its interface.
diff --git a/services/inputflinger/tests/InstrumentedInputReader.cpp b/services/inputflinger/tests/InstrumentedInputReader.cpp
index 110ca5f..53fc8a1 100644
--- a/services/inputflinger/tests/InstrumentedInputReader.cpp
+++ b/services/inputflinger/tests/InstrumentedInputReader.cpp
@@ -38,13 +38,14 @@
}
std::shared_ptr<InputDevice> InstrumentedInputReader::createDeviceLocked(
- nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier) REQUIRES(mLock) {
+ nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier,
+ ftl::Flags<InputDeviceClass> classes) REQUIRES(mLock) {
if (!mNextDevices.empty()) {
std::shared_ptr<InputDevice> device(std::move(mNextDevices.front()));
mNextDevices.pop();
return device;
}
- return InputReader::createDeviceLocked(when, eventHubId, identifier);
+ return InputReader::createDeviceLocked(when, eventHubId, identifier, classes);
}
} // namespace android
diff --git a/services/inputflinger/tests/InstrumentedInputReader.h b/services/inputflinger/tests/InstrumentedInputReader.h
index e9c7bb4..9abf30c 100644
--- a/services/inputflinger/tests/InstrumentedInputReader.h
+++ b/services/inputflinger/tests/InstrumentedInputReader.h
@@ -43,8 +43,9 @@
using InputReader::loopOnce;
protected:
- virtual std::shared_ptr<InputDevice> createDeviceLocked(
- nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier);
+ virtual std::shared_ptr<InputDevice> createDeviceLocked(nsecs_t when, int32_t eventHubId,
+ const InputDeviceIdentifier& identifier,
+ ftl::Flags<InputDeviceClass> classes);
class FakeInputReaderContext : public ContextImpl {
public:
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
index 880df08..f38cf5a 100644
--- a/services/sensorservice/aidl/fuzzer/Android.bp
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -22,6 +22,7 @@
"android.hardware.sensors-V1-convert",
"android.hardware.sensors-V3-ndk",
"android.hardware.common-V2-ndk",
+ "framework-permission-aidl-cpp",
"libsensor",
"libfakeservicemanager",
"libcutils",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 88ff370..9aa1ffa 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -93,7 +93,6 @@
"iinputflinger_aidl_lib_static",
"libaidlcommonsupport",
"libcompositionengine",
- "libframetimeline",
"libgui_aidl_static",
"libperfetto_client_experimental",
"librenderengine",
@@ -208,6 +207,7 @@
"DisplayDevice.cpp",
"Effects/Daltonizer.cpp",
"FpsReporter.cpp",
+ "FrameTimeline/FrameTimeline.cpp",
"FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"FrontEnd/LayerCreationArgs.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e876693..780758e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -19,6 +19,7 @@
#include <optional>
#include <ostream>
#include <unordered_set>
+#include "aidl/android/hardware/graphics/composer3/Composition.h"
#include "ui/LayerStack.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -36,10 +37,6 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
-namespace aidl::android::hardware::graphics::composer3 {
-enum class Composition;
-}
-
namespace android {
class Fence;
@@ -182,10 +179,27 @@
// Whether the layer should be rendered with rounded corners.
virtual bool hasRoundedCorners() const = 0;
virtual void setWasClientComposed(const sp<Fence>&) {}
- virtual void setHwcCompositionType(
- aidl::android::hardware::graphics::composer3::Composition) = 0;
- virtual aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType()
- const = 0;
+
+ // These fields are all copied from the last written HWC state.
+ // This state is only used for debugging purposes.
+ struct HwcLayerDebugState {
+ aidl::android::hardware::graphics::composer3::Composition lastCompositionType =
+ aidl::android::hardware::graphics::composer3::Composition::INVALID;
+ // Corresponds to passing an alpha of 0 to HWC2::Layer::setPlaneAlpha.
+ bool wasSkipped = false;
+
+ // Indicates whether the compositionengine::OutputLayer had properties overwritten.
+ // Not directly passed to HWC.
+ bool wasOverridden = false;
+
+ // Corresponds to the GraphicBuffer ID of the buffer passed to HWC2::Layer::setBuffer.
+ // This buffer corresponds to a CachedSet that the LayerFE was flattened to.
+ uint64_t overrideBufferId = 0;
+ };
+
+ // Used for debugging purposes, e.g. perfetto tracing, dumpsys.
+ virtual void setLastHwcState(const LayerFE::HwcLayerDebugState &hwcState) = 0;
+ virtual const HwcLayerDebugState &getLastHwcState() const = 0;
virtual const gui::LayerMetadata* getMetadata() const = 0;
virtual const gui::LayerMetadata* getRelativeMetadata() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 0063eee..a1434f2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -104,7 +104,7 @@
void detectDisallowedCompositionTypeChange(
aidl::android::hardware::graphics::composer3::Composition from,
aidl::android::hardware::graphics::composer3::Composition to) const;
- bool isClientCompositionForced(bool isPeekingThrough) const;
+ bool isClientCompositionForced(bool isPeekingThrough, bool isCached) const;
void updateLuts(const LayerFECompositionState&,
const std::optional<std::vector<std::optional<LutProperties>>>& properties);
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 7744b8b..d2a5a20 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -59,9 +59,9 @@
MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*());
MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*());
MOCK_METHOD0(onPictureProfileCommitted, void());
- MOCK_METHOD(void, setHwcCompositionType,
- (aidl::android::hardware::graphics::composer3::Composition), (override));
- MOCK_METHOD(aidl::android::hardware::graphics::composer3::Composition, getHwcCompositionType,
+ MOCK_METHOD(void, setLastHwcState,
+ (const HwcLayerDebugState&), (override));
+ MOCK_METHOD(const HwcLayerDebugState&, getLastHwcState,
(), (const, override));
};
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 9b66f01..d89b52d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -502,6 +502,15 @@
editState().hwc->stateOverridden = isOverridden;
editState().hwc->layerSkipped = skipLayer;
+
+
+ // Save the final HWC state for debugging purposes, e.g. perfetto tracing, dumpsys.
+ getLayerFE().setLastHwcState({.lastCompositionType = editState().hwc->hwcCompositionType,
+ .wasSkipped = skipLayer,
+ .wasOverridden = isOverridden,
+ .overrideBufferId = editState().overrideInfo.buffer
+ ? editState().overrideInfo.buffer.get()->getId()
+ : 0});
}
void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer,
@@ -856,7 +865,8 @@
bool isPeekingThrough, bool skipLayer) {
auto& outputDependentState = editState();
- if (isClientCompositionForced(isPeekingThrough)) {
+ bool isCached = !skipLayer && outputDependentState.overrideInfo.buffer;
+ if (isClientCompositionForced(isPeekingThrough, isCached)) {
// If we are forcing client composition, we need to tell the HWC
requestedCompositionType = Composition::CLIENT;
}
@@ -867,7 +877,6 @@
if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType ||
(outputDependentState.hwc->layerSkipped && !skipLayer)) {
outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
- getLayerFE().setHwcCompositionType(requestedCompositionType);
if (auto error = hwcLayer->setCompositionType(requestedCompositionType);
error != hal::Error::NONE) {
@@ -947,9 +956,12 @@
}
}
-bool OutputLayer::isClientCompositionForced(bool isPeekingThrough) const {
+bool OutputLayer::isClientCompositionForced(bool isPeekingThrough, bool isCached) const {
+ // If this layer was flattened into a CachedSet then it is not necessary for
+ // the GPU to compose it.
+ bool requiresClientDrawnRoundedCorners = !isCached && getLayerFE().hasRoundedCorners();
return getState().forceClientComposition ||
- (!isPeekingThrough && getLayerFE().hasRoundedCorners());
+ (!isPeekingThrough && requiresClientDrawnRoundedCorners);
}
void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) {
@@ -965,7 +977,13 @@
}
hwcState.hwcCompositionType = compositionType;
- getLayerFE().setHwcCompositionType(compositionType);
+
+ getLayerFE().setLastHwcState({.lastCompositionType = hwcState.hwcCompositionType,
+ .wasSkipped = hwcState.layerSkipped,
+ .wasOverridden = hwcState.stateOverridden,
+ .overrideBufferId = state.overrideInfo.buffer
+ ? state.overrideInfo.buffer.get()->getId()
+ : 0});
}
void OutputLayer::prepareForDeviceLayerRequests() {
diff --git a/services/surfaceflinger/FrameTimeline/Android.bp b/services/surfaceflinger/FrameTimeline/Android.bp
deleted file mode 100644
index 8e28cc3..0000000
--- a/services/surfaceflinger/FrameTimeline/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
- default_team: "trendy_team_android_core_graphics_stack",
-}
-
-cc_library_static {
- name: "libframetimeline",
- defaults: ["surfaceflinger_defaults"],
- srcs: [
- "FrameTimeline.cpp",
- ],
- header_libs: [
- "libscheduler_headers",
- ],
- shared_libs: [
- "android.hardware.graphics.composer@2.4",
- "libbase",
- "libcutils",
- "liblog",
- "libgui",
- "libtimestats",
- "libui",
- "libutils",
- ],
- static_libs: [
- "libperfetto_client_experimental",
- "libsurfaceflinger_common",
- ],
- export_include_dirs: ["."],
-}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 523ef7b..1514340 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -403,11 +403,8 @@
if (forceUpdate || requested.what & layer_state_t::eSidebandStreamChanged) {
sidebandStream = requested.sidebandStream;
}
- if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged ||
- requested.what & layer_state_t::eClientDrawnShadowsChanged) {
- shadowSettings.length =
- requested.clientDrawnShadowRadius > 0 ? 0.f : requested.shadowRadius;
- shadowSettings.clientDrawnLength = requested.clientDrawnShadowRadius;
+ if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged) {
+ shadowSettings.length = requested.shadowRadius;
}
if (forceUpdate || requested.what & layer_state_t::eFrameRateSelectionPriority) {
@@ -537,16 +534,17 @@
}
}
-char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) const {
+char LayerSnapshot::classifyCompositionForDebug(
+ const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const {
if (!isVisible) {
return '.';
}
- switch (compositionType) {
+ switch (hwcState.lastCompositionType) {
case Composition::INVALID:
return 'i';
case Composition::SOLID_COLOR:
- return 'c';
+ return 'e';
case Composition::CURSOR:
return 'u';
case Composition::SIDEBAND:
@@ -554,28 +552,28 @@
case Composition::DISPLAY_DECORATION:
return 'a';
case Composition::REFRESH_RATE_INDICATOR:
- return 'r';
+ return 'f';
case Composition::CLIENT:
case Composition::DEVICE:
break;
}
char code = '.'; // Default to invisible
- if (hasBufferOrSidebandStream()) {
- code = 'b';
- } else if (fillsColor()) {
- code = 'c'; // Solid color
- } else if (hasBlur()) {
+ if (hasBlur()) {
code = 'l'; // Blur
} else if (hasProtectedContent) {
code = 'p'; // Protected content
- } else if (drawShadows()) {
- code = 's'; // Shadow
} else if (roundedCorner.hasRoundedCorners()) {
code = 'r'; // Rounded corners
+ } else if (drawShadows()) {
+ code = 's'; // Shadow
+ } else if (fillsColor()) {
+ code = 'c'; // Solid color
+ } else if (hasBufferOrSidebandStream()) {
+ code = 'b';
}
- if (compositionType == Composition::CLIENT) {
+ if (hwcState.lastCompositionType == Composition::CLIENT) {
return static_cast<char>(std::toupper(code));
} else {
return code;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 04b9f3b..69120bd 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -24,6 +24,7 @@
#include "RequestedLayerState.h"
#include "Scheduler/LayerInfo.h"
#include "android-base/stringprintf.h"
+#include "compositionengine/LayerFE.h"
namespace android::surfaceflinger::frontend {
@@ -163,7 +164,7 @@
// Returns a char summarizing the composition request
// This function tries to maintain parity with planner::Plan chars.
char classifyCompositionForDebug(
- aidl::android::hardware::graphics::composer3::Composition compositionType) const;
+ const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const;
};
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 1d53e71..58c235e 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -108,7 +108,6 @@
surfaceDamageRegion = Region::INVALID_REGION;
cornerRadius = 0.0f;
clientDrawnCornerRadius = 0.0f;
- clientDrawnShadowRadius = 0.0f;
backgroundBlurRadius = 0;
api = -1;
hasColorTransform = false;
@@ -355,11 +354,6 @@
clientDrawnCornerRadius = clientState.clientDrawnCornerRadius;
changes |= RequestedLayerState::Changes::Geometry;
}
-
- if (clientState.what & layer_state_t::eClientDrawnShadowsChanged) {
- clientDrawnShadowRadius = clientState.clientDrawnShadowRadius;
- changes |= RequestedLayerState::Changes::Geometry;
- }
}
ui::Size RequestedLayerState::getUnrotatedBufferSize(uint32_t displayRotationFlags) const {
@@ -646,7 +640,6 @@
layer_state_t::eColorTransformChanged | layer_state_t::eBackgroundColorChanged |
layer_state_t::eMatrixChanged | layer_state_t::eCornerRadiusChanged |
layer_state_t::eClientDrawnCornerRadiusChanged |
- layer_state_t::eClientDrawnShadowsChanged |
layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBufferTransformChanged |
layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged |
layer_state_t::eDataspaceChanged | layer_state_t::eHdrMetadataChanged |
diff --git a/services/surfaceflinger/Jank/JankTracker.cpp b/services/surfaceflinger/Jank/JankTracker.cpp
index 8e0e084..5e6267d 100644
--- a/services/surfaceflinger/Jank/JankTracker.cpp
+++ b/services/surfaceflinger/Jank/JankTracker.cpp
@@ -88,7 +88,8 @@
}
void JankTracker::addJankListenerLocked(int32_t layerId, sp<IBinder> listener) {
- for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
+ auto range = mJankListeners.equal_range(layerId);
+ for (auto it = range.first; it != range.second; it++) {
if (it->second.mListener == listener) {
// Undo the duplicate increment in addJankListener.
sListenerCount--;
@@ -106,7 +107,8 @@
std::vector<sp<IBinder>> toSend;
mLock.lock();
- for (auto it = mJankListeners.find(layerId); it != mJankListeners.end();) {
+ auto range = mJankListeners.equal_range(layerId);
+ for (auto it = range.first; it != range.second;) {
if (!jankData.empty()) {
toSend.emplace_back(it->second.mListener);
}
@@ -133,7 +135,8 @@
void JankTracker::markJankListenerForRemovalLocked(int32_t layerId, sp<IBinder> listener,
int64_t afterVysnc) {
- for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
+ auto range = mJankListeners.equal_range(layerId);
+ for (auto it = range.first; it != range.second; it++) {
if (it->second.mListener == listener) {
it->second.mRemoveAfter = std::max(static_cast<int64_t>(0), afterVysnc);
return;
@@ -156,7 +159,8 @@
void JankTracker::dropJankListener(int32_t layerId, sp<IBinder> listener) {
const std::lock_guard<std::mutex> _l(mLock);
- for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
+ auto range = mJankListeners.equal_range(layerId);
+ for (auto it = range.first; it != range.second; it++) {
if (it->second.mListener == listener) {
mJankListeners.erase(it);
sListenerCount--;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 195461f..e1bba44 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -64,7 +64,7 @@
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
#include "FrameTracer/FrameTracer.h"
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHandle.h"
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index 725a782..b619268 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -428,13 +428,12 @@
return mReleaseFencePromiseStatus;
}
-void LayerFE::setHwcCompositionType(
- aidl::android::hardware::graphics::composer3::Composition type) {
- mLastHwcCompositionType = type;
+void LayerFE::setLastHwcState(const LayerFE::HwcLayerDebugState &state) {
+ mLastHwcState = state;
}
-aidl::android::hardware::graphics::composer3::Composition LayerFE::getHwcCompositionType() const {
- return mLastHwcCompositionType;
-}
+const LayerFE::HwcLayerDebugState& LayerFE::getLastHwcState() const {
+ return mLastHwcState;
+};
} // namespace android
diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h
index 64ec278..a537456 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -59,9 +59,10 @@
void setReleaseFence(const FenceResult& releaseFence) override;
LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override;
void onPictureProfileCommitted() override;
- void setHwcCompositionType(aidl::android::hardware::graphics::composer3::Composition) override;
- aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType()
- const override;
+
+ // Used for debugging purposes, e.g. perfetto tracing, dumpsys.
+ void setLastHwcState(const HwcLayerDebugState &state) override;
+ const HwcLayerDebugState &getLastHwcState() const override;
std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot;
@@ -93,8 +94,7 @@
std::string mName;
std::promise<FenceResult> mReleaseFence;
ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED;
- aidl::android::hardware::graphics::composer3::Composition mLastHwcCompositionType =
- aidl::android::hardware::graphics::composer3::Composition::INVALID;
+ HwcLayerDebugState mLastHwcState;
};
} // namespace android
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index fa0ecee..13edd16 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -12,6 +12,5 @@
ramindani@google.com
rnlee@google.com
sallyqi@google.com
-scroggo@google.com
vishnun@google.com
xwxw@google.com
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 1c4a11a..514adac 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -356,12 +356,10 @@
screenshotArgs.seamlessTransition = false;
std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
- auto displayState =
- mFlinger.getSnapshotsFromMainThread(screenshotArgs, getLayerSnapshotsFn, layers);
- FenceResult fenceResult =
- mFlinger.captureScreenshot(screenshotArgs, buffer, kRegionSampling, kGrayscale,
- kIsProtected, nullptr, displayState, layers)
- .get();
+ mFlinger.getSnapshotsFromMainThread(screenshotArgs, getLayerSnapshotsFn, layers);
+ FenceResult fenceResult = mFlinger.captureScreenshot(screenshotArgs, buffer, kRegionSampling,
+ kGrayscale, kIsProtected, nullptr, layers)
+ .get();
if (fenceResult.ok()) {
fenceResult.value()->waitForever(LOG_TAG);
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 0efc396..c37b965 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -45,7 +45,7 @@
#include <common/FlagManager.h>
#include <scheduler/FrameRateMode.h>
#include <scheduler/VsyncConfig.h>
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
#include "VSyncDispatch.h"
#include "EventThread.h"
@@ -86,36 +86,43 @@
std::string toString(const DisplayEventReceiver::Event& event) {
switch (event.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ case DisplayEventType::DISPLAY_EVENT_HOTPLUG:
return StringPrintf("Hotplug{displayId=%s, %s}",
to_string(event.header.displayId).c_str(),
event.hotplug.connected ? "connected" : "disconnected");
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ case DisplayEventType::DISPLAY_EVENT_VSYNC:
return StringPrintf("VSync{displayId=%s, count=%u, expectedPresentationTime=%" PRId64
"}",
to_string(event.header.displayId).c_str(), event.vsync.count,
event.vsync.vsyncData.preferredExpectedPresentationTime());
- case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
+ case DisplayEventType::DISPLAY_EVENT_MODE_CHANGE:
return StringPrintf("ModeChanged{displayId=%s, modeId=%u}",
to_string(event.header.displayId).c_str(), event.modeChange.modeId);
- case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
+ case DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
return StringPrintf("HdcpLevelsChange{displayId=%s, connectedLevel=%d, maxLevel=%d}",
to_string(event.header.displayId).c_str(),
event.hdcpLevelsChange.connectedLevel,
event.hdcpLevelsChange.maxLevel);
- case DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION:
+ case DisplayEventType::DISPLAY_EVENT_MODE_REJECTION:
return StringPrintf("ModeRejected{displayId=%s, modeId=%u}",
to_string(event.header.displayId).c_str(),
event.modeRejection.modeId);
- default:
- return "Event{}";
+ case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+ return StringPrintf("FrameRateOverride{displayId=%s, frameRateHz=%f}",
+ to_string(event.header.displayId).c_str(),
+ event.frameRateOverride.frameRateHz);
+ case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+ return StringPrintf("FrameRateOverrideFlush{displayId=%s}",
+ to_string(event.header.displayId).c_str());
+ case DisplayEventType::DISPLAY_EVENT_NULL:
+ return "NULL";
}
}
DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t timestamp,
bool connected) {
DisplayEventReceiver::Event event;
- event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
+ event.header = {DisplayEventType::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
event.hotplug.connected = connected;
return event;
}
@@ -123,7 +130,7 @@
DisplayEventReceiver::Event makeHotplugError(nsecs_t timestamp, int32_t connectionError) {
DisplayEventReceiver::Event event;
PhysicalDisplayId unusedDisplayId;
- event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, unusedDisplayId, timestamp};
+ event.header = {DisplayEventType::DISPLAY_EVENT_HOTPLUG, unusedDisplayId, timestamp};
event.hotplug.connected = false;
event.hotplug.connectionError = connectionError;
return event;
@@ -133,7 +140,7 @@
uint32_t count, nsecs_t expectedPresentationTime,
nsecs_t deadlineTimestamp) {
DisplayEventReceiver::Event event;
- event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
+ event.header = {DisplayEventType::DISPLAY_EVENT_VSYNC, displayId, timestamp};
event.vsync.count = count;
event.vsync.vsyncData.preferredFrameTimelineIndex = 0;
// Temporarily store the current vsync information in frameTimelines[0], marked as
@@ -148,7 +155,7 @@
DisplayEventReceiver::Event makeModeChanged(const scheduler::FrameRateMode& mode) {
DisplayEventReceiver::Event event;
- event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
+ event.header = {DisplayEventType::DISPLAY_EVENT_MODE_CHANGE,
mode.modePtr->getPhysicalDisplayId(), systemTime()};
event.modeChange.modeId = ftl::to_underlying(mode.modePtr->getId());
event.modeChange.vsyncPeriod = mode.fps.getPeriodNsecs();
@@ -160,7 +167,7 @@
return DisplayEventReceiver::Event{
.header =
DisplayEventReceiver::Event::Header{
- .type = DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
+ .type = DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
.displayId = displayId,
.timestamp = systemTime(),
},
@@ -171,7 +178,7 @@
DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId displayId) {
return DisplayEventReceiver::Event{
.header = DisplayEventReceiver::Event::Header{
- .type = DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
+ .type = DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
.displayId = displayId,
.timestamp = systemTime(),
}};
@@ -182,7 +189,7 @@
return DisplayEventReceiver::Event{
.header =
DisplayEventReceiver::Event::Header{
- .type = DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE,
+ .type = DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE,
.displayId = displayId,
.timestamp = systemTime(),
},
@@ -195,7 +202,7 @@
return DisplayEventReceiver::Event{
.header =
DisplayEventReceiver::Event::Header{
- .type = DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION,
+ .type = DisplayEventType::DISPLAY_EVENT_MODE_REJECTION,
.displayId = displayId,
.timestamp = systemTime(),
},
@@ -263,10 +270,10 @@
return size < 0 ? status_t(size) : status_t(NO_ERROR);
};
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE ||
- event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
+ if (event.header.type == DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE ||
+ event.header.type == DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
mPendingEvents.emplace_back(event);
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
+ if (event.header.type == DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
return status_t(NO_ERROR);
}
@@ -524,7 +531,7 @@
event = mPendingEvents.front();
mPendingEvents.pop_front();
- if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
+ if (event->header.type == DisplayEventType::DISPLAY_EVENT_HOTPLUG) {
if (event->hotplug.connectionError == 0) {
if (event->hotplug.connected && !mVSyncState) {
mVSyncState.emplace();
@@ -636,18 +643,21 @@
};
switch (event.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ case DisplayEventType::DISPLAY_EVENT_HOTPLUG:
return true;
- case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
+ case DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
return true;
- case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
+ case DisplayEventType::DISPLAY_EVENT_MODE_CHANGE: {
return connection->mEventRegistration.test(
gui::ISurfaceComposer::EventRegistration::modeChanged);
}
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ case DisplayEventType::DISPLAY_EVENT_MODE_REJECTION:
+ return true;
+
+ case DisplayEventType::DISPLAY_EVENT_VSYNC:
switch (connection->vsyncRequest) {
case VSyncRequest::None:
return false;
@@ -673,13 +683,12 @@
return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
}
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+ case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
[[fallthrough]];
- case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+ case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
return connection->mEventRegistration.test(
gui::ISurfaceComposer::EventRegistration::frameRateOverride);
-
- default:
+ case DisplayEventType::DISPLAY_EVENT_NULL:
return false;
}
}
@@ -758,7 +767,7 @@
ftl::SmallVector<uid_t, 10> uidsPostedQueuedBuffers;
for (const auto& consumer : consumers) {
DisplayEventReceiver::Event copy = event;
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ if (event.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC) {
const Period frameInterval = mCallback.getVsyncPeriod(consumer->mOwnerUid);
copy.vsync.vsyncData.frameInterval = frameInterval.ns();
generateFrameTimeline(copy.vsync.vsyncData, frameInterval.ns(), copy.header.timestamp,
@@ -793,7 +802,7 @@
for (auto uid : uidsPostedQueuedBuffers) {
mBufferStuffedUids.erase(uid);
}
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC &&
+ if (event.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC &&
FlagManager::getInstance().vrr_config()) {
mLastCommittedVsyncTime =
TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime());
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 2e1f938..91a798e 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -24,7 +24,7 @@
#include <scheduler/interface/ICompositor.h>
#include "EventThread.h"
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
#include "MessageQueue.h"
namespace android::impl {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0d0246f..574d39a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2977,6 +2977,8 @@
int index = 0;
ftl::StaticVector<char, WorkloadTracer::COMPOSITION_SUMMARY_SIZE> compositionSummary;
auto lastLayerStack = ui::INVALID_LAYER_STACK;
+
+ uint64_t prevOverrideBufferId = 0;
for (auto& [layer, layerFE] : layers) {
CompositionResult compositionResult{layerFE->stealCompositionResult()};
if (lastLayerStack != layerFE->mSnapshot->outputFilter.layerStack) {
@@ -2986,8 +2988,37 @@
}
lastLayerStack = layerFE->mSnapshot->outputFilter.layerStack;
}
+
+ // If there are N layers in a cached set they should all share the same buffer id.
+ // The first layer in the cached set will be not skipped and layers 1..N-1 will be skipped.
+ // We expect all layers in the cached set to be marked as composited by HWC.
+ // Here is a made up example of how it is visualized
+ //
+ // [b:rrc][s:cc]
+ //
+ // This should be interpreted to mean that there are 2 cached sets.
+ // So there are only 2 non skipped layers -- b and s.
+ // The layers rrc and cc are flattened into layers b and s respectively.
+ const LayerFE::HwcLayerDebugState &hwcState = layerFE->getLastHwcState();
+ if (hwcState.overrideBufferId != prevOverrideBufferId) {
+ // End the existing run.
+ if (prevOverrideBufferId) {
+ compositionSummary.push_back(']');
+ }
+ // Start a new run.
+ if (hwcState.overrideBufferId) {
+ compositionSummary.push_back('[');
+ }
+ }
+
compositionSummary.push_back(
- layerFE->mSnapshot->classifyCompositionForDebug(layerFE->getHwcCompositionType()));
+ layerFE->mSnapshot->classifyCompositionForDebug(hwcState));
+
+ if (hwcState.overrideBufferId && !hwcState.wasSkipped) {
+ compositionSummary.push_back(':');
+ }
+ prevOverrideBufferId = hwcState.overrideBufferId;
+
if (layerFE->mSnapshot->hasEffect()) {
compositedWorkload |= adpf::Workload::EFFECTS;
}
@@ -2999,6 +3030,10 @@
mActivePictureTracker.onLayerComposed(*layer, *layerFE, compositionResult);
}
}
+ // End the last run.
+ if (prevOverrideBufferId) {
+ compositionSummary.push_back(']');
+ }
// Concisely describe the layers composited this frame using single chars. GPU composited layers
// are uppercase, DPU composited are lowercase. Special chars denote effects (blur, shadow,
@@ -7163,14 +7198,13 @@
namespace {
-ui::Dataspace pickBestDataspace(ui::Dataspace requestedDataspace,
- const compositionengine::impl::OutputCompositionState& state,
+ui::Dataspace pickBestDataspace(ui::Dataspace requestedDataspace, ui::ColorMode colorMode,
bool capturingHdrLayers, bool hintForSeamlessTransition) {
if (requestedDataspace != ui::Dataspace::UNKNOWN) {
return requestedDataspace;
}
- const auto dataspaceForColorMode = ui::pickDataspaceFor(state.colorMode);
+ const auto dataspaceForColorMode = ui::pickDataspaceFor(colorMode);
// TODO: Enable once HDR screenshots are ready.
if constexpr (/* DISABLES CODE */ (false)) {
@@ -7482,11 +7516,11 @@
return protectedLayerFound;
}
-// Getting layer snapshots and display should take place on main thread.
-// Accessing display requires mStateLock, and contention for this lock
-// is reduced when grabbed from the main thread, thus also reducing
-// risk of deadlocks.
-std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapshotsFromMainThread(
+// Getting layer snapshots and accessing display state should take place on
+// main thread. Accessing display requires mStateLock, and contention for
+// this lock is reduced when grabbed from the main thread, thus also reducing
+// risk of deadlocks. Returns false if no display is found.
+bool SurfaceFlinger::getSnapshotsFromMainThread(
ScreenshotArgs& args, GetLayerSnapshotsFunction getLayerSnapshotsFn,
std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
return mScheduler
@@ -7526,8 +7560,8 @@
}
std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
- auto displayState = getSnapshotsFromMainThread(args, getLayerSnapshotsFn, layers);
- if (!displayState) {
+ bool hasDisplayState = getSnapshotsFromMainThread(args, getLayerSnapshotsFn, layers);
+ if (!hasDisplayState) {
ALOGD("Display state not found");
invokeScreenCaptureError(NO_MEMORY, captureListener);
}
@@ -7604,12 +7638,13 @@
auto futureFence =
captureScreenshot(args, texture, false /* regionSampling */, grayscale, isProtected,
- captureListener, displayState, layers, hdrTexture, gainmapTexture);
+ captureListener, layers, hdrTexture, gainmapTexture);
futureFence.get();
}
-std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getDisplayStateOnMainThread(
- ScreenshotArgs& args) {
+// Returns true if display is found and args was populated with display state
+// data. Otherwise, returns false.
+bool SurfaceFlinger::getDisplayStateOnMainThread(ScreenshotArgs& args) {
sp<const DisplayDevice> display = nullptr;
{
Mutex::Autolock lock(mStateLock);
@@ -7644,49 +7679,49 @@
}
if (display != nullptr) {
- return std::optional{display->getCompositionDisplay()->getState()};
+ const auto& state = display->getCompositionDisplay()->getState();
+ args.displayBrightnessNits = state.displayBrightnessNits;
+ args.sdrWhitePointNits = state.sdrWhitePointNits;
+ args.renderIntent = state.renderIntent;
+ args.colorMode = state.colorMode;
+ return true;
}
}
- return std::nullopt;
+ return false;
}
ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot(
- const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool regionSampling, bool grayscale, bool isProtected,
const sp<IScreenCaptureListener>& captureListener,
- const std::optional<OutputCompositionState>& displayState,
const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers,
const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer,
const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer) {
SFTRACE_CALL();
ScreenCaptureResults captureResults;
-
- float displayBrightnessNits = displayState.value().displayBrightnessNits;
- float sdrWhitePointNits = displayState.value().sdrWhitePointNits;
-
ftl::SharedFuture<FenceResult> renderFuture;
+ float hdrSdrRatio = args.displayBrightnessNits / args.sdrWhitePointNits;
+
if (hdrBuffer && gainmapBuffer) {
ftl::SharedFuture<FenceResult> hdrRenderFuture =
renderScreenImpl(args, hdrBuffer, regionSampling, grayscale, isProtected,
- captureResults, displayState, layers);
+ captureResults, layers);
captureResults.buffer = buffer->getBuffer();
captureResults.optionalGainMap = gainmapBuffer->getBuffer();
renderFuture =
ftl::Future(std::move(hdrRenderFuture))
- .then([&, displayBrightnessNits, sdrWhitePointNits,
- dataspace = captureResults.capturedDataspace, buffer, hdrBuffer,
- gainmapBuffer](FenceResult fenceResult) -> FenceResult {
+ .then([&, hdrSdrRatio, dataspace = captureResults.capturedDataspace, buffer,
+ hdrBuffer, gainmapBuffer](FenceResult fenceResult) -> FenceResult {
if (!fenceResult.ok()) {
return fenceResult;
}
return getRenderEngine()
.tonemapAndDrawGainmap(hdrBuffer, fenceResult.value()->get(),
- displayBrightnessNits /
- sdrWhitePointNits,
+ hdrSdrRatio,
static_cast<ui::Dataspace>(dataspace),
buffer, gainmapBuffer)
.get();
@@ -7694,17 +7729,16 @@
.share();
} else {
renderFuture = renderScreenImpl(args, buffer, regionSampling, grayscale, isProtected,
- captureResults, displayState, layers);
+ captureResults, layers);
}
if (captureListener) {
// Defer blocking on renderFuture back to the Binder thread.
return ftl::Future(std::move(renderFuture))
.then([captureListener, captureResults = std::move(captureResults),
- displayBrightnessNits,
- sdrWhitePointNits](FenceResult fenceResult) mutable -> FenceResult {
+ hdrSdrRatio](FenceResult fenceResult) mutable -> FenceResult {
captureResults.fenceResult = std::move(fenceResult);
- captureResults.hdrSdrRatio = displayBrightnessNits / sdrWhitePointNits;
+ captureResults.hdrSdrRatio = hdrSdrRatio;
captureListener->onScreenCaptureCompleted(captureResults);
return base::unexpected(NO_ERROR);
})
@@ -7714,9 +7748,8 @@
}
ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
- const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults,
- const std::optional<OutputCompositionState>& displayState,
const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
SFTRACE_CALL();
@@ -7730,49 +7763,37 @@
layerFE->mSnapshot->geomLayerTransform.inverse();
}
- auto capturedBuffer = buffer;
-
- auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
- auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance;
- auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance;
-
- captureResults.capturedDataspace = args.dataspace;
-
const bool enableLocalTonemapping =
FlagManager::getInstance().local_tonemap_screenshots() && !args.seamlessTransition;
- if (displayState) {
- const auto& state = displayState.value();
- captureResults.capturedDataspace =
- pickBestDataspace(args.dataspace, state, captureResults.capturedHdrLayers,
- args.seamlessTransition);
- sdrWhitePointNits = state.sdrWhitePointNits;
+ captureResults.capturedDataspace =
+ pickBestDataspace(args.dataspace, args.colorMode, captureResults.capturedHdrLayers,
+ args.seamlessTransition);
- if (!captureResults.capturedHdrLayers) {
- displayBrightnessNits = sdrWhitePointNits;
- } else {
- displayBrightnessNits = state.displayBrightnessNits;
- if (!enableLocalTonemapping) {
- // Only clamp the display brightness if this is not a seamless transition.
- // Otherwise for seamless transitions it's important to match the current
- // display state as the buffer will be shown under these same conditions, and we
- // want to avoid any flickers
- if (sdrWhitePointNits > 1.0f && !args.seamlessTransition) {
- // Restrict the amount of HDR "headroom" in the screenshot to avoid
- // over-dimming the SDR portion. 2.0 chosen by experimentation
- constexpr float kMaxScreenshotHeadroom = 2.0f;
- displayBrightnessNits = std::min(sdrWhitePointNits * kMaxScreenshotHeadroom,
- displayBrightnessNits);
- }
- }
- }
-
- // Screenshots leaving the device should be colorimetric
- if (args.dataspace == ui::Dataspace::UNKNOWN && args.seamlessTransition) {
- renderIntent = state.renderIntent;
- }
+ // Only clamp the display brightness if this is not a seamless transition.
+ // Otherwise for seamless transitions it's important to match the current
+ // display state as the buffer will be shown under these same conditions, and we
+ // want to avoid any flickers.
+ if (captureResults.capturedHdrLayers && !enableLocalTonemapping &&
+ args.sdrWhitePointNits > 1.0f && !args.seamlessTransition) {
+ // Restrict the amount of HDR "headroom" in the screenshot to avoid
+ // over-dimming the SDR portion. 2.0 chosen by experimentation
+ constexpr float kMaxScreenshotHeadroom = 2.0f;
+ // TODO: Aim to update displayBrightnessNits earlier in screenshot
+ // path so ScreenshotArgs can be passed as const
+ args.displayBrightnessNits = std::min(args.sdrWhitePointNits * kMaxScreenshotHeadroom,
+ args.displayBrightnessNits);
+ } else {
+ args.displayBrightnessNits = args.sdrWhitePointNits;
}
+ auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
+ // Screenshots leaving the device should be colorimetric
+ if (args.dataspace == ui::Dataspace::UNKNOWN && args.seamlessTransition) {
+ renderIntent = args.renderIntent;
+ }
+
+ auto capturedBuffer = buffer;
captureResults.buffer = capturedBuffer->getBuffer();
ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK};
@@ -7782,8 +7803,7 @@
}
auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
- sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, layers,
- layerStack, regionSampling, args, renderIntent,
+ grayscale, isProtected, layers, layerStack, regionSampling, args, renderIntent,
enableLocalTonemapping]() -> FenceResult {
std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
mFactory.createCompositionEngine();
@@ -7809,9 +7829,10 @@
if (enableLocalTonemapping) {
// Boost the whole scene so that SDR white is at 1.0 while still communicating the hdr
// sdr ratio via display brightness / sdrWhite nits.
- targetBrightness = sdrWhitePointNits / displayBrightnessNits;
+ targetBrightness = args.sdrWhitePointNits / args.displayBrightnessNits;
} else if (dataspace == ui::Dataspace::BT2020_HLG) {
- const float maxBrightnessNits = displayBrightnessNits / sdrWhitePointNits * 203;
+ const float maxBrightnessNits =
+ args.displayBrightnessNits / args.sdrWhitePointNits * 203;
// With a low dimming ratio, don't fit the entire curve. Otherwise mixed content
// will appear way too bright.
if (maxBrightnessNits < 1000.f) {
@@ -7837,8 +7858,8 @@
.buffer = std::move(buffer),
.displayId = args.displayId,
.reqBufferSize = args.reqSize,
- .sdrWhitePointNits = sdrWhitePointNits,
- .displayBrightnessNits = displayBrightnessNits,
+ .sdrWhitePointNits = args.sdrWhitePointNits,
+ .displayBrightnessNits = args.displayBrightnessNits,
.targetBrightness = targetBrightness,
.layerAlpha = layerAlpha,
.regionSampling = regionSampling,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 935a2da..3f454ba 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -896,32 +896,41 @@
// If true, the render result may be used for system animations
// that must preserve the exact colors of the display
bool seamlessTransition{false};
+
+ // Current display brightness of the output composition state
+ float displayBrightnessNits{-1.f};
+
+ // SDR white point of the output composition state
+ float sdrWhitePointNits{-1.f};
+
+ // Current active color mode of the output composition state
+ ui::ColorMode colorMode{ui::ColorMode::NATIVE};
+
+ // Current active render intent of the output composition state
+ ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
};
- std::optional<OutputCompositionState> getSnapshotsFromMainThread(
- ScreenshotArgs& args, GetLayerSnapshotsFunction getLayerSnapshotsFn,
- std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
+ bool getSnapshotsFromMainThread(ScreenshotArgs& args,
+ GetLayerSnapshotsFunction getLayerSnapshotsFn,
+ std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
void captureScreenCommon(ScreenshotArgs& args, GetLayerSnapshotsFunction, ui::Size bufferSize,
ui::PixelFormat, bool allowProtected, bool grayscale,
const sp<IScreenCaptureListener>&);
- std::optional<OutputCompositionState> getDisplayStateOnMainThread(ScreenshotArgs& args)
- REQUIRES(kMainThreadContext);
+ bool getDisplayStateOnMainThread(ScreenshotArgs& args) REQUIRES(kMainThreadContext);
ftl::SharedFuture<FenceResult> captureScreenshot(
- const ScreenshotArgs& args,
- const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
- bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener,
- const std::optional<OutputCompositionState>& displayState,
+ ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ bool regionSampling, bool grayscale, bool isProtected,
+ const sp<IScreenCaptureListener>& captureListener,
const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers,
const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer = nullptr,
const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer = nullptr);
ftl::SharedFuture<FenceResult> renderScreenImpl(
- const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>&,
+ ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>&,
bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&,
- const std::optional<OutputCompositionState>& displayState,
const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
void readPersistentProperties();
diff --git a/services/surfaceflinger/common/include/common/WorkloadTracer.h b/services/surfaceflinger/common/include/common/WorkloadTracer.h
index 39b6fa1..c4074f7 100644
--- a/services/surfaceflinger/common/include/common/WorkloadTracer.h
+++ b/services/surfaceflinger/common/include/common/WorkloadTracer.h
@@ -23,7 +23,7 @@
static constexpr int32_t COMPOSITION_TRACE_COOKIE = 1;
static constexpr int32_t POST_COMPOSITION_TRACE_COOKIE = 2;
-static constexpr size_t COMPOSITION_SUMMARY_SIZE = 20;
+static constexpr size_t COMPOSITION_SUMMARY_SIZE = 64;
static constexpr const char* TRACK_NAME = "CriticalWorkload";
} // namespace android::WorkloadTracer
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index b4496d3..5a82914 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -147,7 +147,7 @@
<< "Timeout waiting for vsync event";
DisplayEventReceiver::Event event;
while (mDisplayEventReceiver.getEvents(&event, 1) > 0) {
- if (event.header.type != DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ if (event.header.type != DisplayEventType::DISPLAY_EVENT_VSYNC) {
continue;
}
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index ee5d919..7910e77 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -497,17 +497,6 @@
mLifecycleManager.applyTransactions(transactions);
}
- void setClientDrawnShadowRadius(uint32_t id, float clientDrawnShadowRadius) {
- std::vector<QueuedTransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eClientDrawnShadowsChanged;
- transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.clientDrawnShadowRadius = clientDrawnShadowRadius;
- mLifecycleManager.applyTransactions(transactions);
- }
-
void setShadowRadius(uint32_t id, float shadowRadius) {
std::vector<QueuedTransactionState> transactions;
transactions.emplace_back();
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 42259af..f1c1549 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -65,9 +65,9 @@
"mock/MockFrameTracer.cpp",
"mock/MockNativeWindowSurface.cpp",
"mock/MockTimeStats.cpp",
- "mock/MockVsyncController.cpp",
"mock/MockVSyncDispatch.cpp",
"mock/MockVSyncTracker.cpp",
+ "mock/MockVsyncController.cpp",
],
}
@@ -87,10 +87,10 @@
test_suites: ["device-tests"],
header_libs: ["surfaceflinger_tests_common_headers"],
srcs: [
+ "*.cpp",
":libsurfaceflinger_backend_mock_sources",
":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
- "*.cpp",
],
}
@@ -117,9 +117,8 @@
"android.hardware.power@1.2",
"android.hardware.power@1.3",
"libaidlcommonsupport",
- "libcompositionengine_mocks",
"libcompositionengine",
- "libframetimeline",
+ "libcompositionengine_mocks",
"libgmock",
"libgui_mocks",
"libperfetto_client_experimental",
@@ -140,14 +139,15 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
+ "libSurfaceFlingerProp",
"libbase",
"libbinder",
"libbinder_ndk",
"libcutils",
- "libEGL",
"libfmq",
- "libGLESv1_CM",
- "libGLESv2",
"libgui",
"libhidlbase",
"libinput",
@@ -157,11 +157,10 @@
"libprocessgroup",
"libprotobuf-cpp-lite",
"libstatslog_surfaceflinger",
- "libSurfaceFlingerProp",
"libsync",
+ "libtracing_perfetto",
"libui",
"libutils",
- "libtracing_perfetto",
],
header_libs: [
"android.hardware.graphics.composer3-command-buffer",
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 268a6c4..6f15db8 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -30,7 +30,7 @@
#include "AsyncCallRecorder.h"
#include "DisplayHardware/DisplayMode.h"
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
#include "Scheduler/EventThread.h"
#include "mock/MockVSyncDispatch.h"
#include "mock/MockVSyncTracker.h"
@@ -270,7 +270,7 @@
ASSERT_TRUE(args.has_value()) << name << " did not receive an event for timestamp "
<< expectedTimestamp;
const auto& event = std::get<0>(args.value());
- EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_VSYNC, event.header.type)
+ EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_VSYNC, event.header.type)
<< name << " did not get the correct event for timestamp " << expectedTimestamp;
EXPECT_EQ(expectedTimestamp, event.header.timestamp)
<< name << " did not get the expected timestamp for timestamp " << expectedTimestamp;
@@ -344,7 +344,7 @@
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
- EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
+ EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_HOTPLUG, event.header.type);
EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(expectedConnected, event.hotplug.connected);
}
@@ -355,7 +355,7 @@
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
- EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, event.header.type);
+ EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_MODE_CHANGE, event.header.type);
EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(expectedConfigId, event.modeChange.modeId);
EXPECT_EQ(expectedVsyncPeriod, event.modeChange.vsyncPeriod);
@@ -367,7 +367,7 @@
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
- EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE, event.header.type);
+ EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE, event.header.type);
EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(uid, event.frameRateOverride.uid);
EXPECT_EQ(frameRateHz, event.frameRateOverride.frameRateHz);
@@ -376,7 +376,7 @@
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
- EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH, event.header.type);
+ EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH, event.header.type);
EXPECT_EQ(expectedDisplayId, event.header.displayId);
}
@@ -874,7 +874,7 @@
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
- EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE, event.header.type);
+ EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE, event.header.type);
EXPECT_EQ(EXTERNAL_DISPLAY_ID, event.header.displayId);
EXPECT_EQ(HDCP_V1, event.hdcpLevelsChange.connectedLevel);
EXPECT_EQ(HDCP_V2, event.hdcpLevelsChange.maxLevel);
diff --git a/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp b/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp
index 2941a14..0f16073 100644
--- a/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp
@@ -213,4 +213,33 @@
EXPECT_EQ(listenerCount(), 0u);
}
-} // namespace android
\ No newline at end of file
+TEST_F(JankTrackerTest, multipleLayersAreTrackedIndependently) {
+ size_t jankDataReceived = 0;
+ size_t numBatchesReceived = 0;
+
+ EXPECT_CALL(*mListener.get(), onJankData(_))
+ .WillRepeatedly([&](const std::vector<gui::JankData>& jankData) {
+ jankDataReceived += jankData.size();
+ numBatchesReceived++;
+ return binder::Status::ok();
+ });
+ addJankListener(123);
+ addJankListener(321);
+ addJankData(123, 1);
+ addJankData(123, 2);
+ addJankData(123, 3);
+ addJankData(321, 4);
+ addJankData(321, 5);
+
+ JankTracker::flushJankData(123);
+ flushBackgroundThread();
+ EXPECT_EQ(numBatchesReceived, 1u);
+ EXPECT_EQ(jankDataReceived, 3u);
+
+ JankTracker::flushJankData(321);
+ flushBackgroundThread();
+ EXPECT_EQ(numBatchesReceived, 2u);
+ EXPECT_EQ(jankDataReceived, 5u);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 453c053..7aad84b 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1505,14 +1505,6 @@
EXPECT_EQ(getSnapshot({.id = 111})->roundedCorner.radius.x, RADIUS);
}
-TEST_F(LayerSnapshotTest, ignoreShadows) {
- static constexpr float SHADOW_RADIUS = 123.f;
- setClientDrawnShadowRadius(1, SHADOW_RADIUS);
- setShadowRadius(1, SHADOW_RADIUS);
- UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
- EXPECT_EQ(getSnapshot({.id = 1})->shadowSettings.length, 0.f);
-}
-
TEST_F(LayerSnapshotTest, setShadowRadius) {
static constexpr float SHADOW_RADIUS = 123.f;
setShadowRadius(1, SHADOW_RADIUS);
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 908637a..e9b86b2 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -22,7 +22,7 @@
#include <scheduler/interface/ICompositor.h>
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
#include "Scheduler/MessageQueue.h"
#include "mock/MockVSyncDispatch.h"
#include "utils/Timers.h"
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9a2e254..41f2b6e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -469,7 +469,7 @@
ftl::FakeGuard guard(kMainThreadContext);
ScreenCaptureResults captureResults;
- auto displayState = std::optional{display->getCompositionDisplay()->getState()};
+ const auto& state = display->getCompositionDisplay()->getState();
auto layers = getLayerSnapshotsFn();
SurfaceFlinger::ScreenshotArgs screenshotArgs;
@@ -480,10 +480,14 @@
screenshotArgs.dataspace = dataspace;
screenshotArgs.isSecure = isSecure;
screenshotArgs.seamlessTransition = seamlessTransition;
+ screenshotArgs.displayBrightnessNits = state.displayBrightnessNits;
+ screenshotArgs.sdrWhitePointNits = state.sdrWhitePointNits;
+ screenshotArgs.renderIntent = state.renderIntent;
+ screenshotArgs.colorMode = state.colorMode;
return mFlinger->renderScreenImpl(screenshotArgs, buffer, regionSampling,
false /* grayscale */, false /* isProtected */,
- captureResults, displayState, layers);
+ captureResults, layers);
}
auto getLayerSnapshotsForScreenshotsFn(ui::LayerStack layerStack, uint32_t uid) {
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index 8b4a6be..77a68d9 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -41,7 +41,7 @@
while ((n = q->getEvents(buffer, 1)) > 0) {
for (int i=0 ; i<n ; i++) {
- if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ if (buffer[i].header.type == DisplayEventType::DISPLAY_EVENT_VSYNC) {
printf("event vsync: count=%d\t", buffer[i].vsync.count);
}
if (oldTimeStamp) {