Merge "Add support for new PowerHAL methods to PowerHalWrapper" into main
diff --git a/include/android/asset_manager.h b/include/android/asset_manager.h
index 2ac7d4d..6420cd0 100644
--- a/include/android/asset_manager.h
+++ b/include/android/asset_manager.h
@@ -29,6 +29,10 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#if defined(__APPLE__)
+typedef off_t off64_t; // Mac OSX does not define off64_t
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 30200c7..08d339b 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -240,7 +240,7 @@
* the actual GPU duration is not measured.
*
* @return 0 on success.
- * EINVAL if session is nullptr or any duration is an invalid number.
+ * EINVAL if any duration is an invalid number.
* EPIPE if communication with the system service has failed.
*/
int APerformanceHint_reportActualWorkDuration2(
@@ -269,7 +269,7 @@
*
* @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
* @param workPeriodStartTimestampNanos The work period start timestamp in nanoseconds based on
- * CLOCK_MONOTONIC about when the work starts, the timestamp must be positive.
+ * CLOCK_MONOTONIC about when the work starts. This timestamp must be greater than zero.
*/
void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* _Nonnull aWorkDuration,
int64_t workPeriodStartTimestampNanos) __INTRODUCED_IN(__ANDROID_API_V__);
@@ -278,8 +278,8 @@
* Sets the actual total work duration in nanoseconds.
*
* @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
- * @param actualTotalDurationNanos The actual total work duration in nanoseconds, the number must be
- * positive.
+ * @param actualTotalDurationNanos The actual total work duration in nanoseconds. This number must
+ * be greater than zero.
*/
void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* _Nonnull aWorkDuration,
int64_t actualTotalDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__);
@@ -288,8 +288,8 @@
* Sets the actual CPU work duration in nanoseconds.
*
* @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
- * @param actualCpuDurationNanos The actual CPU work duration in nanoseconds, the number must be
- * positive.
+ * @param actualCpuDurationNanos The actual CPU work duration in nanoseconds. This number must be
+ * greater than zero.
*/
void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* _Nonnull aWorkDuration,
int64_t actualCpuDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__);
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index ce9cd1c..7da8d51 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -31,6 +31,8 @@
namespace android {
namespace battery {
+#define REPORTED_INVALID_TIMESTAMP_DELTA_MS 60000
+
typedef uint16_t state_t;
template <class T>
@@ -171,8 +173,12 @@
if (timestamp >= lastStateChangeTimestamp) {
states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
} else {
- ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
- (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+ if (timestamp < lastStateChangeTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
+ ALOGE("setState is called with an earlier timestamp: %lu, "
+ "previous timestamp: %lu\n",
+ (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+ }
+
// The accumulated durations have become unreliable. For example, if the timestamp
// sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
// we would get 4000, which is greater than (last - first). This could lead to
@@ -232,8 +238,10 @@
}
}
} else if (timestamp < lastUpdateTimestamp) {
- ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
- (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+ if (timestamp < lastUpdateTimestamp - REPORTED_INVALID_TIMESTAMP_DELTA_MS) {
+ ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
+ (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+ }
for (int i = 0; i < stateCount; i++) {
states[i].timeInStateSinceUpdate = 0;
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 1baeb26..576d9d5 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -64,13 +64,6 @@
}
flag {
- name: "remove_app_switch_drops"
- namespace: "input"
- description: "Remove the logic of dropping events due to pending app switch"
- bug: "284808102"
-}
-
-flag {
name: "disable_reject_touch_on_stylus_hover"
namespace: "input"
description: "Disable touch rejection when the stylus hovers the screen"
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index d4278be..8056d9a 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -29,6 +29,7 @@
#define ANDROID_DATA_SPACE_H
#include <inttypes.h>
+#include <stdint.h>
#include <sys/cdefs.h>
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 4571ef4..3ac4285 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -109,7 +109,9 @@
const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
pc.move(deltaX, deltaY);
- pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+ if (canUnfadeOnDisplay(displayId)) {
+ pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+ }
const auto [x, y] = pc.getPosition();
NotifyMotionArgs newArgs(args);
@@ -131,7 +133,9 @@
const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
pc.move(deltaX, deltaY);
- pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+ if (canUnfadeOnDisplay(displayId)) {
+ pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+ }
const auto [x, y] = pc.getPosition();
newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
@@ -140,7 +144,9 @@
newArgs.yCursorPosition = y;
} else {
// This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
- pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+ if (canUnfadeOnDisplay(displayId)) {
+ pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+ }
const auto [x, y] = pc.getPosition();
for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
@@ -223,7 +229,7 @@
if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
- } else {
+ } else if (canUnfadeOnDisplay(args.displayId)) {
pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
}
}
@@ -323,6 +329,10 @@
return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
}
+bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) {
+ return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
+}
+
void PointerChoreographer::updatePointerControllersLocked() {
std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
std::set<DeviceId> touchDevicesToKeep;
@@ -342,7 +352,7 @@
mMousePointersByDisplay.try_emplace(displayId,
getMouseControllerConstructor(displayId));
auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId());
- if (isNewMouseDevice || isNewMousePointer) {
+ if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
}
}
@@ -513,6 +523,28 @@
return true;
}
+void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
+ std::scoped_lock lock(mLock);
+ if (visible) {
+ mDisplaysWithPointersHidden.erase(displayId);
+ // We do not unfade the icons here, because we don't know when the last event happened.
+ return;
+ }
+
+ mDisplaysWithPointersHidden.emplace(displayId);
+
+ // Hide any icons that are currently visible on the display.
+ if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
+ const auto& [_, controller] = *it;
+ controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
+ }
+ for (const auto& [_, controller] : mStylusPointersByDevice) {
+ if (controller->getDisplayId() == displayId) {
+ controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
+ }
+ }
+}
+
PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
int32_t displayId) {
std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index f46419e..6aab3aa 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -67,6 +67,11 @@
*/
virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
int32_t displayId, DeviceId deviceId) = 0;
+ /**
+ * Set whether pointer icons for mice, touchpads, and styluses should be visible on the
+ * given display.
+ */
+ virtual void setPointerIconVisibility(int32_t displayId, bool visible) = 0;
/**
* This method may be called on any thread (usually by the input manager on a binder thread).
@@ -89,6 +94,7 @@
void setStylusPointerIconEnabled(bool enabled) override;
bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
int32_t displayId, DeviceId deviceId) override;
+ void setPointerIconVisibility(int32_t displayId, bool visible) override;
void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override;
@@ -110,6 +116,7 @@
std::pair<int32_t, PointerControllerInterface&> getDisplayIdAndMouseControllerLocked(
int32_t associatedDisplayId) REQUIRES(mLock);
InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock);
+ bool canUnfadeOnDisplay(int32_t displayId) REQUIRES(mLock);
NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
@@ -143,6 +150,7 @@
std::vector<DisplayViewport> mViewports GUARDED_BY(mLock);
bool mShowTouchesEnabled GUARDED_BY(mLock);
bool mStylusPointerIconEnabled GUARDED_BY(mLock);
+ std::set<int32_t /*displayId*/> mDisplaysWithPointersHidden;
};
} // namespace android
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index c889b9b..fe33d94 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -98,13 +98,6 @@
constexpr bool DEBUG_TOUCH_OCCLUSION = true;
/**
- * Log debug messages about the app switch latency optimization.
- * Enable this via "adb shell setprop log.tag.InputDispatcherAppSwitch DEBUG" (requires restart)
- */
-const bool DEBUG_APP_SWITCH =
- android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "AppSwitch");
-
-/**
* Log debug messages about hover events.
* Enable this via "adb shell setprop log.tag.InputDispatcherHover DEBUG" (requires restart)
*/
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index cc0d49c..2153d8a 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -164,6 +164,11 @@
keyCode, scanCode, metaState, repeatCount, policyFlags);
}
+std::ostream& operator<<(std::ostream& out, const KeyEntry& keyEntry) {
+ out << keyEntry.getDescription();
+ return out;
+}
+
// --- TouchModeEntry ---
TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode, int displayId)
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index e2e13c3..a915805 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -18,6 +18,7 @@
#include "InjectionState.h"
#include "InputTarget.h"
+#include "trace/EventTrackerInterface.h"
#include <gui/InputApplication.h>
#include <input/Input.h>
@@ -125,6 +126,7 @@
int32_t scanCode;
int32_t metaState;
nsecs_t downTime;
+ std::unique_ptr<trace::EventTrackerInterface> traceTracker;
bool syntheticRepeat; // set to true for synthetic key repeats
@@ -147,6 +149,8 @@
std::string getDescription() const override;
};
+std::ostream& operator<<(std::ostream& out, const KeyEntry& motionEntry);
+
struct MotionEntry : EventEntry {
int32_t deviceId;
uint32_t source;
@@ -165,6 +169,7 @@
nsecs_t downTime;
std::vector<PointerProperties> pointerProperties;
std::vector<PointerCoords> pointerCoords;
+ std::unique_ptr<trace::EventTrackerInterface> traceTracker;
size_t getPointerCount() const { return pointerProperties.size(); }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index e998d91..1085c94 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -72,12 +72,17 @@
using android::os::InputEventInjectionSync;
namespace input_flags = com::android::input::flags;
-// TODO(b/312714754): remove the corresponding code, as well.
-static const bool REMOVE_APP_SWITCH_DROPS = true;
-
namespace android::inputdispatcher {
namespace {
+
+template <class Entry>
+void ensureEventTraced(const Entry& entry) {
+ if (!entry.traceTracker) {
+ LOG(FATAL) << "Expected event entry to be traced, but it wasn't: " << entry;
+ }
+}
+
// Temporarily releases a held mutex for the lifetime of the instance.
// Named to match std::scoped_lock
class scoped_unlock {
@@ -95,11 +100,6 @@
android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
HwTimeoutMultiplier());
-// Amount of time to allow for all pending events to be processed when an app switch
-// key is on the way. This is used to preempt input dispatch and drop input events
-// when an application takes too long to respond and the user has pressed an app switch key.
-constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
-
const std::chrono::duration STALE_EVENT_TIMEOUT = std::chrono::seconds(10) * HwTimeoutMultiplier();
// Log a warning when an event takes longer than this to process, even if an ANR does not occur.
@@ -783,12 +783,14 @@
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy)
+ : InputDispatcher(policy, nullptr) {}
+
+InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
+ std::unique_ptr<trace::InputTracingBackendInterface> traceBackend)
: mPolicy(policy),
mPendingEvent(nullptr),
mLastDropReason(DropReason::NOT_DROPPED),
mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
- mAppSwitchSawKeyDown(false),
- mAppSwitchDueTime(LLONG_MAX),
mNextUnblockedEvent(nullptr),
mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),
mDispatchEnabled(false),
@@ -807,6 +809,10 @@
SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
#endif
mKeyRepeatState.lastKeyEntry = nullptr;
+
+ if (traceBackend) {
+ // TODO: Create input tracer instance.
+ }
}
InputDispatcher::~InputDispatcher() {
@@ -975,28 +981,10 @@
return;
}
- // Optimize latency of app switches.
- // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
- // been pressed. When it expires, we preempt dispatch and drop all other pending events.
- bool isAppSwitchDue;
- if (!REMOVE_APP_SWITCH_DROPS) {
- isAppSwitchDue = mAppSwitchDueTime <= currentTime;
- nextWakeupTime = std::min(nextWakeupTime, mAppSwitchDueTime);
- }
-
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
if (mInboundQueue.empty()) {
- if (!REMOVE_APP_SWITCH_DROPS) {
- if (isAppSwitchDue) {
- // The inbound queue is empty so the app switch key we were waiting
- // for will never arrive. Stop waiting for it.
- resetPendingAppSwitchLocked(false);
- isAppSwitchDue = false;
- }
- }
-
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
@@ -1091,16 +1079,6 @@
case EventEntry::Type::KEY: {
std::shared_ptr<const KeyEntry> keyEntry =
std::static_pointer_cast<const KeyEntry>(mPendingEvent);
- if (!REMOVE_APP_SWITCH_DROPS) {
- if (isAppSwitchDue) {
- if (isAppSwitchKeyEvent(*keyEntry)) {
- resetPendingAppSwitchLocked(true);
- isAppSwitchDue = false;
- } else if (dropReason == DropReason::NOT_DROPPED) {
- dropReason = DropReason::APP_SWITCH;
- }
- }
- }
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {
dropReason = DropReason::STALE;
}
@@ -1108,17 +1086,16 @@
dropReason = DropReason::BLOCKED;
}
done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
+ if (done && mTracer) {
+ ensureEventTraced(*keyEntry);
+ mTracer->eventProcessingComplete(*keyEntry->traceTracker);
+ }
break;
}
case EventEntry::Type::MOTION: {
std::shared_ptr<const MotionEntry> motionEntry =
std::static_pointer_cast<const MotionEntry>(mPendingEvent);
- if (!REMOVE_APP_SWITCH_DROPS) {
- if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
- dropReason = DropReason::APP_SWITCH;
- }
- }
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
// The event is stale. However, only drop stale events if there isn't an ongoing
// gesture. That would allow us to complete the processing of the current stroke.
@@ -1138,17 +1115,17 @@
}
}
done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
+ if (done && mTracer) {
+ ensureEventTraced(*motionEntry);
+ mTracer->eventProcessingComplete(*motionEntry->traceTracker);
+ }
break;
}
case EventEntry::Type::SENSOR: {
std::shared_ptr<const SensorEntry> sensorEntry =
std::static_pointer_cast<const SensorEntry>(mPendingEvent);
- if (!REMOVE_APP_SWITCH_DROPS) {
- if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
- dropReason = DropReason::APP_SWITCH;
- }
- }
+
// Sensor timestamps use SYSTEM_TIME_BOOTTIME time base, so we can't use
// 'currentTime' here, get SYSTEM_TIME_BOOTTIME instead.
nsecs_t bootTime = systemTime(SYSTEM_TIME_BOOTTIME);
@@ -1245,27 +1222,12 @@
case EventEntry::Type::KEY: {
LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
"Unexpected untrusted event.");
- // Optimize app switch latency.
- // If the application takes too long to catch up then we drop all events preceding
- // the app switch key.
- const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
- if (!REMOVE_APP_SWITCH_DROPS) {
- if (isAppSwitchKeyEvent(keyEntry)) {
- if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
- mAppSwitchSawKeyDown = true;
- } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
- if (mAppSwitchSawKeyDown) {
- if (DEBUG_APP_SWITCH) {
- ALOGD("App switch is pending!");
- }
- mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
- mAppSwitchSawKeyDown = false;
- needWake = true;
- }
- }
- }
+ const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
+ if (mTracer) {
+ ensureEventTraced(keyEntry);
}
+
// If a new up event comes in, and the pending event with same key code has been asked
// to try again later because of the policy. We have to reset the intercept key wake up
// time for it may have been handled in the policy and could be dropped.
@@ -1286,7 +1248,11 @@
case EventEntry::Type::MOTION: {
LOG_ALWAYS_FATAL_IF((entry.policyFlags & POLICY_FLAG_TRUSTED) == 0,
"Unexpected untrusted event.");
- if (shouldPruneInboundQueueLocked(static_cast<const MotionEntry&>(entry))) {
+ const auto& motionEntry = static_cast<const MotionEntry&>(entry);
+ if (mTracer) {
+ ensureEventTraced(motionEntry);
+ }
+ if (shouldPruneInboundQueueLocked(motionEntry)) {
mNextUnblockedEvent = mInboundQueue.back();
needWake = true;
}
@@ -1401,10 +1367,6 @@
}
reason = "inbound event was dropped because input dispatch is disabled";
break;
- case DropReason::APP_SWITCH:
- ALOGI("Dropped event because of pending overdue app switch.");
- reason = "inbound event was dropped because of pending overdue app switch";
- break;
case DropReason::BLOCKED:
LOG(INFO) << "Dropping because the current application is not responding and the user "
"has started interacting with a different application: "
@@ -1468,33 +1430,6 @@
}
}
-static bool isAppSwitchKeyCode(int32_t keyCode) {
- return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL ||
- keyCode == AKEYCODE_APP_SWITCH;
-}
-
-bool InputDispatcher::isAppSwitchKeyEvent(const KeyEntry& keyEntry) {
- return !(keyEntry.flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry.keyCode) &&
- (keyEntry.policyFlags & POLICY_FLAG_TRUSTED) &&
- (keyEntry.policyFlags & POLICY_FLAG_PASS_TO_USER);
-}
-
-bool InputDispatcher::isAppSwitchPendingLocked() const {
- return mAppSwitchDueTime != LLONG_MAX;
-}
-
-void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
- mAppSwitchDueTime = LLONG_MAX;
-
- if (DEBUG_APP_SWITCH) {
- if (handled) {
- ALOGD("App switch has arrived.");
- } else {
- ALOGD("App switch was abandoned.");
- }
- }
-}
-
bool InputDispatcher::haveCommandsLocked() const {
return !mCommandQueue.empty();
}
@@ -1567,6 +1502,10 @@
entry->repeatCount + 1, entry->downTime);
newEntry->syntheticRepeat = true;
+ if (mTracer) {
+ newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
+ }
+
mKeyRepeatState.lastKeyEntry = newEntry;
mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay;
return newEntry;
@@ -1873,6 +1812,13 @@
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
+ if (mTracer) {
+ ensureEventTraced(*entry);
+ for (const auto& target : inputTargets) {
+ mTracer->dispatchToTargetHint(*entry->traceTracker, target);
+ }
+ }
+
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
@@ -1998,6 +1944,13 @@
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
+ if (mTracer) {
+ ensureEventTraced(*entry);
+ for (const auto& target : inputTargets) {
+ mTracer->dispatchToTargetHint(*entry->traceTracker, target);
+ }
+ }
+
// Dispatch the motion.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
@@ -3635,6 +3588,7 @@
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry.pointerCoords.data();
+ // TODO(b/316355518): Do not modify coords before dispatch.
// Set the X and Y offset and X and Y scale depending on the input source.
if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) &&
!(dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS))) {
@@ -3710,6 +3664,9 @@
keyEntry.keyCode, keyEntry.scanCode,
keyEntry.metaState, keyEntry.repeatCount,
keyEntry.downTime, keyEntry.eventTime);
+ if (mTracer) {
+ mTracer->traceEventDispatch(*dispatchEntry, keyEntry.traceTracker.get());
+ }
break;
}
@@ -3718,7 +3675,11 @@
LOG(INFO) << "Publishing " << *dispatchEntry << " to "
<< connection->getInputChannelName();
}
+ const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
status = publishMotionEvent(*connection, *dispatchEntry);
+ if (mTracer) {
+ mTracer->traceEventDispatch(*dispatchEntry, motionEntry.traceTracker.get());
+ }
break;
}
@@ -4400,6 +4361,9 @@
args.deviceId, args.source, args.displayId, policyFlags,
args.action, flags, keyCode, args.scanCode, metaState,
repeatCount, args.downTime);
+ if (mTracer) {
+ newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
+ }
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
@@ -4526,6 +4490,9 @@
args.yPrecision, args.xCursorPosition,
args.yCursorPosition, args.downTime,
args.pointerProperties, args.pointerCoords);
+ if (mTracer) {
+ newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
+ }
if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER &&
@@ -4713,6 +4680,9 @@
incomingKey.getScanCode(), metaState,
incomingKey.getRepeatCount(),
incomingKey.getDownTime());
+ if (mTracer) {
+ injectedEntry->traceTracker = mTracer->traceInboundEvent(*injectedEntry);
+ }
injectedEntries.push(std::move(injectedEntry));
break;
}
@@ -4770,6 +4740,9 @@
samplePointerCoords +
pointerCount));
transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform());
+ if (mTracer) {
+ injectedEntry->traceTracker = mTracer->traceInboundEvent(*injectedEntry);
+ }
injectedEntries.push(std::move(injectedEntry));
for (size_t i = motionEvent.getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
@@ -5843,16 +5816,6 @@
dump += INDENT "Connections: <none>\n";
}
- dump += "input_flags::remove_app_switch_drops() = ";
- dump += toString(REMOVE_APP_SWITCH_DROPS);
- dump += "\n";
- if (isAppSwitchPendingLocked()) {
- dump += StringPrintf(INDENT "AppSwitch: pending, due in %" PRId64 "ms\n",
- ns2ms(mAppSwitchDueTime - now()));
- } else {
- dump += INDENT "AppSwitch: not pending\n";
- }
-
if (!mTouchModePerDisplay.empty()) {
dump += INDENT "TouchModePerDisplay:\n";
for (const auto& [displayId, touchMode] : mTouchModePerDisplay) {
@@ -5869,6 +5832,8 @@
ns2ms(mConfig.keyRepeatTimeout));
dump += mLatencyTracker.dump(INDENT2);
dump += mLatencyAggregator.dump(INDENT2);
+ dump += INDENT "InputTracer: ";
+ dump += mTracer == nullptr ? "Disabled" : "Enabled";
}
void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) const {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 3567288..1e11b27 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -32,6 +32,8 @@
#include "Monitor.h"
#include "TouchState.h"
#include "TouchedWindow.h"
+#include "trace/InputTracerInterface.h"
+#include "trace/InputTracingBackendInterface.h"
#include <attestation/HmacKeyManager.h>
#include <gui/InputApplication.h>
@@ -82,6 +84,9 @@
static constexpr bool kDefaultInTouchMode = true;
explicit InputDispatcher(InputDispatcherPolicyInterface& policy);
+ // Constructor used for testing.
+ explicit InputDispatcher(InputDispatcherPolicyInterface&,
+ std::unique_ptr<trace::InputTracingBackendInterface>);
~InputDispatcher() override;
void dump(std::string& dump) const override;
@@ -155,7 +160,6 @@
enum class DropReason {
NOT_DROPPED,
POLICY,
- APP_SWITCH,
DISABLED,
BLOCKED,
STALE,
@@ -172,6 +176,9 @@
std::condition_variable mDispatcherIsAlive;
mutable std::condition_variable mDispatcherEnteredIdle;
+ // Input event tracer. The tracer will only exist on builds where input tracing is allowed.
+ std::unique_ptr<trace::InputTracerInterface> mTracer GUARDED_BY(mLock);
+
sp<Looper> mLooper;
std::shared_ptr<const EventEntry> mPendingEvent GUARDED_BY(mLock);
@@ -228,14 +235,6 @@
// Adds an event to a queue of recent events for debugging purposes.
void addRecentEventLocked(std::shared_ptr<const EventEntry> entry) REQUIRES(mLock);
- // App switch latency optimization.
- bool mAppSwitchSawKeyDown GUARDED_BY(mLock);
- nsecs_t mAppSwitchDueTime GUARDED_BY(mLock);
-
- bool isAppSwitchKeyEvent(const KeyEntry& keyEntry);
- bool isAppSwitchPendingLocked() const REQUIRES(mLock);
- void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock);
-
// Blocked event latency optimization. Drops old events when the user intends
// to transfer focus to a new application.
std::shared_ptr<const EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/trace/EventTrackerInterface.h b/services/inputflinger/dispatcher/trace/EventTrackerInterface.h
new file mode 100644
index 0000000..929820e
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/EventTrackerInterface.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::inputdispatcher::trace {
+
+/**
+ * A tracker used to track the lifecycle of a traced input event.
+ * The tracker should be stored inside the traced event. When the event goes out of scope after
+ * the dispatcher has finished processing it, the tracker will call back into the tracer to
+ * initiate cleanup.
+ */
+class EventTrackerInterface {
+public:
+ virtual ~EventTrackerInterface() = default;
+};
+
+} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/dispatcher/trace/InputTracerInterface.h b/services/inputflinger/dispatcher/trace/InputTracerInterface.h
new file mode 100644
index 0000000..c6cd7de
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/InputTracerInterface.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../Entry.h"
+#include "../InputTarget.h"
+#include "EventTrackerInterface.h"
+
+namespace android::inputdispatcher::trace {
+
+/**
+ * InputTracerInterface is the tracing interface for InputDispatcher.
+ *
+ * The tracer is responsible for tracing information about input events and where they are
+ * dispatched. The trace is logged to the backend using the InputTracingBackendInterface.
+ *
+ * A normal traced event should have the following lifecycle:
+ * - The EventTracker is obtained from traceInboundEvent(), after which point the event
+ * should not change.
+ * - While the event is being processed, dispatchToTargetHint() is called for each target that
+ * the event will be eventually sent to.
+ * - Once all targets have been determined, eventProcessingComplete() is called, at which point
+ * the tracer will have enough information to commit the event to the trace.
+ * - For each event that is dispatched to the client, traceEventDispatch() is called, and the
+ * tracer will record that the event was sent to the client.
+ */
+class InputTracerInterface {
+public:
+ InputTracerInterface() = default;
+ virtual ~InputTracerInterface() = default;
+ InputTracerInterface(const InputTracerInterface&) = delete;
+ InputTracerInterface& operator=(const InputTracerInterface&) = delete;
+
+ /**
+ * Trace an input event that is being processed by InputDispatcher. The event must not be
+ * modified after it is traced to keep the traced event consistent with the event that is
+ * eventually dispatched. An EventTracker is returned for each traced event that should be used
+ * to track the event's lifecycle inside InputDispatcher.
+ */
+ virtual std::unique_ptr<EventTrackerInterface> traceInboundEvent(const EventEntry&) = 0;
+
+ /**
+ * Notify the tracer that the traced event will be sent to the given InputTarget.
+ * The tracer may change how the event is logged depending on the target. For example,
+ * events targeting certain UIDs may be logged as sensitive events.
+ * This may be called 0 or more times for each tracked event before event processing is
+ * completed.
+ */
+ virtual void dispatchToTargetHint(const EventTrackerInterface&, const InputTarget&) = 0;
+
+ /**
+ * Notify the tracer that the event processing is complete. This may be called at most once
+ * for each traced event. If a tracked event is dropped before it can be processed, it is
+ * possible that this is never called before the EventTracker is destroyed.
+ *
+ * This is used to commit the event to the trace in a timely manner, rather than always
+ * waiting for the event to go out of scope (and thus for the EventTracker to be destroyed)
+ * before committing. The point at which the event is destroyed can depend on several factors
+ * outside of our control, such as how long apps take to respond, so we don't want to depend on
+ * that.
+ */
+ virtual void eventProcessingComplete(const EventTrackerInterface&) = 0;
+
+ /**
+ * Trace an input event being successfully dispatched to a window. The dispatched event may
+ * be a previously traced inbound event, or it may be a synthesized event that has not been
+ * previously traced. For inbound events that were previously traced, the EventTracker cookie
+ * must be provided. For events that were not previously traced, the cookie must be null.
+ */
+ virtual void traceEventDispatch(const DispatchEntry&, const EventTrackerInterface*) = 0;
+};
+
+} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h
new file mode 100644
index 0000000..b430a5b
--- /dev/null
+++ b/services/inputflinger/dispatcher/trace/InputTracingBackendInterface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../Entry.h"
+
+namespace android::inputdispatcher::trace {
+
+/**
+ * An interface for the tracing backend, used for setting a custom backend for testing.
+ */
+class InputTracingBackendInterface {
+public:
+ virtual ~InputTracingBackendInterface() = default;
+
+ /** Trace a KeyEvent. */
+ virtual void traceKeyEvent(const KeyEntry&) const = 0;
+
+ /** Trace a MotionEvent. */
+ virtual void traceMotionEvent(const MotionEntry&) const = 0;
+
+ /** Trace an event being sent to a window. */
+ struct WindowDispatchArgs {
+ std::variant<MotionEntry, KeyEntry> eventEntry;
+ nsecs_t deliveryTime;
+ int32_t resolvedFlags;
+ gui::Uid targetUid;
+ int64_t vsyncId;
+ int32_t windowId;
+ ui::Transform transform;
+ ui::Transform rawTransform;
+ std::array<uint8_t, 32> hmac;
+ };
+ virtual void traceWindowDispatch(const WindowDispatchArgs&) const = 0;
+};
+
+} // namespace android::inputdispatcher::trace
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 40359a4..9abfef1 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -131,10 +131,10 @@
// Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled.
int32_t mousePointerSpeed;
- // Whether to apply an acceleration curve to pointer movements from mice.
+ // Displays on which an acceleration curve shouldn't be applied for pointer movements from mice.
//
// Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled.
- bool mousePointerAccelerationEnabled;
+ std::set<int32_t> displaysWithMousePointerAccelerationDisabled;
// Velocity control parameters for mouse pointer movements.
//
@@ -243,7 +243,7 @@
InputReaderConfiguration()
: virtualKeyQuietTime(0),
mousePointerSpeed(0),
- mousePointerAccelerationEnabled(true),
+ displaysWithMousePointerAccelerationDisabled(),
pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f,
static_cast<float>(
android::os::IInputConstants::
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 4cebd64..d207ed1 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -159,15 +159,15 @@
out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
}
- if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) ||
- configurePointerCapture) {
- configureOnChangePointerSpeed(readerConfig);
- }
-
if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) ||
configurePointerCapture) {
configureOnChangeDisplayInfo(readerConfig);
}
+
+ if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) ||
+ configurePointerCapture) {
+ configureOnChangePointerSpeed(readerConfig);
+ }
return out;
}
@@ -510,7 +510,8 @@
} else {
if (mEnableNewMousePointerBallistics) {
mNewPointerVelocityControl.setAccelerationEnabled(
- config.mousePointerAccelerationEnabled);
+ config.displaysWithMousePointerAccelerationDisabled.count(
+ mDisplayId.value_or(ADISPLAY_ID_NONE)) == 0);
mNewPointerVelocityControl.setCurve(
createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed));
} else {
diff --git a/services/inputflinger/reader/mapper/SlopController.cpp b/services/inputflinger/reader/mapper/SlopController.cpp
index f79219f..9ec02a6 100644
--- a/services/inputflinger/reader/mapper/SlopController.cpp
+++ b/services/inputflinger/reader/mapper/SlopController.cpp
@@ -54,11 +54,13 @@
mCumulativeValue += value;
if (abs(mCumulativeValue) >= mSlopThreshold) {
+ ALOGD("SlopController: did not drop event with value .%3f", value);
mHasSlopBeenMet = true;
// Return the amount of value that exceeds the slop.
return signOf(value) * (abs(mCumulativeValue) - mSlopThreshold);
}
+ ALOGD("SlopController: dropping event with value .%3f", value);
return 0;
}
diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp
index e104543..7b793d8 100644
--- a/services/inputflinger/tests/CursorInputMapper_test.cpp
+++ b/services/inputflinger/tests/CursorInputMapper_test.cpp
@@ -1324,6 +1324,42 @@
ASSERT_EQ(20, relY2);
}
+TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationWithAssociatedViewport) {
+ mPropertyMap.addProperty("cursor.mode", "pointer");
+ DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
+ mReaderConfiguration.setDisplayViewports({primaryViewport});
+ createDevice();
+ ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, primaryViewport);
+ mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
+
+ std::list<NotifyArgs> args;
+
+ // Verify that acceleration is being applied by default by checking that the movement is scaled.
+ args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
+ args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID)))));
+ const auto& coords = get<NotifyMotionArgs>(args.back()).pointerCoords[0];
+ ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), 10.f);
+ ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y), 20.f);
+
+ // Disable acceleration for the display, and verify that acceleration is no longer applied.
+ mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID);
+ args += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
+ InputReaderConfiguration::Change::POINTER_SPEED);
+ args.clear();
+
+ args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
+ args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
+ args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID),
+ WithRelativeMotion(10, 20)))));
+}
+
namespace {
// Minimum timestamp separation between subsequent input events from a Bluetooth device.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 48d7e55..b6ae0b3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -861,30 +861,31 @@
explicit FakeInputReceiver(std::unique_ptr<InputChannel> clientChannel, const std::string name)
: mConsumer(std::move(clientChannel)), mName(name) {}
- InputEvent* consume(std::chrono::milliseconds timeout, bool handled = false) {
- InputEvent* event;
- std::optional<uint32_t> consumeSeq = receiveEvent(timeout, &event);
+ std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = false) {
+ auto [consumeSeq, event] = receiveEvent(timeout);
if (!consumeSeq) {
return nullptr;
}
finishEvent(*consumeSeq, handled);
- return event;
+ return std::move(event);
}
/**
* Receive an event without acknowledging it.
* Return the sequence number that could later be used to send finished signal.
*/
- std::optional<uint32_t> receiveEvent(std::chrono::milliseconds timeout,
- InputEvent** outEvent = nullptr) {
+ std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent(
+ std::chrono::milliseconds timeout) {
uint32_t consumeSeq;
- InputEvent* event;
+ std::unique_ptr<InputEvent> event;
std::chrono::time_point start = std::chrono::steady_clock::now();
status_t status = WOULD_BLOCK;
while (status == WOULD_BLOCK) {
+ InputEvent* rawEventPtr = nullptr;
status = mConsumer.consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq,
- &event);
+ &rawEventPtr);
+ event = std::unique_ptr<InputEvent>(rawEventPtr);
std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
if (elapsed > timeout) {
break;
@@ -893,21 +894,17 @@
if (status == WOULD_BLOCK) {
// Just means there's no event available.
- return std::nullopt;
+ return std::make_pair(std::nullopt, nullptr);
}
if (status != OK) {
ADD_FAILURE() << mName.c_str() << ": consumer consume should return OK.";
- return std::nullopt;
+ return std::make_pair(std::nullopt, nullptr);
}
if (event == nullptr) {
ADD_FAILURE() << "Consumed correctly, but received NULL event from consumer";
- return std::nullopt;
}
- if (outEvent != nullptr) {
- *outEvent = event;
- }
- return consumeSeq;
+ return std::make_pair(consumeSeq, std::move(event));
}
/**
@@ -926,7 +923,7 @@
void consumeEvent(InputEventType expectedEventType, int32_t expectedAction,
std::optional<int32_t> expectedDisplayId,
std::optional<int32_t> expectedFlags) {
- InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
ASSERT_NE(nullptr, event) << mName.c_str()
<< ": consumer should have returned non-NULL event.";
@@ -970,8 +967,8 @@
}
}
- MotionEvent* consumeMotion() {
- InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ std::unique_ptr<MotionEvent> consumeMotion() {
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
if (event == nullptr) {
ADD_FAILURE() << mName << ": expected a MotionEvent, but didn't get one.";
@@ -982,17 +979,17 @@
ADD_FAILURE() << mName << " expected a MotionEvent, got " << *event;
return nullptr;
}
- return static_cast<MotionEvent*>(event);
+ return std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
}
void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
- MotionEvent* motionEvent = consumeMotion();
+ std::unique_ptr<MotionEvent> motionEvent = consumeMotion();
ASSERT_NE(nullptr, motionEvent) << "Did not get a motion event, but expected " << matcher;
ASSERT_THAT(*motionEvent, matcher);
}
void consumeFocusEvent(bool hasFocus, bool inTouchMode) {
- InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
ASSERT_NE(nullptr, event) << mName.c_str()
<< ": consumer should have returned non-NULL event.";
ASSERT_EQ(InputEventType::FOCUS, event->getType())
@@ -1001,12 +998,12 @@
ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
<< mName.c_str() << ": event displayId should always be NONE.";
- FocusEvent* focusEvent = static_cast<FocusEvent*>(event);
- EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
+ FocusEvent& focusEvent = static_cast<FocusEvent&>(*event);
+ EXPECT_EQ(hasFocus, focusEvent.getHasFocus());
}
void consumeCaptureEvent(bool hasCapture) {
- const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
ASSERT_NE(nullptr, event) << mName.c_str()
<< ": consumer should have returned non-NULL event.";
ASSERT_EQ(InputEventType::CAPTURE, event->getType())
@@ -1020,7 +1017,7 @@
}
void consumeDragEvent(bool isExiting, float x, float y) {
- const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
ASSERT_NE(nullptr, event) << mName.c_str()
<< ": consumer should have returned non-NULL event.";
ASSERT_EQ(InputEventType::DRAG, event->getType()) << "Instead of DragEvent, got " << *event;
@@ -1035,7 +1032,7 @@
}
void consumeTouchModeEvent(bool inTouchMode) {
- const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
ASSERT_NE(nullptr, event) << mName.c_str()
<< ": consumer should have returned non-NULL event.";
ASSERT_EQ(InputEventType::TOUCH_MODE, event->getType())
@@ -1048,7 +1045,7 @@
}
void assertNoEvents() {
- InputEvent* event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED);
if (event == nullptr) {
return;
}
@@ -1081,7 +1078,7 @@
private:
InputConsumer mConsumer;
- PreallocatedInputEventFactory mEventFactory;
+ DynamicInputEventFactory mEventFactory;
std::string mName;
};
@@ -1229,17 +1226,23 @@
void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); }
- const KeyEvent& consumeKey(bool handled = true) {
- const InputEvent& event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled);
- if (event.getType() != InputEventType::KEY) {
- LOG(FATAL) << "Instead of key event, got " << event;
+ std::unique_ptr<KeyEvent> consumeKey(bool handled = true) {
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED, handled);
+ if (event == nullptr) {
+ ADD_FAILURE() << "No event";
+ return nullptr;
}
- return static_cast<const KeyEvent&>(event);
+ if (event->getType() != InputEventType::KEY) {
+ ADD_FAILURE() << "Instead of key event, got " << event;
+ return nullptr;
+ }
+ return std::unique_ptr<KeyEvent>(static_cast<KeyEvent*>(event.release()));
}
void consumeKeyEvent(const ::testing::Matcher<KeyEvent>& matcher) {
- const KeyEvent& keyEvent = consumeKey();
- ASSERT_THAT(keyEvent, matcher);
+ std::unique_ptr<KeyEvent> keyEvent = consumeKey();
+ ASSERT_NE(nullptr, keyEvent);
+ ASSERT_THAT(*keyEvent, matcher);
}
void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
@@ -1325,14 +1328,20 @@
mInputReceiver->consumeCaptureEvent(hasCapture);
}
- const MotionEvent& consumeMotionEvent(
+ std::unique_ptr<MotionEvent> consumeMotionEvent(
const ::testing::Matcher<MotionEvent>& matcher = testing::_) {
- const InputEvent& event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
- if (event.getType() != InputEventType::MOTION) {
- LOG(FATAL) << "Instead of motion event, got " << event;
+ std::unique_ptr<InputEvent> event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ if (event == nullptr) {
+ ADD_FAILURE() << "No event";
+ return nullptr;
}
- const auto& motionEvent = static_cast<const MotionEvent&>(event);
- EXPECT_THAT(motionEvent, matcher);
+ if (event->getType() != InputEventType::MOTION) {
+ ADD_FAILURE() << "Instead of motion event, got " << *event;
+ return nullptr;
+ }
+ std::unique_ptr<MotionEvent> motionEvent =
+ std::unique_ptr<MotionEvent>(static_cast<MotionEvent*>(event.release()));
+ EXPECT_THAT(*motionEvent, matcher);
return motionEvent;
}
@@ -1346,12 +1355,12 @@
mInputReceiver->consumeTouchModeEvent(inTouchMode);
}
- std::optional<uint32_t> receiveEvent(InputEvent** outEvent = nullptr) {
+ std::pair<std::optional<uint32_t>, std::unique_ptr<InputEvent>> receiveEvent() {
if (mInputReceiver == nullptr) {
ADD_FAILURE() << "Invalid receive event on window with no receiver";
- return std::nullopt;
+ return std::make_pair(std::nullopt, nullptr);
}
- return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED, outEvent);
+ return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
}
void finishEvent(uint32_t sequenceNum) {
@@ -1396,15 +1405,15 @@
static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger
friend class sp<FakeWindowHandle>;
- const InputEvent& consume(std::chrono::milliseconds timeout, bool handled = true) {
+ std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout, bool handled = true) {
if (mInputReceiver == nullptr) {
LOG(FATAL) << "Cannot consume event from a window with no input event receiver";
}
- InputEvent* event = mInputReceiver->consume(timeout, handled);
+ std::unique_ptr<InputEvent> event = mInputReceiver->consume(timeout, handled);
if (event == nullptr) {
- LOG(FATAL) << "Consume failed: no event";
+ ADD_FAILURE() << "Consume failed: no event";
}
- return *event;
+ return event;
}
};
@@ -1423,7 +1432,8 @@
}
std::optional<int32_t> receiveEvent() {
- return mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ const auto [sequenceNum, _] = mInputReceiver.receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
+ return sequenceNum;
}
void finishEvent(uint32_t consumeSeq) { return mInputReceiver.finishEvent(consumeSeq); }
@@ -1461,7 +1471,7 @@
mInputReceiver.consumeMotionEvent(matcher);
}
- MotionEvent* consumeMotion() { return mInputReceiver.consumeMotion(); }
+ std::unique_ptr<MotionEvent> consumeMotion() { return mInputReceiver.consumeMotion(); }
void assertNoEvents() { mInputReceiver.assertNoEvents(); }
@@ -3779,18 +3789,20 @@
mDispatcher->waitForIdle();
- const MotionEvent& motionEvent1 = window1->consumeMotionEvent();
+ std::unique_ptr<MotionEvent> motionEvent1 = window1->consumeMotionEvent();
+ ASSERT_NE(nullptr, motionEvent1);
window2->assertNoEvents();
- nsecs_t downTimeForWindow1 = motionEvent1.getDownTime();
- ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime());
+ nsecs_t downTimeForWindow1 = motionEvent1->getDownTime();
+ ASSERT_EQ(motionEvent1->getDownTime(), motionEvent1->getEventTime());
// Now touch down on the window with another pointer
mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}));
mDispatcher->waitForIdle();
- const MotionEvent& motionEvent2 = window2->consumeMotionEvent();
- nsecs_t downTimeForWindow2 = motionEvent2.getDownTime();
+ std::unique_ptr<MotionEvent> motionEvent2 = window2->consumeMotionEvent();
+ ASSERT_NE(nullptr, motionEvent2);
+ nsecs_t downTimeForWindow2 = motionEvent2->getDownTime();
ASSERT_NE(downTimeForWindow1, downTimeForWindow2);
- ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime());
+ ASSERT_EQ(motionEvent2->getDownTime(), motionEvent2->getEventTime());
// Now move the pointer on the second window
mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}));
@@ -4624,12 +4636,13 @@
InputEventInjectionSync::WAIT_FOR_RESULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- const MotionEvent& event = window->consumeMotionEvent();
- EXPECT_EQ(POINTER_1_DOWN, event.getAction());
- EXPECT_EQ(70, event.getX(0)); // 50 + 20
- EXPECT_EQ(90, event.getY(0)); // 50 + 40
- EXPECT_EQ(-10, event.getX(1)); // -30 + 20
- EXPECT_EQ(-10, event.getY(1)); // -50 + 40
+ std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
+ ASSERT_NE(nullptr, event);
+ EXPECT_EQ(POINTER_1_DOWN, event->getAction());
+ EXPECT_EQ(70, event->getX(0)); // 50 + 20
+ EXPECT_EQ(90, event->getY(0)); // 50 + 40
+ EXPECT_EQ(-10, event->getX(1)); // -30 + 20
+ EXPECT_EQ(-10, event->getY(1)); // -50 + 40
}
/**
@@ -4895,15 +4908,16 @@
EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
// windowDefaultDisplay gets cancel
- const MotionEvent& event = windowDefaultDisplay->consumeMotionEvent();
- EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
+ std::unique_ptr<MotionEvent> event = windowDefaultDisplay->consumeMotionEvent();
+ ASSERT_NE(nullptr, event);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
// The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
// coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
// coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
// SECOND_DISPLAY_ID, the x and y coordinates are 200
- EXPECT_EQ(100, event.getX(0));
- EXPECT_EQ(100, event.getY(0));
+ EXPECT_EQ(100, event->getX(0));
+ EXPECT_EQ(100, event->getY(0));
}
/**
@@ -5033,18 +5047,19 @@
{PointF{150, 220}}));
firstWindow->assertNoEvents();
- const MotionEvent& event = secondWindow->consumeMotionEvent();
- EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event.getAction());
+ std::unique_ptr<MotionEvent> event = secondWindow->consumeMotionEvent();
+ ASSERT_NE(nullptr, event);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
// Ensure that the events from the "getRaw" API are in logical display coordinates.
- EXPECT_EQ(300, event.getRawX(0));
- EXPECT_EQ(880, event.getRawY(0));
+ EXPECT_EQ(300, event->getRawX(0));
+ EXPECT_EQ(880, event->getRawY(0));
// Ensure that the x and y values are in the window's coordinate space.
// The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
// the logical display space. This will be the origin of the window space.
- EXPECT_EQ(100, event.getX(0));
- EXPECT_EQ(80, event.getY(0));
+ EXPECT_EQ(100, event->getX(0));
+ EXPECT_EQ(80, event->getY(0));
}
TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
@@ -6081,7 +6096,8 @@
injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- MotionEvent* event = monitor.consumeMotion();
+ std::unique_ptr<MotionEvent> event = monitor.consumeMotion();
+ ASSERT_NE(nullptr, event);
// Even though window has transform, gesture monitor must not.
ASSERT_EQ(ui::Transform(), event->getTransform());
}
@@ -6188,9 +6204,9 @@
const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
mDispatcher->notifyKey(keyArgs);
- const KeyEvent& event = window->consumeKey();
-
- std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(event);
+ std::unique_ptr<KeyEvent> event = window->consumeKey();
+ ASSERT_NE(event, nullptr);
+ std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
ASSERT_NE(verified, nullptr);
ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
@@ -6231,9 +6247,9 @@
ADISPLAY_ID_DEFAULT);
mDispatcher->notifyMotion(motionArgs);
- const MotionEvent& event = window->consumeMotionEvent();
-
- std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(event);
+ std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
+ ASSERT_NE(nullptr, event);
+ std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
ASSERT_NE(verified, nullptr);
ASSERT_EQ(verified->type, VerifiedInputEvent::Type::MOTION);
@@ -6760,13 +6776,13 @@
ADISPLAY_ID_DEFAULT, {PointF{50, 50}});
mDispatcher->notifyMotion(notifyArgs);
- const MotionEvent& leftEnter = left->consumeMotionEvent(
+ std::unique_ptr<MotionEvent> leftEnter = left->consumeMotionEvent(
AllOf(WithMotionAction(ACTION_HOVER_ENTER), Not(WithEventId(notifyArgs.id)),
WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
-
+ ASSERT_NE(nullptr, leftEnter);
spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
Not(WithEventId(notifyArgs.id)),
- Not(WithEventId(leftEnter.getId())),
+ Not(WithEventId(leftEnter->getId())),
WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
// Send move to the right window, and ensure hover exit and enter are synthesized with new ids.
@@ -6774,13 +6790,13 @@
{PointF{150, 50}});
mDispatcher->notifyMotion(notifyArgs);
- const MotionEvent& leftExit = left->consumeMotionEvent(
+ std::unique_ptr<MotionEvent> leftExit = left->consumeMotionEvent(
AllOf(WithMotionAction(ACTION_HOVER_EXIT), Not(WithEventId(notifyArgs.id)),
WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
-
+ ASSERT_NE(nullptr, leftExit);
right->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER),
Not(WithEventId(notifyArgs.id)),
- Not(WithEventId(leftExit.getId())),
+ Not(WithEventId(leftExit->getId())),
WithEventIdSource(IdGenerator::Source::INPUT_DISPATCHER)));
spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithEventId(notifyArgs.id)));
@@ -6811,8 +6827,9 @@
}
void consumeKey(bool handled, const ::testing::Matcher<KeyEvent>& matcher) {
- const KeyEvent& event = mWindow->consumeKey(handled);
- ASSERT_THAT(event, matcher);
+ std::unique_ptr<KeyEvent> event = mWindow->consumeKey(handled);
+ ASSERT_NE(nullptr, event);
+ ASSERT_THAT(*event, matcher);
}
};
@@ -7146,9 +7163,10 @@
GTEST_SKIP() << "Flaky test (b/270393106)";
sendAndConsumeKeyDown(/*deviceId=*/1);
for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
- const KeyEvent& repeatEvent = mWindow->consumeKey();
+ std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
+ ASSERT_NE(nullptr, repeatEvent);
EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER,
- IdGenerator::getSource(repeatEvent.getId()));
+ IdGenerator::getSource(repeatEvent->getId()));
}
}
@@ -7158,8 +7176,9 @@
std::unordered_set<int32_t> idSet;
for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
- const KeyEvent& repeatEvent = mWindow->consumeKey();
- int32_t id = repeatEvent.getId();
+ std::unique_ptr<KeyEvent> repeatEvent = mWindow->consumeKey();
+ ASSERT_NE(nullptr, repeatEvent);
+ int32_t id = repeatEvent->getId();
EXPECT_EQ(idSet.end(), idSet.find(id));
idSet.insert(id);
}
@@ -7813,21 +7832,21 @@
void consumeMotionEvent(const sp<FakeWindowHandle>& window, int32_t expectedAction,
const std::vector<PointF>& points) {
const std::string name = window->getName();
- const MotionEvent& motionEvent =
+ std::unique_ptr<MotionEvent> motionEvent =
window->consumeMotionEvent(WithMotionAction(expectedAction));
-
- ASSERT_EQ(points.size(), motionEvent.getPointerCount());
+ ASSERT_NE(nullptr, motionEvent);
+ ASSERT_EQ(points.size(), motionEvent->getPointerCount());
for (size_t i = 0; i < points.size(); i++) {
float expectedX = points[i].x;
float expectedY = points[i].y;
- EXPECT_EQ(expectedX, motionEvent.getX(i))
+ EXPECT_EQ(expectedX, motionEvent->getX(i))
<< "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str()
- << ", got " << motionEvent.getX(i);
- EXPECT_EQ(expectedY, motionEvent.getY(i))
+ << ", got " << motionEvent->getX(i);
+ EXPECT_EQ(expectedY, motionEvent->getY(i))
<< "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str()
- << ", got " << motionEvent.getY(i);
+ << ", got " << motionEvent->getY(i);
}
}
@@ -8115,7 +8134,7 @@
injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
WINDOW_LOCATION));
- std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN
+ const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
@@ -8131,7 +8150,7 @@
TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
// Inject a key, and don't respond - expect that ANR is called.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher));
- std::optional<uint32_t> sequenceNum = mWindow->receiveEvent();
+ const auto [sequenceNum, _] = mWindow->receiveEvent();
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
@@ -8291,7 +8310,7 @@
WINDOW_LOCATION));
mWindow->consumeMotionDown();
- std::optional<uint32_t> sequenceNum = spy->receiveEvent(); // ACTION_DOWN
+ const auto [sequenceNum, _] = spy->receiveEvent(); // ACTION_DOWN
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy);
@@ -8446,9 +8465,9 @@
mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
tapOnWindow();
- std::optional<uint32_t> downSequenceNum = mWindow->receiveEvent();
+ const auto& [downSequenceNum, downEvent] = mWindow->receiveEvent();
ASSERT_TRUE(downSequenceNum);
- std::optional<uint32_t> upSequenceNum = mWindow->receiveEvent();
+ const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
ASSERT_TRUE(upSequenceNum);
// Don't finish the events yet, and send a key
// Injection will "succeed" because we will eventually give up and send the key to the focused
@@ -8486,9 +8505,9 @@
mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0});
tapOnWindow();
- std::optional<uint32_t> downSequenceNum = mWindow->receiveEvent();
+ const auto& [downSequenceNum, _] = mWindow->receiveEvent();
ASSERT_TRUE(downSequenceNum);
- std::optional<uint32_t> upSequenceNum = mWindow->receiveEvent();
+ const auto& [upSequenceNum, upEvent] = mWindow->receiveEvent();
ASSERT_TRUE(upSequenceNum);
// Don't finish the events yet, and send a key
mDispatcher->notifyKey(
@@ -8524,7 +8543,7 @@
.pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10))
.build());
- std::optional<uint32_t> sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN
+ const auto [sequenceNum, _] = mWindow->receiveEvent(); // ACTION_DOWN
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
@@ -8653,7 +8672,7 @@
.x(FOCUSED_WINDOW_LOCATION.x)
.y(FOCUSED_WINDOW_LOCATION.y))
.build()));
- std::optional<uint32_t> unfocusedSequenceNum = mUnfocusedWindow->receiveEvent();
+ const auto [unfocusedSequenceNum, _] = mUnfocusedWindow->receiveEvent();
ASSERT_TRUE(unfocusedSequenceNum);
const std::chrono::duration timeout =
@@ -8718,9 +8737,9 @@
tapOnFocusedWindow();
mUnfocusedWindow->consumeMotionOutside(ADISPLAY_ID_DEFAULT, /*flags=*/0);
// Receive the events, but don't respond
- std::optional<uint32_t> downEventSequenceNum = mFocusedWindow->receiveEvent(); // ACTION_DOWN
+ const auto [downEventSequenceNum, downEvent] = mFocusedWindow->receiveEvent(); // ACTION_DOWN
ASSERT_TRUE(downEventSequenceNum);
- std::optional<uint32_t> upEventSequenceNum = mFocusedWindow->receiveEvent(); // ACTION_UP
+ const auto [upEventSequenceNum, upEvent] = mFocusedWindow->receiveEvent(); // ACTION_UP
ASSERT_TRUE(upEventSequenceNum);
const std::chrono::duration timeout =
mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -8798,9 +8817,9 @@
{{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0});
tapOnUnfocusedWindow();
- std::optional<uint32_t> downSequenceNum = mUnfocusedWindow->receiveEvent();
+ const auto [downSequenceNum, downEvent] = mUnfocusedWindow->receiveEvent();
ASSERT_TRUE(downSequenceNum);
- std::optional<uint32_t> upSequenceNum = mUnfocusedWindow->receiveEvent();
+ const auto [upSequenceNum, upEvent] = mUnfocusedWindow->receiveEvent();
ASSERT_TRUE(upSequenceNum);
// Don't finish the events yet, and send a key
// Injection will succeed because we will eventually give up and send the key to the focused
@@ -8863,8 +8882,7 @@
mFocusedWindow->consumeMotionDown();
// Focused window may or may not receive ACTION_MOVE
// But it should definitely receive ACTION_CANCEL due to the ANR
- InputEvent* event;
- std::optional<int32_t> moveOrCancelSequenceNum = mFocusedWindow->receiveEvent(&event);
+ const auto [moveOrCancelSequenceNum, event] = mFocusedWindow->receiveEvent();
ASSERT_TRUE(moveOrCancelSequenceNum);
mFocusedWindow->finishEvent(*moveOrCancelSequenceNum);
ASSERT_NE(nullptr, event);
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 1ac043c..e9e5061 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -1557,4 +1557,122 @@
mousePc->assertPointerIconNotSet();
}
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) {
+ // Make sure there are two PointerControllers on different displays.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
+ auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId());
+ auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId());
+
+ // Both pointers should be visible.
+ ASSERT_TRUE(firstMousePc->isPointerShown());
+ ASSERT_TRUE(secondMousePc->isPointerShown());
+
+ // Hide the icon on the second display.
+ mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, false);
+ ASSERT_TRUE(firstMousePc->isPointerShown());
+ ASSERT_FALSE(secondMousePc->isPointerShown());
+
+ // Move and set pointer icons for both mice. The second pointer should still be hidden.
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(ANOTHER_DISPLAY_ID)
+ .build());
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ ASSERT_TRUE(firstMousePc->isPointerShown());
+ ASSERT_FALSE(secondMousePc->isPointerShown());
+
+ // Allow the icon to be visible on the second display, and move the mouse.
+ mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, true);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(ANOTHER_DISPLAY_ID)
+ .build());
+ ASSERT_TRUE(firstMousePc->isPointerShown());
+ ASSERT_TRUE(secondMousePc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) {
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+
+ // Hide the pointer on the display, and then connect the mouse.
+ mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(DISPLAY_ID, mousePc->getDisplayId());
+
+ // The pointer should not be visible.
+ ASSERT_FALSE(mousePc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) {
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+
+ // Hide the pointer on the display.
+ mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ADISPLAY_ID_NONE)}});
+ auto touchpadPc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(DISPLAY_ID, touchpadPc->getDisplayId());
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
+ AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD)
+ .pointer(TOUCHPAD_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+
+ // The pointer should not be visible.
+ ASSERT_FALSE(touchpadPc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) {
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setStylusPointerIconEnabled(true);
+
+ // Hide the pointer on the display.
+ mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+
+ // The pointer should not be visible.
+ ASSERT_FALSE(pc->isPointerShown());
+}
+
} // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 45fab7e..8e9dfea 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -16,13 +16,6 @@
#include "SensorDevice.h"
-#include "android/hardware/sensors/2.0/types.h"
-#include "android/hardware/sensors/2.1/types.h"
-#include "convertV2_1.h"
-
-#include "AidlSensorHalWrapper.h"
-#include "HidlSensorHalWrapper.h"
-
#include <android-base/logging.h>
#include <android/util/ProtoOutputStream.h>
#include <com_android_frameworks_sensorservice_flags.h>
@@ -36,10 +29,16 @@
#include <chrono>
#include <cinttypes>
-#include <cstddef>
-#include <thread>
-#include <mutex>
#include <condition_variable>
+#include <cstddef>
+#include <mutex>
+#include <thread>
+
+#include "AidlSensorHalWrapper.h"
+#include "HidlSensorHalWrapper.h"
+#include "android/hardware/sensors/2.0/types.h"
+#include "android/hardware/sensors/2.1/types.h"
+#include "convertV2_1.h"
using namespace android::hardware::sensors;
using android::util::ProtoOutputStream;
@@ -168,6 +167,9 @@
mActivationCount.clear();
mSensorList.clear();
+ if (sensorservice_flags::dynamic_sensor_hal_reconnect_handling()) {
+ mConnectedDynamicSensors.clear();
+ }
if (mHalWrapper->connect(this)) {
initializeSensorList();
@@ -342,6 +344,15 @@
}
}
+std::vector<int32_t> SensorDevice::getDynamicSensorHandles() {
+ std::vector<int32_t> sensorHandles;
+ std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+ for (auto& sensors : mConnectedDynamicSensors) {
+ sensorHandles.push_back(sensors.first);
+ }
+ return sensorHandles;
+}
+
ssize_t SensorDevice::getSensorList(sensor_t const** list) {
*list = &mSensorList[0];
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index f127c0f..52f7cf2 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -60,6 +60,8 @@
ssize_t getSensorList(sensor_t const** list);
+ std::vector<int32_t> getDynamicSensorHandles();
+
void handleDynamicSensorConnection(int handle, bool connected);
status_t initCheck() const;
int getHalDeviceVersion() const;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 85043c9..e1c43c6 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "SensorService.h"
+
#include <aidl/android/hardware/sensors/ISensors.h>
#include <android-base/strings.h>
#include <android/content/pm/IPackageManagerNative.h>
@@ -22,20 +24,36 @@
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
#include <binder/PermissionController.h>
+#include <com_android_frameworks_sensorservice_flags.h>
#include <cutils/ashmem.h>
#include <cutils/misc.h>
#include <cutils/properties.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
#include <hardware_legacy/power.h>
+#include <inttypes.h>
#include <log/log.h>
+#include <math.h>
#include <openssl/digest.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
+#include <private/android_filesystem_config.h>
+#include <sched.h>
#include <sensor/SensorEventQueue.h>
#include <sensorprivacy/SensorPrivacyManager.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <utils/SystemClock.h>
+#include <condition_variable>
+#include <ctime>
+#include <future>
+#include <mutex>
+#include <string>
+
#include "BatteryService.h"
#include "CorrectedGyroSensor.h"
#include "GravitySensor.h"
@@ -43,35 +61,17 @@
#include "LinearAccelerationSensor.h"
#include "OrientationSensor.h"
#include "RotationVectorSensor.h"
-#include "SensorFusion.h"
-#include "SensorInterface.h"
-
-#include "SensorService.h"
#include "SensorDirectConnection.h"
#include "SensorEventAckReceiver.h"
#include "SensorEventConnection.h"
+#include "SensorFusion.h"
+#include "SensorInterface.h"
#include "SensorRecord.h"
#include "SensorRegistrationInfo.h"
#include "SensorServiceUtils.h"
-#include <inttypes.h>
-#include <math.h>
-#include <sched.h>
-#include <stdint.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <condition_variable>
-#include <ctime>
-#include <future>
-#include <mutex>
-#include <string>
-
-#include <private/android_filesystem_config.h>
-
using namespace std::chrono_literals;
+namespace sensorservice_flags = com::android::frameworks::sensorservice::flags;
namespace android {
// ---------------------------------------------------------------------------
@@ -335,6 +335,11 @@
case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
hasGyroUncalibrated = true;
break;
+ case SENSOR_TYPE_DYNAMIC_SENSOR_META:
+ if (sensorservice_flags::dynamic_sensor_hal_reconnect_handling()) {
+ mDynamicMetaSensorHandle = list[i].handle;
+ }
+ break;
case SENSOR_TYPE_GRAVITY:
case SENSOR_TYPE_LINEAR_ACCELERATION:
case SENSOR_TYPE_ROTATION_VECTOR:
@@ -1055,6 +1060,68 @@
}
}
+void SensorService::sendEventsToAllClients(
+ const std::vector<sp<SensorEventConnection>>& activeConnections,
+ ssize_t count) {
+ // Send our events to clients. Check the state of wake lock for each client
+ // and release the lock if none of the clients need it.
+ bool needsWakeLock = false;
+ for (const sp<SensorEventConnection>& connection : activeConnections) {
+ connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
+ mMapFlushEventsToConnections);
+ needsWakeLock |= connection->needsWakeLock();
+ // If the connection has one-shot sensors, it may be cleaned up after
+ // first trigger. Early check for one-shot sensors.
+ if (connection->hasOneShotSensors()) {
+ cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count);
+ }
+ }
+
+ if (mWakeLockAcquired && !needsWakeLock) {
+ setWakeLockAcquiredLocked(false);
+ }
+}
+
+void SensorService::disconnectDynamicSensor(
+ int handle,
+ const std::vector<sp<SensorEventConnection>>& activeConnections) {
+ ALOGI("Dynamic sensor handle 0x%x disconnected", handle);
+ SensorDevice::getInstance().handleDynamicSensorConnection(
+ handle, false /*connected*/);
+ if (!unregisterDynamicSensorLocked(handle)) {
+ ALOGE("Dynamic sensor release error.");
+ }
+ for (const sp<SensorEventConnection>& connection : activeConnections) {
+ connection->removeSensor(handle);
+ }
+}
+
+void SensorService::handleDeviceReconnection(SensorDevice& device) {
+ if (sensorservice_flags::dynamic_sensor_hal_reconnect_handling()) {
+ const std::vector<sp<SensorEventConnection>> activeConnections =
+ mConnectionHolder.lock(mLock).getActiveConnections();
+
+ for (int32_t handle : device.getDynamicSensorHandles()) {
+ if (mDynamicMetaSensorHandle.has_value()) {
+ // Sending one event at a time to prevent the number of handle is more than the
+ // buffer can hold.
+ mSensorEventBuffer[0].type = SENSOR_TYPE_DYNAMIC_SENSOR_META;
+ mSensorEventBuffer[0].sensor = *mDynamicMetaSensorHandle;
+ mSensorEventBuffer[0].dynamic_sensor_meta.connected = false;
+ mSensorEventBuffer[0].dynamic_sensor_meta.handle = handle;
+ mMapFlushEventsToConnections[0] = nullptr;
+
+ disconnectDynamicSensor(handle, activeConnections);
+ sendEventsToAllClients(activeConnections, 1);
+ } else {
+ ALOGE("Failed to find mDynamicMetaSensorHandle during init.");
+ break;
+ }
+ }
+ }
+ device.reconnect();
+}
+
bool SensorService::threadLoop() {
ALOGD("nuSensorService thread starting...");
@@ -1071,8 +1138,8 @@
do {
ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
if (count < 0) {
- if(count == DEAD_OBJECT && device.isReconnecting()) {
- device.reconnect();
+ if (count == DEAD_OBJECT && device.isReconnecting()) {
+ handleDeviceReconnection(device);
continue;
} else {
ALOGE("sensor poll failed (%s)", strerror(-count));
@@ -1176,7 +1243,6 @@
rec->removeFirstPendingFlushConnection();
}
}
-
// handle dynamic sensor meta events, process registration and unregistration of dynamic
// sensor based on content of event.
if (mSensorEventBuffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
@@ -1206,37 +1272,14 @@
}
} else {
int handle = mSensorEventBuffer[i].dynamic_sensor_meta.handle;
- ALOGI("Dynamic sensor handle 0x%x disconnected", handle);
-
- device.handleDynamicSensorConnection(handle, false /*connected*/);
- if (!unregisterDynamicSensorLocked(handle)) {
- ALOGE("Dynamic sensor release error.");
- }
-
- for (const sp<SensorEventConnection>& connection : activeConnections) {
- connection->removeSensor(handle);
- }
+ disconnectDynamicSensor(handle, activeConnections);
}
}
}
// Send our events to clients. Check the state of wake lock for each client and release the
// lock if none of the clients need it.
- bool needsWakeLock = false;
- for (const sp<SensorEventConnection>& connection : activeConnections) {
- connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
- mMapFlushEventsToConnections);
- needsWakeLock |= connection->needsWakeLock();
- // If the connection has one-shot sensors, it may be cleaned up after first trigger.
- // Early check for one-shot sensors.
- if (connection->hasOneShotSensors()) {
- cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count);
- }
- }
-
- if (mWakeLockAcquired && !needsWakeLock) {
- setWakeLockAcquiredLocked(false);
- }
+ sendEventsToAllClients(activeConnections, count);
} while (!Thread::exitPending());
ALOGW("Exiting SensorService::threadLoop => aborting...");
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index b643f6b..ad10e7a 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -17,9 +17,6 @@
#ifndef ANDROID_SENSOR_SERVICE_H
#define ANDROID_SENSOR_SERVICE_H
-#include "SensorList.h"
-#include "RecentEventLogger.h"
-
#include <android-base/macros.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
@@ -27,11 +24,11 @@
#include <cutils/compiler.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
-#include <sensor/ISensorServer.h>
#include <sensor/ISensorEventConnection.h>
+#include <sensor/ISensorServer.h>
#include <sensor/Sensor.h>
-#include "android/hardware/BnSensorPrivacyListener.h"
-
+#include <stdint.h>
+#include <sys/types.h>
#include <utils/AndroidThreads.h>
#include <utils/KeyedVector.h>
#include <utils/Looper.h>
@@ -40,8 +37,6 @@
#include <utils/Vector.h>
#include <utils/threads.h>
-#include <stdint.h>
-#include <sys/types.h>
#include <condition_variable>
#include <mutex>
#include <queue>
@@ -49,6 +44,10 @@
#include <unordered_set>
#include <vector>
+#include "RecentEventLogger.h"
+#include "SensorList.h"
+#include "android/hardware/BnSensorPrivacyListener.h"
+
#if __clang__
// Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable
// without changing the API, so let's tell clang this is indeed intentional.
@@ -57,7 +56,7 @@
// ---------------------------------------------------------------------------
#define IGNORE_HARDWARE_FUSION false
-#define DEBUG_CONNECTIONS false
+#define DEBUG_CONNECTIONS false
// Max size is 100 KB which is enough to accept a batch of about 1000 events.
#define MAX_SOCKET_BUFFER_SIZE_BATCHED (100 * 1024)
// For older HALs which don't support batching, use a smaller socket buffer size.
@@ -453,6 +452,11 @@
// Send events from the event cache for this particular connection.
void sendEventsFromCache(const sp<SensorEventConnection>& connection);
+ // Send all events in the buffer to all clients.
+ void sendEventsToAllClients(
+ const std::vector<sp<SensorEventConnection>>& activeConnections,
+ ssize_t count);
+
// If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
// allowed to register for or call flush on sensors. Typically only cts test packages are
// allowed.
@@ -516,6 +520,14 @@
bool isInjectionMode(int mode);
+ void handleDeviceReconnection(SensorDevice& device);
+
+ // Removes a connected dynamic sensor and send the corresponding event to
+ // all connections.
+ void disconnectDynamicSensor(
+ int handle,
+ const std::vector<sp<SensorEventConnection>>& activeConnections);
+
static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
}
@@ -583,6 +595,10 @@
bool mLastReportedProxIsActive;
// Listeners subscribed to receive updates on the proximity sensor active state.
std::vector<sp<ProximityActiveListener>> mProximityActiveListeners;
+
+ // Stores the handle of the dynamic_meta sensor to send clean up event once
+ // HAL crashes.
+ std::optional<int> mDynamicMetaSensorHandle;
};
} // namespace android
diff --git a/services/surfaceflinger/Display/DisplayModeRequest.h b/services/surfaceflinger/Display/DisplayModeRequest.h
index c0e77bb..d07cdf5 100644
--- a/services/surfaceflinger/Display/DisplayModeRequest.h
+++ b/services/surfaceflinger/Display/DisplayModeRequest.h
@@ -27,9 +27,6 @@
// Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE.
bool emitEvent = false;
-
- // Whether to force the request to be applied, even if the mode is unchanged.
- bool force = false;
};
inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b96264b..799d62c 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -24,7 +24,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <common/FlagManager.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
@@ -222,17 +221,6 @@
bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline& outTimeline) {
- // TODO(b/255635711): Flow the DisplayModeRequest through the desired/pending/active states. For
- // now, `desiredMode` and `mDesiredModeOpt` are one and the same, but the latter is not cleared
- // until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been consumed
- // at this point, so clear the `force` flag to prevent an endless loop of `initiateModeChange`.
- if (FlagManager::getInstance().connected_display()) {
- std::scoped_lock lock(mDesiredModeLock);
- if (mDesiredModeOpt) {
- mDesiredModeOpt->force = false;
- }
- }
-
mPendingModeOpt = std::move(desiredMode);
mIsModeSetPending = true;
@@ -538,7 +526,8 @@
}
}
-auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode) -> DesiredModeAction {
+auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode, bool force)
+ -> DesiredModeAction {
ATRACE_CALL();
const auto& desiredModePtr = desiredMode.mode.modePtr;
@@ -546,26 +535,20 @@
LOG_ALWAYS_FATAL_IF(getPhysicalId() != desiredModePtr->getPhysicalDisplayId(),
"DisplayId mismatch");
- // TODO (b/318533819): Stringize DisplayModeRequest.
- ALOGD("%s(%s, force=%s)", __func__, to_string(*desiredModePtr).c_str(),
- desiredMode.force ? "true" : "false");
+ ALOGV("%s(%s)", __func__, to_string(*desiredModePtr).c_str());
std::scoped_lock lock(mDesiredModeLock);
if (mDesiredModeOpt) {
// A mode transition was already scheduled, so just override the desired mode.
const bool emitEvent = mDesiredModeOpt->emitEvent;
- const bool force = mDesiredModeOpt->force;
mDesiredModeOpt = std::move(desiredMode);
mDesiredModeOpt->emitEvent |= emitEvent;
- if (FlagManager::getInstance().connected_display()) {
- mDesiredModeOpt->force |= force;
- }
return DesiredModeAction::None;
}
// If the desired mode is already active...
const auto activeMode = refreshRateSelector().getActiveMode();
- if (!desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
+ if (!force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
if (activeMode == desiredMode.mode) {
return DesiredModeAction::None;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 46534de..97b56a2 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -189,7 +189,8 @@
enum class DesiredModeAction { None, InitiateDisplayModeSwitch, InitiateRenderRateSwitch };
- DesiredModeAction setDesiredMode(display::DisplayModeRequest&&) EXCLUDES(mDesiredModeLock);
+ DesiredModeAction setDesiredMode(display::DisplayModeRequest&&, bool force = false)
+ EXCLUDES(mDesiredModeLock);
using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index db66f5b..704ece5 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -27,7 +27,6 @@
#include "HWC2.h"
#include <android/configuration.h>
-#include <common/FlagManager.h>
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
@@ -417,19 +416,7 @@
VsyncPeriodChangeTimeline* outTimeline) {
ALOGV("[%" PRIu64 "] setActiveConfigWithConstraints", mId);
- // FIXME (b/319505580): At least the first config set on an external display must be
- // `setActiveConfig`, so skip over the block that calls `setActiveConfigWithConstraints`
- // for simplicity.
- ui::DisplayConnectionType type = ui::DisplayConnectionType::Internal;
- const bool connected_display = FlagManager::getInstance().connected_display();
- if (connected_display) {
- if (auto err = getConnectionType(&type); err != Error::NONE) {
- return err;
- }
- }
-
- if (isVsyncPeriodSwitchSupported() &&
- (!connected_display || type != ui::DisplayConnectionType::External)) {
+ if (isVsyncPeriodSwitchSupported()) {
Hwc2::IComposerClient::VsyncPeriodChangeConstraints hwc2Constraints;
hwc2Constraints.desiredTimeNanos = constraints.desiredTimeNanos;
hwc2Constraints.seamlessRequired = constraints.seamlessRequired;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index bb32afa..8df5d8c 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -587,8 +587,8 @@
bool LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
if (!mResortSnapshots && args.forceUpdate == ForceUpdateFlags::NONE &&
!args.layerLifecycleManager.getGlobalChanges().any(
- RequestedLayerState::Changes::Hierarchy |
- RequestedLayerState::Changes::Visibility)) {
+ RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility |
+ RequestedLayerState::Changes::Input)) {
// We are not force updating and there are no hierarchy or visibility changes. Avoid sorting
// the snapshots.
return false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31d120d..6910a57 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -492,14 +492,6 @@
mSupportsBlur = supportsBlurs;
ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported.");
- const size_t defaultListSize = MAX_LAYERS;
- auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
- mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
- mGraphicBufferProducerListSizeLogThreshold =
- std::max(static_cast<int>(0.95 *
- static_cast<double>(mMaxGraphicBufferProducerListSize)),
- 1);
-
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
@@ -1235,10 +1227,8 @@
return NO_ERROR;
}
-void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) {
- const auto mode = desiredMode.mode;
- const auto displayId = mode.modePtr->getPhysicalDisplayId();
-
+void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) {
+ const auto displayId = request.mode.modePtr->getPhysicalDisplayId();
ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
const auto display = getDisplayDeviceLocked(displayId);
@@ -1247,9 +1237,10 @@
return;
}
- const bool emitEvent = desiredMode.emitEvent;
+ const auto mode = request.mode;
+ const bool emitEvent = request.emitEvent;
- switch (display->setDesiredMode(std::move(desiredMode))) {
+ switch (display->setDesiredMode(std::move(request), force)) {
case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch:
// DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler.
mScheduler->setRenderRate(displayId,
@@ -1435,8 +1426,7 @@
to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(),
to_string(display->getId()).c_str());
- if ((!FlagManager::getInstance().connected_display() || !desiredModeOpt->force) &&
- display->getActiveMode() == desiredModeOpt->mode) {
+ if (display->getActiveMode() == desiredModeOpt->mode) {
applyActiveMode(display);
continue;
}
@@ -3302,88 +3292,14 @@
std::vector<HWComposer::HWCDisplayMode> hwcModes;
std::optional<hal::HWDisplayId> activeModeHwcId;
- const bool isExternalDisplay = FlagManager::getInstance().connected_display() &&
- getHwComposer().getDisplayConnectionType(displayId) ==
- ui::DisplayConnectionType::External;
-
int attempt = 0;
constexpr int kMaxAttempts = 3;
do {
hwcModes = getHwComposer().getModes(displayId,
scheduler::RefreshRateSelector::kMinSupportedFrameRate
.getPeriodNsecs());
-
activeModeHwcId = getHwComposer().getActiveMode(displayId);
- if (isExternalDisplay) {
- constexpr nsecs_t k59HzVsyncPeriod = 16949153;
- constexpr nsecs_t k60HzVsyncPeriod = 16666667;
-
- // DM sets the initial mode for an external display to 1080p@60, but
- // this comes after SF creates its own state (including the
- // DisplayDevice). For now, pick the same mode in order to avoid
- // inconsistent state and unnecessary mode switching.
- // TODO (b/318534874): Let DM decide the initial mode.
- //
- // Try to find 1920x1080 @ 60 Hz
- if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(),
- [](const auto& mode) {
- return mode.width == 1920 &&
- mode.height == 1080 &&
- mode.vsyncPeriod == k60HzVsyncPeriod;
- });
- iter != hwcModes.end()) {
- activeModeHwcId = iter->hwcId;
- break;
- }
-
- // Try to find 1920x1080 @ 59-60 Hz
- if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(),
- [](const auto& mode) {
- return mode.width == 1920 &&
- mode.height == 1080 &&
- mode.vsyncPeriod >= k60HzVsyncPeriod &&
- mode.vsyncPeriod <= k59HzVsyncPeriod;
- });
- iter != hwcModes.end()) {
- activeModeHwcId = iter->hwcId;
- break;
- }
-
- // The display does not support 1080p@60, and this is the last attempt to pick a display
- // mode. Prefer 60 Hz if available, with the closest resolution to 1080p.
- if (attempt + 1 == kMaxAttempts) {
- std::vector<HWComposer::HWCDisplayMode> hwcModeOpts;
-
- for (const auto& mode : hwcModes) {
- if (mode.width <= 1920 && mode.height <= 1080 &&
- mode.vsyncPeriod >= k60HzVsyncPeriod &&
- mode.vsyncPeriod <= k59HzVsyncPeriod) {
- hwcModeOpts.push_back(mode);
- }
- }
-
- if (const auto iter = std::max_element(hwcModeOpts.begin(), hwcModeOpts.end(),
- [](const auto& a, const auto& b) {
- const auto aSize = a.width * a.height;
- const auto bSize = b.width * b.height;
- if (aSize < bSize)
- return true;
- else if (aSize == bSize)
- return a.vsyncPeriod > b.vsyncPeriod;
- else
- return false;
- });
- iter != hwcModeOpts.end()) {
- activeModeHwcId = iter->hwcId;
- break;
- }
-
- // hwcModeOpts was empty, use hwcModes[0] as the last resort
- activeModeHwcId = hwcModes[0].hwcId;
- }
- }
-
const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) {
return mode.hwcId == activeModeHwcId;
};
@@ -3443,10 +3359,6 @@
return pair.second->getHwcId() == activeModeHwcId;
})->second;
- if (isExternalDisplay) {
- ALOGI("External display %s initial mode: {%s}", to_string(displayId).c_str(),
- to_string(*activeMode).c_str());
- }
return {modes, activeMode};
}
@@ -3753,27 +3665,6 @@
}
mDisplays.try_emplace(displayToken, std::move(display));
-
- // For an external display, loadDisplayModes already selected the same mode
- // as DM, but SF still needs to be updated to match.
- // TODO (b/318534874): Let DM decide the initial mode.
- if (const auto& physical = state.physical;
- mScheduler && physical && FlagManager::getInstance().connected_display()) {
- const bool isInternalDisplay = mPhysicalDisplays.get(physical->id)
- .transform(&PhysicalDisplay::isInternal)
- .value_or(false);
-
- if (!isInternalDisplay) {
- auto activeModePtr = physical->activeMode;
- const auto fps = activeModePtr->getPeakFps();
-
- setDesiredMode(
- {.mode = scheduler::FrameRateMode{fps,
- ftl::as_non_null(std::move(activeModePtr))},
- .emitEvent = false,
- .force = true});
- }
- }
}
void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
@@ -8442,7 +8333,7 @@
return INVALID_OPERATION;
}
- setDesiredMode({std::move(preferredMode), .emitEvent = true, .force = force});
+ setDesiredMode({std::move(preferredMode), .emitEvent = true}, force);
// Update the frameRateOverride list as the display render rate might have changed
if (mScheduler->updateFrameRateOverrides(scheduler::GlobalSignals{}, preferredFps)) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b23b519..6e12172 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -718,7 +718,7 @@
// Show hdr sdr ratio overlay
bool mHdrSdrRatioOverlay = false;
- void setDesiredMode(display::DisplayModeRequest&&) REQUIRES(mStateLock);
+ void setDesiredMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock);
status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId, Fps minFps,
Fps maxFps);
@@ -1212,12 +1212,6 @@
float mGlobalSaturationFactor = 1.0f;
mat4 mClientColorMatrix;
- size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
- // If there are more GraphicBufferProducers tracked by SurfaceFlinger than
- // this threshold, then begin logging.
- size_t mGraphicBufferProducerListSizeLogThreshold =
- static_cast<size_t>(0.95 * static_cast<double>(MAX_LAYERS));
-
// protected by mStateLock (but we could use another lock)
bool mLayersRemoved = false;
bool mLayersAdded = false;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 99fef7e..6671414 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -447,11 +447,9 @@
? IComposerClient::DisplayConnectionType::INTERNAL
: IComposerClient::DisplayConnectionType::EXTERNAL;
- using ::testing::AtLeast;
EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
- .Times(AtLeast(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(CONNECTION_TYPE),
- Return(hal::V2_4::Error::NONE)));
+ .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE),
+ Return(hal::V2_4::Error::NONE)));
}
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 6394d63..13b47ff 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -64,6 +64,18 @@
actualBuilder.update(args);
}
+ void update(LayerSnapshotBuilder& actualBuilder) {
+ LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = true,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {}};
+ update(actualBuilder, args);
+ }
+
void updateAndVerify(LayerSnapshotBuilder& actualBuilder, bool hasDisplayChanges,
const std::vector<uint32_t> expectedVisibleLayerIdsInZOrder) {
LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
@@ -1199,4 +1211,30 @@
EXPECT_EQ(getSnapshot(11)->dropInputMode, gui::DropInputMode::ALL);
}
+TEST_F(LayerSnapshotTest, NonVisibleLayerWithInput) {
+ LayerHierarchyTestBase::createRootLayer(3);
+ setColor(3, {-1._hf, -1._hf, -1._hf});
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
+ transactions.back().states.front().layerId = 3;
+ transactions.back().states.front().state.windowInfoHandle = sp<gui::WindowInfoHandle>::make();
+ auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ inputInfo->token = sp<BBinder>::make();
+ mLifecycleManager.applyTransactions(transactions);
+
+ update(mSnapshotBuilder);
+
+ bool foundInputLayer = false;
+ mSnapshotBuilder.forEachInputSnapshot([&](const frontend::LayerSnapshot& snapshot) {
+ if (snapshot.uniqueSequence == 3) {
+ foundInputLayer = true;
+ }
+ });
+ EXPECT_TRUE(foundInputLayer);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 82b4ad0..8b16a8a 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -21,13 +21,9 @@
#include "mock/DisplayHardware/MockDisplayMode.h"
#include "mock/MockDisplayModeSpecs.h"
-#include <com_android_graphics_surfaceflinger_flags.h>
-#include <common/test/FlagUtils.h>
#include <ftl/fake_guard.h>
#include <scheduler/Fps.h>
-using namespace com::android::graphics::surfaceflinger;
-
namespace android {
namespace {
@@ -364,13 +360,6 @@
}
TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
- // For the inner display, this is handled by setupHwcHotplugCallExpectations.
- EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
- .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
- Return(hal::V2_4::Error::NONE)));
-
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -440,12 +429,6 @@
}
TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
- // For the inner display, this is handled by setupHwcHotplugCallExpectations.
- EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
- .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
- Return(hal::V2_4::Error::NONE)));
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -529,13 +512,6 @@
}
TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
- // For the inner display, this is handled by setupHwcHotplugCallExpectations.
- EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
- .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
- Return(hal::V2_4::Error::NONE)));
-
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6b3c379..867fc45 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1369,197 +1369,221 @@
const VkPhysicalDevice& pdev = GetData(device).driver_physical_device;
const InstanceData& instance_data = GetData(pdev);
const InstanceDriverTable& instance_dispatch = instance_data.driver;
- if (!instance_dispatch.GetPhysicalDeviceImageFormatProperties2 &&
- !instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) {
- uint64_t native_usage = 0;
- void* usage_info_pNext = nullptr;
- VkResult result;
+ if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2 ||
+ instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) {
+ // Look through the create_info pNext chain passed to createSwapchainKHR
+ // for an image compression control struct.
+ // if one is found AND the appropriate extensions are enabled, create a
+ // VkImageCompressionControlEXT structure to pass on to
+ // GetPhysicalDeviceImageFormatProperties2
+ void* compression_control_pNext = nullptr;
VkImageCompressionControlEXT image_compression = {};
- const auto& dispatch = GetData(device).driver;
- if (dispatch.GetSwapchainGrallocUsage4ANDROID) {
- ATRACE_BEGIN("GetSwapchainGrallocUsage4ANDROID");
- VkGrallocUsageInfo2ANDROID gralloc_usage_info = {};
- gralloc_usage_info.sType =
- VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_2_ANDROID;
- gralloc_usage_info.format = create_info->imageFormat;
- gralloc_usage_info.imageUsage = create_info->imageUsage;
- gralloc_usage_info.swapchainImageUsage = swapchain_image_usage;
-
- // Look through the pNext chain for an image compression control struct
- // if one is found AND the appropriate extensions are enabled,
- // append it to be the gralloc usage pNext chain
- const VkSwapchainCreateInfoKHR* create_infos = create_info;
- while (create_infos->pNext) {
- create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
- create_infos->pNext);
- switch (create_infos->sType) {
- case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
- const VkImageCompressionControlEXT* compression_infos =
- reinterpret_cast<const VkImageCompressionControlEXT*>(
- create_infos);
- image_compression = *compression_infos;
- image_compression.pNext = nullptr;
- usage_info_pNext = &image_compression;
- } break;
-
- default:
- // Ignore all other info structs
- break;
- }
+ const VkSwapchainCreateInfoKHR* create_infos = create_info;
+ while (create_infos->pNext) {
+ create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(create_infos->pNext);
+ switch (create_infos->sType) {
+ case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+ const VkImageCompressionControlEXT* compression_infos =
+ reinterpret_cast<const VkImageCompressionControlEXT*>(create_infos);
+ image_compression = *compression_infos;
+ image_compression.pNext = nullptr;
+ compression_control_pNext = &image_compression;
+ } break;
+ default:
+ // Ignore all other info structs
+ break;
}
- gralloc_usage_info.pNext = usage_info_pNext;
-
- result = dispatch.GetSwapchainGrallocUsage4ANDROID(
- device, &gralloc_usage_info, &native_usage);
- ATRACE_END();
- if (result != VK_SUCCESS) {
- ALOGE("vkGetSwapchainGrallocUsage4ANDROID failed: %d", result);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- } else if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
- ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
- VkGrallocUsageInfoANDROID gralloc_usage_info = {};
- gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
- gralloc_usage_info.format = create_info->imageFormat;
- gralloc_usage_info.imageUsage = create_info->imageUsage;
-
- // Look through the pNext chain for an image compression control struct
- // if one is found AND the appropriate extensions are enabled,
- // append it to be the gralloc usage pNext chain
- const VkSwapchainCreateInfoKHR* create_infos = create_info;
- while (create_infos->pNext) {
- create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
- create_infos->pNext);
- switch (create_infos->sType) {
- case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
- const VkImageCompressionControlEXT* compression_infos =
- reinterpret_cast<const VkImageCompressionControlEXT*>(
- create_infos);
- image_compression = *compression_infos;
- image_compression.pNext = nullptr;
- usage_info_pNext = &image_compression;
- } break;
-
- default:
- // Ignore all other info structs
- break;
- }
- }
- gralloc_usage_info.pNext = usage_info_pNext;
-
- result = dispatch.GetSwapchainGrallocUsage3ANDROID(
- device, &gralloc_usage_info, &native_usage);
- ATRACE_END();
- if (result != VK_SUCCESS) {
- ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
- uint64_t consumer_usage, producer_usage;
- ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
- result = dispatch.GetSwapchainGrallocUsage2ANDROID(
- device, create_info->imageFormat, create_info->imageUsage,
- swapchain_image_usage, &consumer_usage, &producer_usage);
- ATRACE_END();
- if (result != VK_SUCCESS) {
- ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- native_usage =
- convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
- } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
- ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
- int32_t legacy_usage = 0;
- result = dispatch.GetSwapchainGrallocUsageANDROID(
- device, create_info->imageFormat, create_info->imageUsage,
- &legacy_usage);
- ATRACE_END();
- if (result != VK_SUCCESS) {
- ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
- native_usage = static_cast<uint64_t>(legacy_usage);
}
- *producer_usage = native_usage;
- return VK_SUCCESS;
+ // call GetPhysicalDeviceImageFormatProperties2KHR
+ VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
+ .pNext = compression_control_pNext,
+ .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
+ };
+
+ // AHB does not have an sRGB format so we can't pass it to GPDIFP
+ // We need to convert the format to unorm if it is srgb
+ VkFormat format = create_info->imageFormat;
+ if (format == VK_FORMAT_R8G8B8A8_SRGB) {
+ format = VK_FORMAT_R8G8B8A8_UNORM;
+ }
+
+ VkPhysicalDeviceImageFormatInfo2 image_format_info = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
+ .pNext = &external_image_format_info,
+ .format = format,
+ .type = VK_IMAGE_TYPE_2D,
+ .tiling = VK_IMAGE_TILING_OPTIMAL,
+ .usage = create_info->imageUsage,
+ .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
+ };
+
+ VkAndroidHardwareBufferUsageANDROID ahb_usage;
+ ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
+ ahb_usage.pNext = nullptr;
+
+ VkImageFormatProperties2 image_format_properties;
+ image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+ image_format_properties.pNext = &ahb_usage;
+
+ if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2) {
+ VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2(
+ pdev, &image_format_info, &image_format_properties);
+ if (result != VK_SUCCESS) {
+ ALOGE("VkGetPhysicalDeviceImageFormatProperties2 for AHB usage failed: %d", result);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ }
+ else {
+ VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR(
+ pdev, &image_format_info,
+ &image_format_properties);
+ if (result != VK_SUCCESS) {
+ ALOGE("VkGetPhysicalDeviceImageFormatProperties2KHR for AHB usage failed: %d",
+ result);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ }
+
+ // Determine if USAGE_FRONT_BUFFER is needed.
+ // GPDIFP2 has no means of using VkSwapchainImageUsageFlagsANDROID when
+ // querying for producer_usage. So androidHardwareBufferUsage will not
+ // contain USAGE_FRONT_BUFFER. We need to manually check for usage here.
+ if (!(swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) {
+ *producer_usage = ahb_usage.androidHardwareBufferUsage;
+ return VK_SUCCESS;
+ }
+
+ // Check if USAGE_FRONT_BUFFER is supported for this swapchain
+ AHardwareBuffer_Desc ahb_desc = {
+ .width = create_info->imageExtent.width,
+ .height = create_info->imageExtent.height,
+ .layers = create_info->imageArrayLayers,
+ .format = create_info->imageFormat,
+ .usage = ahb_usage.androidHardwareBufferUsage | AHARDWAREBUFFER_USAGE_FRONT_BUFFER,
+ .stride = 0, // stride is always ignored when calling isSupported()
+ };
+
+ // If FRONT_BUFFER is not supported,
+ // then we need to call GetSwapchainGrallocUsageXAndroid below
+ if (AHardwareBuffer_isSupported(&ahb_desc)) {
+ *producer_usage = ahb_usage.androidHardwareBufferUsage;
+ *producer_usage |= AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
+ return VK_SUCCESS;
+ }
}
- // Look through the create_info pNext chain passed to createSwapchainKHR
- // for an image compression control struct.
- // if one is found AND the appropriate extensions are enabled, create a
- // VkImageCompressionControlEXT structure to pass on to GetPhysicalDeviceImageFormatProperties2
- void* compression_control_pNext = nullptr;
+ uint64_t native_usage = 0;
+ void* usage_info_pNext = nullptr;
+ VkResult result;
VkImageCompressionControlEXT image_compression = {};
- const VkSwapchainCreateInfoKHR* create_infos = create_info;
- while (create_infos->pNext) {
- create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(create_infos->pNext);
- switch (create_infos->sType) {
- case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
- const VkImageCompressionControlEXT* compression_infos =
- reinterpret_cast<const VkImageCompressionControlEXT*>(create_infos);
- image_compression = *compression_infos;
- image_compression.pNext = nullptr;
- compression_control_pNext = &image_compression;
- } break;
- default:
- // Ignore all other info structs
- break;
+ const auto& dispatch = GetData(device).driver;
+ if (dispatch.GetSwapchainGrallocUsage4ANDROID) {
+ ATRACE_BEGIN("GetSwapchainGrallocUsage4ANDROID");
+ VkGrallocUsageInfo2ANDROID gralloc_usage_info = {};
+ gralloc_usage_info.sType =
+ VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_2_ANDROID;
+ gralloc_usage_info.format = create_info->imageFormat;
+ gralloc_usage_info.imageUsage = create_info->imageUsage;
+ gralloc_usage_info.swapchainImageUsage = swapchain_image_usage;
+
+ // Look through the pNext chain for an image compression control struct
+ // if one is found AND the appropriate extensions are enabled,
+ // append it to be the gralloc usage pNext chain
+ const VkSwapchainCreateInfoKHR* create_infos = create_info;
+ while (create_infos->pNext) {
+ create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+ create_infos->pNext);
+ switch (create_infos->sType) {
+ case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+ const VkImageCompressionControlEXT* compression_infos =
+ reinterpret_cast<const VkImageCompressionControlEXT*>(
+ create_infos);
+ image_compression = *compression_infos;
+ image_compression.pNext = nullptr;
+ usage_info_pNext = &image_compression;
+ } break;
+
+ default:
+ // Ignore all other info structs
+ break;
+ }
}
- }
+ gralloc_usage_info.pNext = usage_info_pNext;
- // call GetPhysicalDeviceImageFormatProperties2KHR
- VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
- .pNext = compression_control_pNext,
- .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
- };
-
- // AHB does not have an sRGB format so we can't pass it to GPDIFP
- // We need to convert the format to unorm if it is srgb
- VkFormat format = create_info->imageFormat;
- if (format == VK_FORMAT_R8G8B8A8_SRGB) {
- format = VK_FORMAT_R8G8B8A8_UNORM;
- }
-
- VkPhysicalDeviceImageFormatInfo2 image_format_info = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
- .pNext = &external_image_format_info,
- .format = format,
- .type = VK_IMAGE_TYPE_2D,
- .tiling = VK_IMAGE_TILING_OPTIMAL,
- .usage = create_info->imageUsage,
- .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
- };
-
- VkAndroidHardwareBufferUsageANDROID ahb_usage;
- ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
- ahb_usage.pNext = nullptr;
-
- VkImageFormatProperties2 image_format_properties;
- image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
- image_format_properties.pNext = &ahb_usage;
-
- if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2) {
- VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2(
- pdev, &image_format_info, &image_format_properties);
+ result = dispatch.GetSwapchainGrallocUsage4ANDROID(
+ device, &gralloc_usage_info, &native_usage);
+ ATRACE_END();
if (result != VK_SUCCESS) {
- ALOGE("VkGetPhysicalDeviceImageFormatProperties2 for AHB usage failed: %d", result);
+ ALOGE("vkGetSwapchainGrallocUsage4ANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
}
- }
- else {
- VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR(
- pdev, &image_format_info,
- &image_format_properties);
+ } else if (dispatch.GetSwapchainGrallocUsage3ANDROID) {
+ ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID");
+ VkGrallocUsageInfoANDROID gralloc_usage_info = {};
+ gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID;
+ gralloc_usage_info.format = create_info->imageFormat;
+ gralloc_usage_info.imageUsage = create_info->imageUsage;
+
+ // Look through the pNext chain for an image compression control struct
+ // if one is found AND the appropriate extensions are enabled,
+ // append it to be the gralloc usage pNext chain
+ const VkSwapchainCreateInfoKHR* create_infos = create_info;
+ while (create_infos->pNext) {
+ create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+ create_infos->pNext);
+ switch (create_infos->sType) {
+ case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+ const VkImageCompressionControlEXT* compression_infos =
+ reinterpret_cast<const VkImageCompressionControlEXT*>(
+ create_infos);
+ image_compression = *compression_infos;
+ image_compression.pNext = nullptr;
+ usage_info_pNext = &image_compression;
+ } break;
+
+ default:
+ // Ignore all other info structs
+ break;
+ }
+ }
+ gralloc_usage_info.pNext = usage_info_pNext;
+
+ result = dispatch.GetSwapchainGrallocUsage3ANDROID(
+ device, &gralloc_usage_info, &native_usage);
+ ATRACE_END();
if (result != VK_SUCCESS) {
- ALOGE("VkGetPhysicalDeviceImageFormatProperties2KHR for AHB usage failed: %d",
- result);
+ ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
+ uint64_t consumer_usage, producer_usage;
+ ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
+ result = dispatch.GetSwapchainGrallocUsage2ANDROID(
+ device, create_info->imageFormat, create_info->imageUsage,
+ swapchain_image_usage, &consumer_usage, &producer_usage);
+ ATRACE_END();
+ if (result != VK_SUCCESS) {
+ ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ native_usage =
+ convertGralloc1ToBufferUsage(producer_usage, consumer_usage);
+ } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
+ ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
+ int32_t legacy_usage = 0;
+ result = dispatch.GetSwapchainGrallocUsageANDROID(
+ device, create_info->imageFormat, create_info->imageUsage,
+ &legacy_usage);
+ ATRACE_END();
+ if (result != VK_SUCCESS) {
+ ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ native_usage = static_cast<uint64_t>(legacy_usage);
}
-
- *producer_usage = ahb_usage.androidHardwareBufferUsage;
+ *producer_usage = native_usage;
return VK_SUCCESS;
}