Skip to content

Commit 7fb7187

Browse files
committed
EventHub: Reimplement sysfsNodeChanged
There were several bugs in the old implementation of sysfsNodeChanged. There are unfortunately no existing unit tests for EventHub, so the old code and the new code are not tested exhaustively. Issues addressed: - The old code would concurrently modify mOpeningDevices while iterating through it, making the code difficult to reason about, particularly since calling openDeviceLocked() from the iteration would add an additional opening device. - The old code was improperly erasing items from mOpeningDevices. vector::erase() returns the next iterator position after the removal, and when progressing to the next for loop iteration, the iterator is incremented again, leading to a missed element. - Each call to isChanged() involves several syscalls, and the old code would perform the check multiple times on the same AssociatedDevice object. Note that for each changed sysfs node, the sysfs node is reloaded yet again for each openDeviceLocked() call, which this CL does not address. Bug: 245989146 Test: atest SonyDualshock4BluetoothTest --iterations Test: Presubmit Flag: EXEMPT refactor/bug fix Change-Id: Iaec9079d8c888310f6d8e496b9dd9df231aff228
1 parent e136587 commit 7fb7187

2 files changed

Lines changed: 44 additions & 26 deletions

File tree

services/inputflinger/reader/EventHub.cpp

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,10 +1654,6 @@ EventHub::AssociatedDevice::AssociatedDevice(const std::filesystem::path& sysfsR
16541654
lightInfos(readLightsConfiguration(sysfsRootPath)),
16551655
layoutInfo(readLayoutConfiguration(sysfsRootPath)) {}
16561656

1657-
bool EventHub::AssociatedDevice::isChanged() const {
1658-
return AssociatedDevice(sysfsRootPath) != *this;
1659-
}
1660-
16611657
std::string EventHub::AssociatedDevice::dump() const {
16621658
return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(),
16631659
batteryInfos.size(), lightInfos.size());
@@ -2652,33 +2648,56 @@ status_t EventHub::disableDevice(int32_t deviceId) {
26522648
void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) {
26532649
std::scoped_lock _l(mLock);
26542650

2655-
// Check in opening devices
2656-
for (auto it = mOpeningDevices.begin(); it != mOpeningDevices.end(); it++) {
2657-
std::unique_ptr<Device>& device = *it;
2658-
if (device->associatedDevice &&
2659-
sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
2660-
std::string::npos &&
2661-
device->associatedDevice->isChanged()) {
2662-
it = mOpeningDevices.erase(it);
2663-
openDeviceLocked(device->path);
2651+
// Testing whether a sysfs node changed involves several syscalls, so use a cache to avoid
2652+
// testing the same node multiple times.
2653+
std::map<std::shared_ptr<const AssociatedDevice>, bool /*changed*/> testedDevices;
2654+
auto isAssociatedDeviceChanged = [&testedDevices, &sysfsNodePath](const Device& dev) {
2655+
if (!dev.associatedDevice) {
2656+
return false;
26642657
}
2665-
}
2658+
if (auto testedIt = testedDevices.find(dev.associatedDevice);
2659+
testedIt != testedDevices.end()) {
2660+
return testedIt->second;
2661+
}
2662+
// Cache miss
2663+
if (sysfsNodePath.find(dev.associatedDevice->sysfsRootPath.string()) == std::string::npos) {
2664+
testedDevices.emplace(dev.associatedDevice, false);
2665+
return false;
2666+
}
2667+
auto reloadedDevice = AssociatedDevice(dev.associatedDevice->sysfsRootPath);
2668+
const bool changed = *dev.associatedDevice != reloadedDevice;
2669+
testedDevices.emplace(dev.associatedDevice, changed);
2670+
return changed;
2671+
};
26662672

2667-
// Check in already added device
2668-
std::vector<Device*> devicesToReopen;
2669-
for (const auto& [id, device] : mDevices) {
2670-
if (device->associatedDevice &&
2671-
sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
2672-
std::string::npos &&
2673-
device->associatedDevice->isChanged()) {
2674-
devicesToReopen.push_back(device.get());
2673+
std::set<Device*> devicesToClose;
2674+
std::set<std::string /*path*/> devicesToOpen;
2675+
2676+
// Check in opening devices. If its associated device changed,
2677+
// the device should be removed from mOpeningDevices and needs to be opened again.
2678+
std::erase_if(mOpeningDevices, [&](const auto& dev) {
2679+
if (isAssociatedDeviceChanged(*dev)) {
2680+
devicesToOpen.emplace(dev->path);
2681+
return true;
2682+
}
2683+
return false;
2684+
});
2685+
2686+
// Check in already added device. If its associated device changed,
2687+
// the device needs to be re-opened.
2688+
for (const auto& [id, dev] : mDevices) {
2689+
if (isAssociatedDeviceChanged(*dev)) {
2690+
devicesToOpen.emplace(dev->path);
2691+
devicesToClose.emplace(dev.get());
26752692
}
26762693
}
2677-
for (const auto& device : devicesToReopen) {
2694+
2695+
for (auto* device : devicesToClose) {
26782696
closeDeviceLocked(*device);
2679-
openDeviceLocked(device->path);
26802697
}
2681-
devicesToReopen.clear();
2698+
for (const auto& path : devicesToOpen) {
2699+
openDeviceLocked(path);
2700+
}
26822701
}
26832702

26842703
void EventHub::createVirtualKeyboardLocked() {

services/inputflinger/reader/include/EventHub.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,6 @@ class EventHub : public EventHubInterface {
626626
std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
627627
std::optional<RawLayoutInfo> layoutInfo;
628628

629-
bool isChanged() const;
630629
bool operator==(const AssociatedDevice&) const = default;
631630
bool operator!=(const AssociatedDevice&) const = default;
632631
std::string dump() const;

0 commit comments

Comments
 (0)