Skip to content

Commit a8f8854

Browse files
committed
EventHub: Re-open Devices serially when AssociatedDevice changes
This CL changes behavior so that when an AssociatedDevice changes, all affected Devices will be re-opened serially, where the DEVICE_REMOVED notification of one device closing is followed by the DEVICE_ADDED signal of its new counterpart, before proceeding with the re-opening of the next affected Device. This is to temorarily curb the side-effects of delayed AssociatedDevice changes by reducing the number of cases where we send device removed notifications immediately after an input device is first connected, followed by the addition of a new InputDevice. These kind of "hotplug" events are detrimental to many tests and may have side effects in production. This CL relies on some assumptions on how devices will be merged in InputReader, so it does not solve the problem for all cases. It only aims to reduce the likelihood of impact temporarily until AssociatedDevice changes can be processed separately in InputReader, which is backlogged as b/281822656. Bug: 397208968 Test: Presubmit Flag: EXEMPT bug fix Change-Id: I61818076a720a5474de8cbeb431ddbceec6e1545
1 parent 9d63f1c commit a8f8854

File tree

2 files changed

+89
-59
lines changed

2 files changed

+89
-59
lines changed

services/inputflinger/reader/EventHub.cpp

Lines changed: 88 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,58 +1899,87 @@ std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) {
18991899

19001900
handleSysfsNodeChangeNotificationsLocked();
19011901

1902-
// Report any devices that had last been added/removed.
1903-
for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {
1904-
std::unique_ptr<Device> device = std::move(*it);
1905-
ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
1906-
const int32_t deviceId = (device->id == mBuiltInKeyboardId)
1907-
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
1908-
: device->id;
1909-
events.push_back({
1910-
.when = now,
1911-
.deviceId = deviceId,
1912-
.type = DEVICE_REMOVED,
1913-
});
1914-
it = mClosingDevices.erase(it);
1915-
if (events.size() == EVENT_BUFFER_SIZE) {
1916-
break;
1902+
// Use a do-while loop to ensure that we drain the closing and opening devices loop
1903+
// at least once, even if there are no devices to re-open.
1904+
do {
1905+
if (!mDeviceIdsToReopen.empty()) {
1906+
// If there are devices that need to be re-opened, ensure that we re-open them
1907+
// one at a time to send the DEVICE_REMOVED and DEVICE_ADDED notifications for
1908+
// each before moving on to the next. This is to avoid notifying all device
1909+
// removals and additions in one batch, which could cause additional unnecessary
1910+
// device added/removed notifications for merged InputDevices from InputReader.
1911+
const int32_t deviceId = mDeviceIdsToReopen.back();
1912+
mDeviceIdsToReopen.erase(mDeviceIdsToReopen.end() - 1);
1913+
if (auto it = mDevices.find(deviceId); it != mDevices.end()) {
1914+
ALOGI("Reopening input device: id=%d, name=%s", it->second->id,
1915+
it->second->identifier.name.c_str());
1916+
const auto path = it->second->path;
1917+
closeDeviceLocked(*it->second);
1918+
openDeviceLocked(path);
1919+
}
19171920
}
1918-
}
19191921

1920-
if (mNeedToScanDevices) {
1921-
mNeedToScanDevices = false;
1922-
scanDevicesLocked();
1923-
}
1924-
1925-
while (!mOpeningDevices.empty()) {
1926-
std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
1927-
mOpeningDevices.pop_back();
1928-
ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
1929-
const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
1930-
events.push_back({
1931-
.when = now,
1932-
.deviceId = deviceId,
1933-
.type = DEVICE_ADDED,
1934-
});
1935-
1936-
// Try to find a matching video device by comparing device names
1937-
for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();
1938-
it++) {
1939-
std::unique_ptr<TouchVideoDevice>& videoDevice = *it;
1940-
if (tryAddVideoDeviceLocked(*device, videoDevice)) {
1941-
// videoDevice was transferred to 'device'
1942-
it = mUnattachedVideoDevices.erase(it);
1922+
// Report any devices that had last been added/removed.
1923+
for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {
1924+
std::unique_ptr<Device> device = std::move(*it);
1925+
ALOGV("Reporting device closed: id=%d, name=%s\n", device->id,
1926+
device->path.c_str());
1927+
const int32_t deviceId = (device->id == mBuiltInKeyboardId)
1928+
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
1929+
: device->id;
1930+
events.push_back({
1931+
.when = now,
1932+
.deviceId = deviceId,
1933+
.type = DEVICE_REMOVED,
1934+
});
1935+
it = mClosingDevices.erase(it);
1936+
if (events.size() == EVENT_BUFFER_SIZE) {
19431937
break;
19441938
}
19451939
}
19461940

1947-
auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));
1948-
if (!inserted) {
1949-
ALOGW("Device id %d exists, replaced.", device->id);
1941+
if (mNeedToScanDevices) {
1942+
mNeedToScanDevices = false;
1943+
scanDevicesLocked();
19501944
}
1951-
if (events.size() == EVENT_BUFFER_SIZE) {
1952-
break;
1945+
1946+
while (!mOpeningDevices.empty()) {
1947+
std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());
1948+
mOpeningDevices.pop_back();
1949+
ALOGV("Reporting device opened: id=%d, name=%s\n", device->id,
1950+
device->path.c_str());
1951+
const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
1952+
events.push_back({
1953+
.when = now,
1954+
.deviceId = deviceId,
1955+
.type = DEVICE_ADDED,
1956+
});
1957+
1958+
// Try to find a matching video device by comparing device names
1959+
for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();
1960+
it++) {
1961+
std::unique_ptr<TouchVideoDevice>& videoDevice = *it;
1962+
if (tryAddVideoDeviceLocked(*device, videoDevice)) {
1963+
// videoDevice was transferred to 'device'
1964+
it = mUnattachedVideoDevices.erase(it);
1965+
break;
1966+
}
1967+
}
1968+
1969+
auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));
1970+
if (!inserted) {
1971+
ALOGW("Device id %d exists, replaced.", device->id);
1972+
}
1973+
if (events.size() == EVENT_BUFFER_SIZE) {
1974+
break;
1975+
}
19531976
}
1977+
1978+
// Perform this loop of re-opening devices so that we re-open one device at a time.
1979+
} while (!mDeviceIdsToReopen.empty());
1980+
1981+
if (events.size() == EVENT_BUFFER_SIZE) {
1982+
break;
19541983
}
19551984

