Merge "Ensure non visible layers that have input are traversed for input" into main
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 750e170..2d64872 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -290,6 +290,17 @@
*/
bool probablyHasInput() const;
+ /* Wait until there is a message in the channel.
+ *
+ * The |timeout| specifies how long to block waiting for an input event to appear. Negative
+ * values are not allowed.
+ *
+ * In some cases returning before timeout expiration can happen without a message available.
+ * This could happen after the channel was closed on the other side. Another possible reason
+ * is incorrect setup of the channel.
+ */
+ void waitForMessage(std::chrono::milliseconds timeout) const;
+
/* Return a new object that has a duplicate of this channel's fd. */
std::unique_ptr<InputChannel> dup() const;
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/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index d4b8dbe..b9ab803 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -168,8 +168,8 @@
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
- InputEvent *consumeEvent(int timeoutMs = 3000) {
- waitForEventAvailable(timeoutMs);
+ InputEvent* consumeEvent(std::chrono::milliseconds timeout = 3000ms) {
+ mClientChannel->waitForMessage(timeout);
InputEvent *ev;
uint32_t seqId;
@@ -302,15 +302,6 @@
t.apply(true);
}
-private:
- void waitForEventAvailable(int timeoutMs) {
- struct pollfd fd;
-
- fd.fd = mClientChannel->getFd();
- fd.events = POLLIN;
- poll(&fd, 1, timeoutMs);
- }
-
public:
sp<SurfaceControl> mSurfaceControl;
std::shared_ptr<InputChannel> mClientChannel;
@@ -615,7 +606,7 @@
// A tap within the surface but outside the touchable region should not be sent to the surface.
injectTap(20, 30);
- EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/200ms), nullptr);
injectTap(31, 52);
surface->expectTap(20, 30);
@@ -981,12 +972,12 @@
obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222};
obscuringSurface->showAt(100, 100);
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
@@ -1002,12 +993,12 @@
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
@@ -1024,12 +1015,12 @@
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
@@ -1046,12 +1037,12 @@
injectTap(111, 111);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) {
@@ -1076,12 +1067,12 @@
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) {
@@ -1116,7 +1107,7 @@
// Does not receive events outside its crop
injectTap(26, 26);
- EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+ EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
}
/**
@@ -1141,7 +1132,7 @@
// Does not receive events outside parent bounds
injectTap(31, 31);
- EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+ EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
}
/**
@@ -1167,7 +1158,7 @@
// Does not receive events outside crop layer bounds
injectTap(21, 21);
injectTap(71, 71);
- EXPECT_EQ(containerSurface->consumeEvent(100), nullptr);
+ EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(InputSurfacesTest, child_container_with_no_input_channel_blocks_parent) {
@@ -1184,7 +1175,7 @@
[&](auto &t, auto &sc) { t.reparent(sc, parent->mSurfaceControl); });
injectTap(101, 101);
- EXPECT_EQ(parent->consumeEvent(100), nullptr);
+ EXPECT_EQ(parent->consumeEvent(/*timeout=*/100ms), nullptr);
}
class MultiDisplayTests : public InputSurfacesTest {
@@ -1233,7 +1224,7 @@
// Touches should be dropped if the layer is on an invalid display.
injectTapOnDisplay(101, 101, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
// However, we still let the window be focused and receive keys.
surface->requestFocus(layerStack.id);
@@ -1271,12 +1262,12 @@
injectTapOnDisplay(101, 101, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
surface->requestFocus(layerStack.id);
surface->assertFocusChange(true);
injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(100), nullptr);
+ EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
}
TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index fa094df..37de00c 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -521,11 +521,11 @@
bool InputChannel::probablyHasInput() const {
struct pollfd pfds = {.fd = mFd, .events = POLLIN};
if (::poll(&pfds, /*nfds=*/1, /*timeout=*/0) <= 0) {
- // This can be a false negative because EAGAIN and ENOMEM are not handled. The latter should
- // be extremely rare. The EAGAIN is also unlikely because it happens only when the signal
- // arrives while the syscall is executed, and the syscall is quick. Hitting EAGAIN too often
+ // This can be a false negative because EINTR and ENOMEM are not handled. The latter should
+ // be extremely rare. The EINTR is also unlikely because it happens only when the signal
+ // arrives while the syscall is executed, and the syscall is quick. Hitting EINTR too often
// would be a sign of having too many signals, which is a bigger performance problem. A
- // common tradition is to repeat the syscall on each EAGAIN, but it is not necessary here.
+ // common tradition is to repeat the syscall on each EINTR, but it is not necessary here.
// In other words, the missing one liner is replaced by a multiline explanation.
return false;
}
@@ -534,6 +534,22 @@
return (pfds.revents & POLLIN) != 0;
}
+void InputChannel::waitForMessage(std::chrono::milliseconds timeout) const {
+ if (timeout < 0ms) {
+ LOG(FATAL) << "Timeout cannot be negative, received " << timeout.count();
+ }
+ struct pollfd pfds = {.fd = mFd, .events = POLLIN};
+ int ret;
+ std::chrono::time_point<std::chrono::steady_clock> stopTime =
+ std::chrono::steady_clock::now() + timeout;
+ std::chrono::milliseconds remaining = timeout;
+ do {
+ ret = ::poll(&pfds, /*nfds=*/1, /*timeout=*/remaining.count());
+ remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
+ stopTime - std::chrono::steady_clock::now());
+ } while (ret == -1 && errno == EINTR && remaining > 0ms);
+}
+
std::unique_ptr<InputChannel> InputChannel::dup() const {
base::unique_fd newFd(dupFd());
return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
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/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/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/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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31d120d..fe5b159 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);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b23b519..6ae05d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -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/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 2f2895c..c01465b 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <functional>
#include <mutex>
#include <optional>
#include <string>
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;
}