Merge "Gralloc4: accept invalid 0x2400 usage bits"
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 677d6c7..49c1318 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -61,6 +61,10 @@
MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&));
+ MOCK_METHOD2(registerForNotifications, status_t(const String16&,
+ const sp<LocalRegistrationCallback>&));
+ MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
+ const sp<LocalRegistrationCallback>&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 81e61da..ea2f8d2 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -43,6 +43,8 @@
namespace android {
+using AidlRegistrationCallback = IServiceManager::LocalRegistrationCallback;
+
using AidlServiceManager = android::os::IServiceManager;
using android::binder::Status;
@@ -79,7 +81,24 @@
Vector<String16> getDeclaredInstances(const String16& interface) override;
std::optional<String16> updatableViaApex(const String16& name) override;
std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
+ class RegistrationWaiter : public android::os::BnServiceCallback {
+ public:
+ explicit RegistrationWaiter(const sp<AidlRegistrationCallback>& callback)
+ : mImpl(callback) {}
+ Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
+ mImpl->onServiceRegistration(String16(name.c_str()), binder);
+ return Status::ok();
+ }
+ private:
+ sp<AidlRegistrationCallback> mImpl;
+ };
+
+ status_t registerForNotifications(const String16& service,
+ const sp<AidlRegistrationCallback>& cb) override;
+
+ status_t unregisterForNotifications(const String16& service,
+ const sp<AidlRegistrationCallback>& cb) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
return mTheRealServiceManager->getInterfaceDescriptor();
@@ -90,6 +109,17 @@
protected:
sp<AidlServiceManager> mTheRealServiceManager;
+ // AidlRegistrationCallback -> services that its been registered for
+ // notifications.
+ using LocalRegistrationAndWaiter =
+ std::pair<sp<LocalRegistrationCallback>, sp<RegistrationWaiter>>;
+ using ServiceCallbackMap = std::map<std::string, std::vector<LocalRegistrationAndWaiter>>;
+ ServiceCallbackMap mNameToRegistrationCallback;
+ std::mutex mNameToRegistrationLock;
+
+ void removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter);
// Directly get the service in a way that, for lazy services, requests the service to be started
// if it is not currently started. This way, calls directly to ServiceManagerShim::getService
@@ -442,6 +472,77 @@
: std::nullopt;
}
+status_t ServiceManagerShim::registerForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
+ if (cb == nullptr) {
+ ALOGE("%s: null cb passed", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ std::string nameStr = String8(name).c_str();
+ sp<RegistrationWaiter> registrationWaiter = sp<RegistrationWaiter>::make(cb);
+ std::lock_guard<std::mutex> lock(mNameToRegistrationLock);
+ if (Status status =
+ mTheRealServiceManager->registerForNotifications(nameStr, registrationWaiter);
+ !status.isOk()) {
+ ALOGW("Failed to registerForNotifications for %s: %s", nameStr.c_str(),
+ status.toString8().c_str());
+ return UNKNOWN_ERROR;
+ }
+ mNameToRegistrationCallback[nameStr].push_back(std::make_pair(cb, registrationWaiter));
+ return OK;
+}
+
+void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter) {
+ std::vector<LocalRegistrationAndWaiter>& localRegistrationAndWaiters = (*it)->second;
+ for (auto lit = localRegistrationAndWaiters.begin();
+ lit != localRegistrationAndWaiters.end();) {
+ if (lit->first == cb) {
+ if (waiter) {
+ *waiter = lit->second;
+ }
+ lit = localRegistrationAndWaiters.erase(lit);
+ } else {
+ ++lit;
+ }
+ }
+
+ if (localRegistrationAndWaiters.empty()) {
+ mNameToRegistrationCallback.erase(*it);
+ }
+}
+
+status_t ServiceManagerShim::unregisterForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
+ if (cb == nullptr) {
+ ALOGE("%s: null cb passed", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ std::string nameStr = String8(name).c_str();
+ std::lock_guard<std::mutex> lock(mNameToRegistrationLock);
+ auto it = mNameToRegistrationCallback.find(nameStr);
+ sp<RegistrationWaiter> registrationWaiter;
+ if (it != mNameToRegistrationCallback.end()) {
+ removeRegistrationCallbackLocked(cb, &it, ®istrationWaiter);
+ } else {
+ ALOGE("%s no callback registered for notifications on %s", __FUNCTION__, nameStr.c_str());
+ return BAD_VALUE;
+ }
+ if (registrationWaiter == nullptr) {
+ ALOGE("%s Callback passed wasn't used to register for notifications", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ if (Status status = mTheRealServiceManager->unregisterForNotifications(String8(name).c_str(),
+ registrationWaiter);
+ !status.isOk()) {
+ ALOGW("Failed to get service manager to unregisterForNotifications for %s: %s",
+ String8(name).c_str(), status.toString8().c_str());
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+}
+
#ifndef __ANDROID__
// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
// The internal implementation of the AIDL interface android::os::IServiceManager calls into
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 240e3c2..ea40db8 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -115,6 +115,17 @@
unsigned int port;
};
virtual std::optional<ConnectionInfo> getConnectionInfo(const String16& name) = 0;
+
+ struct LocalRegistrationCallback : public virtual RefBase {
+ virtual void onServiceRegistration(const String16& instance, const sp<IBinder>& binder) = 0;
+ virtual ~LocalRegistrationCallback() {}
+ };
+
+ virtual status_t registerForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) = 0;
+
+ virtual status_t unregisterForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) = 0;
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 63a4b2c..700940a 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1220,6 +1220,19 @@
EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
}
+TEST(ServiceNotifications, Unregister) {
+ auto sm = defaultServiceManager();
+ using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback;
+ class LocalRegistrationCallbackImpl : public virtual LocalRegistrationCallback {
+ void onServiceRegistration(const String16 &, const sp<IBinder> &) override {}
+ virtual ~LocalRegistrationCallbackImpl() {}
+ };
+ sp<LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make();
+
+ EXPECT_EQ(sm->registerForNotifications(String16("RogerRafa"), cb), OK);
+ EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK);
+}
+
class BinderLibRpcTestBase : public BinderLibTest {
public:
void SetUp() override {
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 9f0754b..61e4a98 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -84,4 +84,14 @@
return std::nullopt;
}
+status_t ServiceManager::registerForNotifications(const String16&,
+ const sp<LocalRegistrationCallback>&) {
+ return INVALID_OPERATION;
+}
+
+status_t ServiceManager::unregisterForNotifications(const String16&,
+ const sp<LocalRegistrationCallback>&) {
+ return INVALID_OPERATION;
+}
+
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index b1496ba..6d6e008 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -53,6 +53,11 @@
std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
+ status_t registerForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) override;
+
+ status_t unregisterForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) override;
private:
std::map<String16, sp<IBinder>> mNameToService;
};
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d1982fc..aa3643c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -548,6 +548,7 @@
mAppSwitchSawKeyDown(false),
mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(nullptr),
+ mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
@@ -707,8 +708,13 @@
return LONG_LONG_MIN;
}
-std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(const sp<IBinder>& token) {
- sp<WindowInfoHandle> window = getWindowHandleLocked(token);
+std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(
+ const sp<Connection>& connection) {
+ if (connection->monitor) {
+ return mMonitorDispatchingTimeout;
+ }
+ const sp<WindowInfoHandle> window =
+ getWindowHandleLocked(connection->inputChannel->getConnectionToken());
if (window != nullptr) {
return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
}
@@ -3205,8 +3211,7 @@
while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
- const std::chrono::nanoseconds timeout =
- getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
+ const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection);
dispatchEntry->timeoutTime = currentTime + timeout.count();
// Publish the event.
@@ -6400,4 +6405,9 @@
mLooper->wake();
}
+void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout) {
+ std::scoped_lock _l(mLock);
+ mMonitorDispatchingTimeout = timeout;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 7564839..bff6cac 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -148,6 +148,9 @@
void cancelCurrentTouch() override;
+ // Public to allow tests to verify that a Monitor can get ANR.
+ void setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout);
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -324,8 +327,12 @@
bool runCommandsLockedInterruptable() REQUIRES(mLock);
void postCommandLocked(Command&& command) REQUIRES(mLock);
+ // The dispatching timeout to use for Monitors.
+ std::chrono::nanoseconds mMonitorDispatchingTimeout GUARDED_BY(mLock);
+
nsecs_t processAnrsLocked() REQUIRES(mLock);
- std::chrono::nanoseconds getDispatchingTimeoutLocked(const sp<IBinder>& token) REQUIRES(mLock);
+ std::chrono::nanoseconds getDispatchingTimeoutLocked(const sp<Connection>& connection)
+ REQUIRES(mLock);
// Input filter processing.
bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aa2f832..f97a9ec 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -17,6 +17,7 @@
#include "../dispatcher/InputDispatcher.h"
#include <android-base/properties.h>
+#include <android-base/silent_death_test.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
@@ -2766,9 +2767,10 @@
class FakeMonitorReceiver {
public:
FakeMonitorReceiver(const std::unique_ptr<InputDispatcher>& dispatcher, const std::string name,
- int32_t displayId, bool isGestureMonitor = false) {
+ int32_t displayId) {
base::Result<std::unique_ptr<InputChannel>> channel =
- dispatcher->createInputMonitor(displayId, isGestureMonitor, name, MONITOR_PID);
+ dispatcher->createInputMonitor(displayId, false /*isGestureMonitor*/, name,
+ MONITOR_PID);
mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
}
@@ -2829,6 +2831,8 @@
std::unique_ptr<FakeInputReceiver> mInputReceiver;
};
+using InputDispatcherMonitorTest = InputDispatcherTest;
+
/**
* Two entities that receive touch: A window, and a global monitor.
* The touch goes to the window, and then the window disappears.
@@ -2837,14 +2841,12 @@
* 1. foregroundWindow
* 2. monitor <-- global monitor (doesn't observe z order, receives all events)
*/
-TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_GlobalMonitorTouchIsCanceled) {
+TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "GlobalMonitor", ADISPLAY_ID_DEFAULT,
- false /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -2880,15 +2882,13 @@
monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
}
-// Tests for gesture monitors
-TEST_F(InputDispatcherTest, GestureMonitor_ReceivesMotionEvents) {
+TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
@@ -2897,71 +2897,34 @@
monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
}
-TEST_F(InputDispatcherTest, GestureMonitor_DoesNotReceiveKeyEvents) {
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
- mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- window->setFocusable(true);
-
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
- setFocusedWindow(window);
-
- window->consumeFocusEvent(true);
-
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
- << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
- monitor.assertNoEvents();
-}
-
-TEST_F(InputDispatcherTest, GestureMonitor_CanPilferAfterWindowIsRemovedMidStream) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- window->releaseChannel();
-
- mDispatcher->pilferPointers(monitor.getToken());
+ // Pilfer pointers from the monitor.
+ // This should not do anything and the window should continue to receive events.
+ EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+
+ monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
}
-TEST_F(InputDispatcherTest, UnresponsiveGestureMonitor_GetsAnr) {
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
- std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
- ASSERT_TRUE(consumeSeq);
-
- mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(DISPATCHING_TIMEOUT);
- monitor.finishEvent(*consumeSeq);
- ASSERT_TRUE(mDispatcher->waitForIdle());
- mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
-}
-
-// Tests for gesture monitors
-TEST_F(InputDispatcherTest, GestureMonitor_NoWindowTransform) {
+TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
@@ -2969,8 +2932,7 @@
window->setWindowOffset(20, 40);
window->setWindowTransform(0, 1, -1, 0);
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
@@ -2981,15 +2943,14 @@
ASSERT_EQ(ui::Transform(), event->getTransform());
}
-TEST_F(InputDispatcherTest, GestureMonitor_NoWindow) {
+TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ ASSERT_EQ(InputEventInjectionResult::FAILED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ << "Injection should fail if there is a monitor, but no touchable window";
+ monitor.assertNoEvents();
}
TEST_F(InputDispatcherTest, TestMoveEvent) {
@@ -3018,91 +2979,6 @@
0 /*expectedFlags*/);
}
-TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) {
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
- window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
-
- // First finger down, no window touched.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {100, 200}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- window->assertNoEvents();
-
- // Second finger down on window, the window should receive touch down.
- const MotionEvent secondFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
- .displayId(ADISPLAY_ID_DEFAULT)
- .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
- .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
- .x(100)
- .y(200))
- .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
- .build();
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-
- window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionPointerDown(1 /* pointerIndex */);
-}
-
-TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) {
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
- window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
-
- // First finger down, no window touched.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {100, 200}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- window->assertNoEvents();
-
- // Gesture monitor pilfer the pointers.
- mDispatcher->pilferPointers(monitor.getToken());
-
- // Second finger down on window, the window should not receive touch down.
- const MotionEvent secondFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
- .displayId(ADISPLAY_ID_DEFAULT)
- .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
- .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
- .x(100)
- .y(200))
- .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
- .build();
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-
- window->assertNoEvents();
- monitor.consumeMotionPointerDown(1 /* pointerIndex */);
-}
-
/**
* Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
* the device default right away. In the test scenario, we check both the default value,
@@ -4442,6 +4318,17 @@
injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
WINDOW_LOCATION));
}
+
+ sp<FakeWindowHandle> addSpyWindow() {
+ sp<FakeWindowHandle> spy =
+ new FakeWindowHandle(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spy->setTrustedOverlay(true);
+ spy->setFocusable(false);
+ spy->setInputFeatures(WindowInfo::Feature::SPY);
+ spy->setDispatchingTimeout(30ms);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, mWindow}}});
+ return spy;
+ }
};
// Send a tap and respond, which should not cause an ANR.
@@ -4617,12 +4504,31 @@
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
}
-// If an app is not responding to a key event, gesture monitors should continue to receive
+// A spy window can receive an ANR
+TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
+ sp<FakeWindowHandle> spy = addSpyWindow();
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ WINDOW_LOCATION));
+ mWindow->consumeMotionDown();
+
+ std::optional<uint32_t> sequenceNum = spy->receiveEvent(); // ACTION_DOWN
+ ASSERT_TRUE(sequenceNum);
+ const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy->getToken());
+
+ spy->finishEvent(*sequenceNum);
+ spy->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT,
+ 0 /*flags*/);
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken());
+}
+
+// If an app is not responding to a key event, spy windows should continue to receive
// new motion events
-TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnrOnKey) {
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
+ sp<FakeWindowHandle> spy = addSpyWindow();
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT));
@@ -4633,44 +4539,64 @@
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
- // New tap will go to the gesture monitor, but not to the window
+ // New tap will go to the spy window, but not to the window
tapOnWindow();
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
mDispatcher->waitForIdle();
mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
mWindow->assertNoEvents();
- monitor.assertNoEvents();
+ spy->assertNoEvents();
}
-// If an app is not responding to a motion event, gesture monitors should continue to receive
+// If an app is not responding to a motion event, spy windows should continue to receive
// new motion events
-TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnrOnMotion) {
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
+ sp<FakeWindowHandle> spy = addSpyWindow();
tapOnWindow();
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
mWindow->consumeMotionDown();
// Stuck on the ACTION_UP
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
- // New tap will go to the gesture monitor, but not to the window
+ // New tap will go to the spy window, but not to the window
tapOnWindow();
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
mDispatcher->waitForIdle();
mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
mWindow->assertNoEvents();
- monitor.assertNoEvents();
+ spy->assertNoEvents();
+}
+
+TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
+ mDispatcher->setMonitorDispatchingTimeoutForTest(30ms);
+
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ WINDOW_LOCATION));
+
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
+ ASSERT_TRUE(consumeSeq);
+
+ mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(30ms);
+
+ monitor.finishEvent(*consumeSeq);
+ monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
}
// If a window is unresponsive, then you get anr. if the window later catches up and starts to
@@ -6338,6 +6264,7 @@
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ window->setFocusable(true);
return window;
}
@@ -6345,10 +6272,13 @@
int mSpyCount{0};
};
+using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
/**
* Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
*/
-TEST_F(InputDispatcherSpyWindowTest, UntrustedSpy_AbortsDispatcher) {
+TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
+ ScopedSilentDeath _silentDeath;
+
auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
spy->setTrustedOverlay(false);
ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}),
@@ -6532,7 +6462,7 @@
spy2->consumeMotionDown();
// Pilfer pointers from the second spy window.
- mDispatcher->pilferPointers(spy2->getToken());
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
spy2->assertNoEvents();
spy1->consumeMotionCancel();
window->consumeMotionCancel();
@@ -6548,6 +6478,80 @@
}
/**
+ * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
+ * in the middle of the gesture.
+ */
+TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) {
+ auto window = createForeground();
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ window->releaseChannel();
+
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+}
+
+/**
+ * After a spy window pilfers pointers, new pointers that go down should not go to any foreground
+ * windows.
+ */
+TEST_F(InputDispatcherSpyWindowTest, NoSplitAfterPilfer) {
+ // Create a touch modal spy that spies on the entire display.
+ auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+
+ // Create a non touch modal window that supports split touch.
+ auto window = createForeground();
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ // First finger down, no window touched.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+
+ // Spy window pilfer the pointers.
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+
+ // Second finger down on window, the window should not receive touch down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->assertNoEvents();
+ // Since we no longer allow splitting, the spy will not receive new pointers.
+ // TODO(b/217376964): Add a way for the pilfering window to receive the rest of the gesture.
+ spy->consumeMotionMove();
+}
+
+/**
* Even when a spy window spans over multiple foreground windows, the spy should receive all
* pointers that are down within its bounds.
*/
@@ -6619,6 +6623,76 @@
spyRight->consumeMotionDown();
}
+/**
+ * The spy window should not be able to affect whether or not touches are split. Only the foreground
+ * windows should be allowed to control split touch.
+ */
+TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
+ // Create a touch modal spy that spies on the entire display.
+ // This spy window does not set the SPLIT_TOUCH flag. However, we still expect to split touches
+ // because a foreground window has not disabled splitting.
+ auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+
+ // Create a non touch modal window that supports split touch.
+ auto window = createForeground();
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ // First finger down, no window touched.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+
+ // Second finger down on window, the window should receive touch down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionPointerDown(1 /* pointerIndex */);
+}
+
+/**
+ * A spy window will usually be implemented as an un-focusable window. Verify that these windows
+ * do not receive key events.
+ */
+TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
+ auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+ spy->setFocusable(false);
+
+ auto window = createForeground();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeKeyDown(ADISPLAY_ID_NONE);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeKeyUp(ADISPLAY_ID_NONE);
+
+ spy->assertNoEvents();
+}
+
class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
public:
std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
@@ -6665,7 +6739,11 @@
}
};
-TEST_F(InputDispatcherStylusInterceptorTest, UntrustedOverlay_AbortsDispatcher) {
+using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
+
+TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
+ ScopedSilentDeath _silentDeath;
+
auto [overlay, window] = setupStylusOverlayScenario();
overlay->setTrustedOverlay(false);
// Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.