19561985
// Grab the next input event.
@@ -2700,8 +2729,10 @@ void EventHub::handleSysfsNodeChangeNotificationsLocked() {
27002729

27012730
// Testing whether a sysfs node changed involves several syscalls, so use a cache to avoid
27022731
// testing the same node multiple times.
2732+
// TODO(b/281822656): Notify InputReader separately when an AssociatedDevice changes,
2733+
// instead of needing to re-open all of Devices that are associated with it.
27032734
std::map<std::shared_ptr<const AssociatedDevice>, bool /*changed*/> testedDevices;
2704-
auto isAssociatedDeviceChanged = [&testedDevices, &changedNodes](const Device& dev) {
2735+
auto shouldReopenDevice = [&testedDevices, &changedNodes](const Device& dev) {
27052736
if (!dev.associatedDevice) {
27062737
return false;
27072738
}
@@ -2730,27 +2761,25 @@ void EventHub::handleSysfsNodeChangeNotificationsLocked() {
27302761
return changed;
27312762
};
27322763

2733-
std::set<Device*> devicesToReopen;
2734-
2735-
// Check in opening devices.
2764+
// Check in opening devices. These can be re-opened directly because we have not yet notified
2765+
// the Reader about these devices.
27362766
for (const auto& dev : mOpeningDevices) {
2737-
if (isAssociatedDeviceChanged(*dev)) {
2738-
devicesToReopen.emplace(dev.get());
2767+
if (shouldReopenDevice(*dev)) {
2768+
ALOGI("Reopening input device from mOpeningDevices: id=%d, name=%s", dev->id,
2769+
dev->identifier.name.c_str());
2770+
const auto path = dev->path;
2771+
closeDeviceLocked(*dev); // The Device object is deleted by this function.
2772+
openDeviceLocked(path);
27392773
}
27402774
}
27412775

2742-
// Check in already added devices.
2776+
// Check in already added devices. Add them to the re-opening list so they can be
2777+
// re-opened serially.
27432778
for (const auto& [id, dev] : mDevices) {
2744-
if (isAssociatedDeviceChanged(*dev)) {
2745-
devicesToReopen.emplace(dev.get());
2779+
if (shouldReopenDevice(*dev)) {
2780+
mDeviceIdsToReopen.emplace_back(dev->id);
27462781
}
27472782
}
2748-
2749-
for (auto* device : devicesToReopen) {
2750-
const auto path = device->path;
2751-
closeDeviceLocked(*device); // The Device object is deleted by this function.
2752-
openDeviceLocked(path);
2753-
}
27542783
}
27552784

27562785
void EventHub::createVirtualKeyboardLocked() {

services/inputflinger/reader/include/EventHub.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,7 @@ class EventHub : public EventHubInterface {
815815
bool mNeedToReopenDevices;
816816
bool mNeedToScanDevices;
817817
std::vector<std::string> mExcludedDevices;
818+
std::vector<int32_t> mDeviceIdsToReopen;
818819

819820
int mEpollFd;
820821
int mINotifyFd;

0 commit comments

Comments
 (0)