-
-
Notifications
You must be signed in to change notification settings - Fork 862
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix leaking udev reference in LinuxUsbDevice #1678
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,14 @@ | |
@Immutable | ||
public class LinuxUsbDevice extends AbstractUsbDevice { | ||
|
||
private static final String SUBSYSTEM_USB = "usb"; | ||
private static final String DEVTYPE_USB_DEVICE = "usb_device"; | ||
private static final String ATTR_PRODUCT = "product"; | ||
private static final String ATTR_MANUFACTURER = "manufacturer"; | ||
private static final String ATTR_VENDOR_ID = "idVendor"; | ||
private static final String ATTR_PRODUCT_ID = "idProduct"; | ||
private static final String ATTR_SERIAL = "serial"; | ||
|
||
public LinuxUsbDevice(String name, String vendor, String vendorId, String productId, String serialNumber, | ||
String uniqueDeviceId, List<UsbDevice> connectedDevices) { | ||
super(name, vendor, vendorId, productId, serialNumber, uniqueDeviceId, connectedDevices); | ||
|
@@ -82,73 +90,76 @@ public static List<UsbDevice> getUsbDevices(boolean tree) { | |
} | ||
|
||
private static List<UsbDevice> getUsbDevices() { | ||
// Enumerate all usb devices and build information maps | ||
Udev.UdevContext udev = Udev.INSTANCE.udev_new(); | ||
// Create a list of the devices in the 'usb' subsystem. | ||
UdevEnumerate enumerate = Udev.INSTANCE.udev_enumerate_new(udev); | ||
Udev.INSTANCE.udev_enumerate_add_match_subsystem(enumerate, "usb"); | ||
Udev.INSTANCE.udev_enumerate_scan_devices(enumerate); | ||
UdevListEntry devices = Udev.INSTANCE.udev_enumerate_get_list_entry(enumerate); | ||
|
||
// Build a list of devices with no parent; these will be the roots | ||
List<String> usbControllers = new ArrayList<>(); | ||
|
||
// Maps to store information using device node path as the key | ||
// Maps to store information using device syspath as the key | ||
Map<String, String> nameMap = new HashMap<>(); | ||
Map<String, String> vendorMap = new HashMap<>(); | ||
Map<String, String> vendorIdMap = new HashMap<>(); | ||
Map<String, String> productIdMap = new HashMap<>(); | ||
Map<String, String> serialMap = new HashMap<>(); | ||
Map<String, List<String>> hubMap = new HashMap<>(); | ||
|
||
// For each item enumerated, store information in the maps | ||
for (UdevListEntry dev_list_entry = devices; dev_list_entry != null; dev_list_entry = Udev.INSTANCE | ||
.udev_list_entry_get_next(dev_list_entry)) { | ||
// Enumerate all usb devices and build information maps | ||
Udev.UdevContext udev = Udev.INSTANCE.udev_new(); | ||
try { | ||
UdevEnumerate enumerate = udev.enumerateNew(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to udev_new this can theoretically return null but probably never will. Something to think about for a future fix. |
||
try { | ||
enumerate.addMatchSubsystem(SUBSYSTEM_USB); | ||
enumerate.scanDevices(); | ||
|
||
// Get the filename of the /sys entry for the device and create a | ||
// udev_device object (dev) representing it | ||
String path = Udev.INSTANCE.udev_list_entry_get_name(dev_list_entry); | ||
UdevDevice dev = Udev.INSTANCE.udev_device_new_from_syspath(udev, path); | ||
// Ignore interfaces | ||
if (!"usb_device".equals(Udev.INSTANCE.udev_device_get_devtype(dev))) { | ||
continue; | ||
} | ||
// For each item enumerated, store information in the maps | ||
for (UdevListEntry entry = enumerate.getListEntry(); entry != null; entry = entry.getNext()) { | ||
String syspath = entry.getName(); | ||
UdevDevice device = udev.deviceNewFromSyspath(syspath); | ||
if (device != null) { | ||
try { | ||
// Only include usb_device devtype, skipping usb_interface | ||
if (DEVTYPE_USB_DEVICE.equals(device.getDevtype())) { | ||
String value = device.getSysattrValue(ATTR_PRODUCT); | ||
if (value != null) { | ||
nameMap.put(syspath, value); | ||
} | ||
value = device.getSysattrValue(ATTR_MANUFACTURER); | ||
if (value != null) { | ||
vendorMap.put(syspath, value); | ||
} | ||
value = device.getSysattrValue(ATTR_VENDOR_ID); | ||
if (value != null) { | ||
vendorIdMap.put(syspath, value); | ||
} | ||
value = device.getSysattrValue(ATTR_PRODUCT_ID); | ||
if (value != null) { | ||
productIdMap.put(syspath, value); | ||
} | ||
value = device.getSysattrValue(ATTR_SERIAL); | ||
if (value != null) { | ||
serialMap.put(syspath, value); | ||
} | ||
|
||
// Use the path as the key for the maps | ||
String value = Udev.INSTANCE.udev_device_get_sysattr_value(dev, "product"); | ||
if (value != null) { | ||
nameMap.put(path, value); | ||
} | ||
value = Udev.INSTANCE.udev_device_get_sysattr_value(dev, "manufacturer"); | ||
if (value != null) { | ||
vendorMap.put(path, value); | ||
} | ||
value = Udev.INSTANCE.udev_device_get_sysattr_value(dev, "idVendor"); | ||
if (value != null) { | ||
vendorIdMap.put(path, value); | ||
} | ||
value = Udev.INSTANCE.udev_device_get_sysattr_value(dev, "idProduct"); | ||
if (value != null) { | ||
productIdMap.put(path, value); | ||
} | ||
value = Udev.INSTANCE.udev_device_get_sysattr_value(dev, "serial"); | ||
if (value != null) { | ||
serialMap.put(path, value); | ||
} | ||
UdevDevice parent = Udev.INSTANCE.udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); | ||
if (parent == null) { | ||
// This is a controller with no parent, add to list | ||
usbControllers.add(path); | ||
} else { | ||
// Add child path (path variable) to parent's path | ||
String parentPath = Udev.INSTANCE.udev_device_get_syspath(parent); | ||
hubMap.computeIfAbsent(parentPath, x -> new ArrayList<>()).add(path); | ||
UdevDevice parent = device.getParentWithSubsystemDevtype(SUBSYSTEM_USB, | ||
DEVTYPE_USB_DEVICE); | ||
if (parent == null) { | ||
// This is a controller with no parent, add to list | ||
usbControllers.add(syspath); | ||
} else { | ||
// Add child syspath to parent's path | ||
String parentPath = parent.getSyspath(); | ||
hubMap.computeIfAbsent(parentPath, x -> new ArrayList<>()).add(syspath); | ||
} | ||
} | ||
} finally { | ||
device.unref(); | ||
} | ||
} | ||
} | ||
} finally { | ||
enumerate.unref(); | ||
} | ||
Udev.INSTANCE.udev_device_unref(dev); | ||
} finally { | ||
udev.unref(); | ||
} | ||
// Free the enumerator object | ||
Udev.INSTANCE.udev_enumerate_unref(enumerate); | ||
Udev.INSTANCE.udev_unref(udev); | ||
|
||
// Build tree and return | ||
List<UsbDevice> controllerDevices = new ArrayList<>(); | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this again, I see that it's possible to return null if the native call fails, but of the four times we call this, we only null check one of them. No need to change this PR for that but I'll have to think about whether we should update all of them.