Port remaining Linux JNA classes to FFM#3121
Conversation
- Refactor LinuxCentralProcessor: move getSystemLoadAverage to base using /proc/loadavg fallback; JNA subclass uses getloadavg() with fallback to super; FFM subclass uses LinuxLibcFunctions with fallback - Refactor LinuxUsbDevice: rename to LinuxUsbDeviceJNA, create abstract LinuxUsbDevice base with shared template method; LinuxUsbDeviceFFM extends base using UdevFunctions - Refactor LinuxFileSystem, LinuxNetworkParams, LinuxOSProcess, LinuxOperatingSystem: extract abstract bases in oshi-core, add JNA subclasses, add FFM subclasses in oshi-core-java25 - Add LinuxLibcFunctions FFM bindings: getpid, gettid, getloadavg, sysinfo, statvfs, gethostname, getaddrinfo/freeaddrinfo, getrlimit - Add ProcPath.LOADAVG constant - Remove redundant getProcessCount override in LinuxOperatingSystemJNA - Update LinuxHardwareAbstractionLayerJNA to use LinuxUsbDeviceJNA
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR migrates Linux platform code from JNA to FFM (Foreign Function & Memory API) by introducing comprehensive FFM bindings, converting concrete classes to abstract base classes, and implementing both FFM and JNA variants. A new Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant OSFactory as OS Factory
participant LinuxOSAbs as LinuxOperatingSystem<br/>(abstract)
participant LinuxOSJNA as LinuxOperatingSystemJNA
participant LinuxOSFFM as LinuxOperatingSystemFFM
participant JNAImpl as JNA Implementation<br/>(LibC, etc.)
participant FFMImpl as FFM Implementation<br/>(LinuxLibcFunctions)
App->>OSFactory: Create OS instance
alt Factory selects JNA variant
OSFactory->>LinuxOSJNA: new LinuxOperatingSystemJNA()
Note over LinuxOSJNA: Initializes HAS_UDEV, HAS_GETTID, HAS_SYSCALL_GETTID
App->>LinuxOSJNA: getProcessId()
LinuxOSJNA->>JNAImpl: LinuxLibc.INSTANCE.getpid()
JNAImpl-->>LinuxOSJNA: pid
LinuxOSJNA-->>App: processId
else Factory selects FFM variant
OSFactory->>LinuxOSFFM: new LinuxOperatingSystemFFM()
App->>LinuxOSFFM: getProcessId()
LinuxOSFFM->>FFMImpl: LinuxLibcFunctions.getpid()
FFMImpl->>FFMImpl: invokeExact(getpidHandle)
FFMImpl-->>LinuxOSFFM: pid
LinuxOSFFM-->>App: processId
end
sequenceDiagram
participant App as Application
participant FileSysAbs as LinuxFileSystem<br/>(abstract)
participant FileSysJNA as LinuxFileSystemJNA
participant FileSysFFM as LinuxFileSystemFFM
participant OSFileStore as OSFileStore
participant JNALib as LibC (JNA)
participant FFMLib as LinuxLibcFunctions (FFM)
App->>FileSysAbs: getFileStores(localOnly)
alt Implementation: JNA
FileSysAbs->>FileSysJNA: queryStatvfs(path)
FileSysJNA->>JNALib: statvfs(path, buf)
JNALib-->>FileSysJNA: struct statvfs
FileSysJNA->>FileSysJNA: Extract f_files, f_ffree, blocks*frsize
FileSysJNA-->>FileSysAbs: long[] { inodes, free, space, usable, free }
else Implementation: FFM
FileSysAbs->>FileSysFFM: queryStatvfs(path)
FileSysFFM->>FFMLib: getloadavg(pathSeg, buf)
FFMLib->>FFMLib: Arena-allocated native memory
FFMLib->>FFMLib: invokeExact(statvfs handle)
FFMLib-->>FileSysFFM: int (return code)
FileSysFFM->>FileSysFFM: Extract via VarHandle accessors
FileSysFFM-->>FileSysAbs: long[] { inodes, free, space, usable, free }
end
FileSysAbs->>OSFileStore: Create with stats
OSFileStore-->>App: FileStore object
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3121 +/- ##
==========================================
+ Coverage 66.81% 67.70% +0.88%
==========================================
Files 37 37
Lines 2025 2025
Branches 336 336
==========================================
+ Hits 1353 1371 +18
+ Misses 557 539 -18
Partials 115 115 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Use LINKER.defaultLookup() instead of libraryLookup("c") to resolve
libc symbols. libraryLookup maps "c" to "libc.so" via
System.mapLibraryName, which fails on Linux where the actual soname
is "libc.so.6". libc is always linked into the JVM process so the
default lookup covers all its symbols without opening the library
by name.
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java (1)
95-111: Consider simplifying the redundanthasGettid()check.At line 99,
LinuxLibcFunctions.hasGettid()is checked again inside theHAS_SYSCALL_GETTIDblock, but this was already evaluated during static initialization at line 50. IfHAS_SYSCALL_GETTIDis true andhasGettid()was true at init time, it will still be true here. The current code is safe but slightly redundant.That said, rechecking at runtime provides defense against any hypothetical scenario where the function pointer could become invalid, so this is acceptable as a defensive measure.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java` around lines 95 - 111, The getThreadId method redundantly calls LinuxLibcFunctions.hasGettid() inside the HAS_SYSCALL_GETTID guard; remove that runtime check and directly invoke the appropriate getter (use LinuxLibcFunctions.gettid() when HAS_SYSCALL_GETTID is true) and fall back to the Files.readSymbolicLink parsing as before; update the try block in getThreadId to call LinuxLibcFunctions.gettid() (and keep the existing catch and fallback) so you no longer re-evaluate LinuxLibcFunctions.hasGettid() at runtime.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java`:
- Around line 45-53: The SYS_GETTID mapping currently sets a fallback of 224 for
unknown arches which is incorrect for several architectures; update the logic in
LinuxLibcFunctions where SYS_GETTID is assigned (the block using
System.getProperty("os.arch") and the SYS_GETTID constant) to explicitly handle
riscv64, s390x, ppc64le, and loongarch64 with the correct syscall numbers
(riscv64 -> 178, s390x -> 236, ppc64le -> 207, loongarch64 -> 178), keep
existing mappings for aarch64/arm64 and amd64/x86_64, and use a safe default or
throw an informative exception/log if an unknown/unsupported arch is encountered
so gettid() probes aren't silently incorrect.
- Around line 262-264: The method sysinfoProcs currently returns a signed short
but should expose the unsigned 16-bit sysinfo.procs; change the signature of
sysinfoProcs(MemorySegment info) to return int and convert the raw 16-bit value
from SYSINFO_PROCS to an unsigned int (e.g., mask with 0xFFFF or use
Short.toUnsignedInt) before returning; update any callers to handle an int
instead of short.
- Around line 174-175: The gethostname native binding currently declares its
second parameter as JAVA_INT, which is incorrect on LP64 Linux where size_t is
64-bit; update the FunctionDescriptor.of(...) call used in LINKER.downcallHandle
for gethostname to use JAVA_LONG for the second parameter instead of JAVA_INT,
and change the corresponding wrapper method signature/parameter type for
gethostname from int to long so the call and ABI match; apply the same change
pattern to the similar binding located at the other occurrence referenced (lines
344-345) so both LINKER.downcallHandle(FunctionDescriptor.of(...)) and their
Java wrapper parameter types use JAVA_LONG.
In `@oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.java`:
- Around line 62-64: The code calls Udev.INSTANCE.udev_new() and immediately
uses the returned Udev.UdevContext (variable udev) to call enumerateNew(), but
udev_new() can return null; add a null check after Udev.INSTANCE.udev_new() and
handle the failure path (log or return early) before calling
udev.enumerateNew(). In other words, check if udev == null after the udev_new()
call in LinuxUsbDeviceJNA.java and avoid calling udev.enumerateNew() (or clean
up) when null to prevent a NullPointerException.
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.java`:
- Around line 46-57: The getDomainName() block leaks native memory because the
Addrinfo returned by LIBC.getaddrinfo(...) is freed only via Addrinfo.close()
which calls Util.freeMemory() (no-op for native C allocations); update the
try-with-resources handling around CloseablePointerByReference and Addrinfo so
that after using new Addrinfo(ptr.getValue()) you explicitly call
LIBC.freeaddrinfo(ptr.getValue()) (or LIBC.freeaddrinfo(info.getPointer()) if
available) before closing/letting Addrinfo be garbage-collected, mirroring the
pattern used in MacNetworkParams/FreeBsdNetworkParams; ensure you still return
the canonical name (info.ai_canonname) and handle nulls as before.
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java`:
- Line 53: The change made LinuxOperatingSystem into an abstract type with a
protected constructor and a new abstract factory, which is a public API break;
either revert the class to a concrete public class with a public constructor
(restore LinuxOperatingSystem to its previous non-abstract declaration and
public ctor) or add a deprecated compatibility shim by introducing a public
subclass (e.g., DeprecatedLinuxOperatingSystem) that provides a public
constructor and implements the new abstract factory methods, marked `@Deprecated`
and delegating to the new API; update all affected locations (the
LinuxOperatingSystem class, its constructor, and the newly introduced abstract
factory methods referenced around the changed blocks) so external subclasses can
still instantiate without changing their code.
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.java`:
- Around line 23-33: The getrlimit() return value is currently ignored in
queryRlimitSoft() and queryRlimitHard(), risking use of uninitialized
Resource.Rlimit fields on error; update both methods (queryRlimitSoft and
queryRlimitHard) to capture the int result from
LinuxLibc.INSTANCE.getrlimit(LinuxLibc.RLIMIT_NOFILE, rlimit), check for success
(0) and on failure call and return the fallback getProcessOpenFileLimit();
ensure you only read rlimit.rlim_cur or rlim_max when getrlimit succeeded and
otherwise return the fallback value, mirroring the error-handling pattern used
in LinuxOSProcessFFM.
---
Nitpick comments:
In
`@oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java`:
- Around line 95-111: The getThreadId method redundantly calls
LinuxLibcFunctions.hasGettid() inside the HAS_SYSCALL_GETTID guard; remove that
runtime check and directly invoke the appropriate getter (use
LinuxLibcFunctions.gettid() when HAS_SYSCALL_GETTID is true) and fall back to
the Files.readSymbolicLink parsing as before; update the try block in
getThreadId to call LinuxLibcFunctions.gettid() (and keep the existing catch and
fallback) so you no longer re-evaluate LinuxLibcFunctions.hasGettid() at
runtime.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: dc75890a-8108-4c23-b2c5-867037f245f1
📒 Files selected for processing (25)
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessor.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParams.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core/src/main/java/oshi/util/platform/linux/ProcPath.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: Test JDK 11, windows-latest
- GitHub Check: Test JDK 11, macos-latest
- GitHub Check: Test JDK 25, windows-latest
- GitHub Check: Test JDK 25, macos-latest
- GitHub Check: Analyze (java)
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
📚 Learning: 2026-04-05T15:37:16.042Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java:59-65
Timestamp: 2026-04-05T15:37:16.042Z
Learning: In OSHI's Linux USB device implementations (LinuxUsbDeviceFFM, and the JNA equivalent), when `getUsbDevices(boolean tree)` is called with `tree=false`, the returned flat list intentionally **includes** controller nodes — it does not exclude them. The existing Javadoc that says "returns a flat list excluding controllers" is incorrect. Do not flag the implementation for including controllers in flat mode; instead, flag only the Javadoc if it claims controllers are excluded.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.java
📚 Learning: 2026-04-05T05:40:43.357Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-04-05T05:39:18.791Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java
📚 Learning: 2026-04-05T16:15:03.230Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java:95-97
Timestamp: 2026-04-05T16:15:03.230Z
Learning: In `LinuxLogicalVolumeGroupJNA.getLogicalVolumeGroups()` (oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java), `physicalVolumesMap.get(e.getKey())` in the final stream mapping cannot return null: both `logicalVolumesMap` and `physicalVolumesMap` are populated via `computeIfAbsent` inside the same conditional block (`!Util.isBlank(vgName) && !Util.isBlank(lvName)`), so every VG key in `logicalVolumesMap` is guaranteed to have a corresponding entry in `physicalVolumesMap`. Do not flag this `.get()` call as a potential null-return issue. The FFM version uses `getOrDefault` as extra defensiveness, not because null is possible here.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.java
📚 Learning: 2026-03-29T20:01:06.452Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java11/src/main/java/module-info.java:10-17
Timestamp: 2026-03-29T20:01:06.452Z
Learning: In the oshi project, `oshi-core-java25/src/main/java/module-info.java` intentionally does NOT export `oshi.util.platform.unix.freebsd`, `oshi.util.platform.unix.openbsd`, or `oshi.util.platform.unix.solaris`, because the FFM (Foreign Function & Memory) implementation only supports Windows, macOS, and Linux. This differs from `oshi-core-java11/src/main/java/module-info.java` which exports all Unix platform packages. The asymmetry is by design.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/util/platform/linux/ProcPath.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessor.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-04-05T05:40:43.357Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI’s Linux FFM implementations (e.g., LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the corresponding JNA udev code, do not require/flag a missing null check around `udev_enumerate_new()`/`enumerateNew()`. Per libudev semantics, `udev_enumerate_new()` returns NULL only if udev itself is broken (e.g., OOM). Since `udev_new()` is already guarded and is the successful prerequisite for enumeration, treating `udev_enumerate_new()` as non-null is consistent with the established pattern; adding a redundant null guard would be inconsistent.
Applied to files:
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java
📚 Learning: 2026-04-05T05:39:18.791Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: When reviewing OSHI Linux FFM/JNA code that uses libudev, do not flag a missing null check on `udev_enumerate_new()` if `udev_new()` has already been guarded. Per libudev semantics, `udev_enumerate_new()` returns NULL only when the udev context itself is broken (e.g., OOM), so a successful `udev_new()` implies `udev_enumerate_new()` should succeed as well. Therefore, lack of a redundant null guard on `udev_enumerate_new()` is acceptable in this pattern.
Applied to files:
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java
📚 Learning: 2026-04-03T02:07:47.621Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3110
File: oshi-core-java25/src/main/java/oshi/hardware/platform/mac/MacHWDiskStoreFFM.java:119-121
Timestamp: 2026-04-03T02:07:47.621Z
Learning: In OSHI’s Java FFM/API implementation classes (e.g., *FFM.java) that implement/override `updateAttributes()`, preserve the intentional failure-handling pattern: catch `Throwable` and return `false` without logging. `updateAttributes()` is a public API whose contract is to signal failure via the boolean return value, and callers rely on that return value (so emitting logs from this path is not desired and should not be introduced during review unless the method contract changes).
Applied to files:
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java
📚 Learning: 2026-04-05T15:37:16.042Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java:59-65
Timestamp: 2026-04-05T15:37:16.042Z
Learning: For OSHI Linux USB device implementations, the behavior of `getUsbDevices(boolean tree)` with `tree=false` is intentional: the returned flat list includes controller nodes (it is not meant to exclude them). In code review, do not flag the implementation for including controllers in flat mode; instead, only flag/update documentation/JavaDoc that incorrectly claims controllers are excluded (e.g., Javadoc text like "returns a flat list excluding controllers" should be corrected).
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java
📚 Learning: 2026-03-29T20:03:00.830Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java25/src/main/java/oshi/util/platform/windows/PdhUtilFFM.java:87-89
Timestamp: 2026-03-29T20:03:00.830Z
Learning: In the OSHI FFM codebase (oshi-core-java25), all PDH/Kernel32/COM wrapper methods in classes like PdhFFM, Kernel32FFM, etc. declare `throws Throwable` solely as a compiler artifact of `MethodHandle.invokeExact`. They are native calls and do not throw Java checked exceptions in practice. The enclosing `getOpenFileDescriptors()` method in PdhUtilFFM already has an outer `catch (Throwable t)` that covers the entire method body including any `finally` blocks, so no exception-masking concern exists for cleanup calls like `PdhCloseQuery` in `finally`.
Applied to files:
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java
🔇 Additional comments (40)
oshi-core/src/main/java/oshi/util/platform/linux/ProcPath.java (1)
30-30: LGTM:LOADAVGbelongs inProcPath.Centralizing
/proc/loadavghere keeps the fallback path consistent with the rest of the configurable procfs constants.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessor.java (1)
501-509: LGTM: procfs fallback is clean.This keeps the base class native-agnostic and preserves the
-1dsentinel behavior for missing or unparsable load-average slots.oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java (1)
185-194: LGTM: the shared PID walk stays centralized.Using the factory here avoids duplicating the procfs traversal between the JNA and FFM process implementations.
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.java (1)
38-55: LGTM: native load-average fallback is robust.The FFM path validates
nelem, handles partial native results, and cleanly falls back to the procfs implementation on failure.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.java (1)
39-40: LGTM: USB delegation follows the rename.This keeps the HAL aligned with the new abstract-base + JNA-subclass split.
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java (1)
7-7: LGTM: the udev capability flag points at the new home.Importing
HAS_UDEVfromLinuxOperatingSystemJNAmatches where JNA capability detection now lives.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.java (1)
7-7: LGTM: correctHAS_UDEVsource after the refactor.The JNA disk path is now gated by the JNA-specific Linux OS capability probe.
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.java (1)
7-7: JNA-scopedHAS_UDEVimport looks correct.Line 7 cleanly aligns this class with the JNA capability flag source after the class split.
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.java (1)
7-7: Import migration to JNAHAS_UDEVis consistent.Line 7 correctly follows the new JNA-specific Linux OS wiring.
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.java (2)
7-7:HAS_UDEVimport update is good.Line 7 correctly binds this JNA implementation to the JNA OS feature flag.
143-152: Remove suggestion to add try-catch aroundgetloadavg().The
getloadavg()call relies on the return value (retval < 0) for error handling, which is the documented and consistent pattern across all OSHI platforms (Mac, Linux, Solaris, FreeBSD, OpenBSD). Native linkage errors are caught at library initialization time viaNative.load(), not at individual method invocations. No other JNA method calls in OSHI are wrapped in try-catch (e.g.,getpid(),sysctl(),getrlimit()), and this implementation correctly follows that established pattern.> Likely an incorrect or invalid review comment.oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.java (1)
25-39:queryStatvfscontract mapping looks correct.The returned tuple order and null-on-failure behavior match the base class expectations.
oshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.java (1)
24-39: JNAstatvfsimplementation is solid.The value ordering and failure handling align with the abstract
LinuxFileSystemcontract.oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParams.java (1)
15-19: Abstract base conversion is clean.The updated class role and Javadoc match the new subclass-based native implementations.
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.java (1)
32-45:⚠️ Potential issue | 🔴 CriticalCheck the return value from
LinuxLibcFunctions.getrlimit()before reading the rlimit struct.On lines 32 and 44,
getrlimit()returns anint(0 on success, -1 on error) but the return value is ignored. The method does not throw an exception on native failure, so the fallback catch block is never triggered. Ifgetrlimitfails, the rlimit struct remains uninitialized and garbage values are returned.Add an error check:
int rc = LinuxLibcFunctions.getrlimit(LinuxLibcFunctions.RLIMIT_NOFILE, rlim); if (rc != 0) { throw new IOException("getrlimit failed: " + rc); }⛔ Skipped due to learnings
Learnt from: dbwiddis Repo: oshi/oshi PR: 3014 File: oshi-core-java25/src/main/java/oshi/util/platform/windows/PdhUtilFFM.java:87-89 Timestamp: 2026-03-29T20:03:00.830Z Learning: In the OSHI FFM codebase (oshi-core-java25), all PDH/Kernel32/COM wrapper methods in classes like PdhFFM, Kernel32FFM, etc. declare `throws Throwable` solely as a compiler artifact of `MethodHandle.invokeExact`. They are native calls and do not throw Java checked exceptions in practice. The enclosing `getOpenFileDescriptors()` method in PdhUtilFFM already has an outer `catch (Throwable t)` that covers the entire method body including any `finally` blocks, so no exception-masking concern exists for cleanup calls like `PdhCloseQuery` in `finally`.Learnt from: dbwiddis Repo: oshi/oshi PR: 3117 File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65 Timestamp: 2026-04-05T05:40:43.357Z Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.Learnt from: dbwiddis Repo: oshi/oshi PR: 3117 File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65 Timestamp: 2026-04-05T05:39:18.791Z Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.java (1)
61-68: LGTM!The
getHostName()implementation correctly allocates a buffer sized toHOST_NAME_MAX + 1(accounting for null terminator), checks the return value, and falls back tosuper.getHostName()on failure. This matches the expected pattern from theAbstractNetworkParamsfallback in the relevant code snippet.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.java (2)
44-46: LGTM on the factory pattern for static entry point.Creating a temporary instance to invoke the inherited
queryUsbDevices(tree)is a clean way to leverage the template method pattern while maintaining API compatibility with the previous staticgetUsbDevices(boolean tree)signature.
96-101: LGTM on parent device handling.Correctly identifies root controllers (no USB parent) vs. hub-connected devices. The
getParentWithSubsystemDevtypereturns a borrowed reference that should not be unref'd, which is handled correctly here.oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.java (3)
49-49: LGTM on abstract class conversion.The conversion to an abstract class with
queryRlimitSoft()andqueryRlimitHard()abstract methods cleanly separates the native-specificgetrlimitimplementations into JNA and FFM subclasses while preserving shared logic in the base class.
286-296: LGTM on the rlimit delegation pattern.The conditional check
getProcessID() == this.os.getProcessId()correctly determines whether nativegetrlimitcan be used (current process only) or must fall back to parsing/proc/pid/limitsfor other processes. This maintains backward compatibility while enabling native implementations in subclasses.
487-502: LGTM on visibility change.Changing
getProcessOpenFileLimitfromprivatetoprotectedallows subclasses to use this method as a fallback when their nativegetrlimitimplementation fails, which is the intended pattern per the AI summary.oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.java (3)
63-70: LGTM on resource cleanup.The
freeaddrinfo(resPtr)call in thefinallyblock ensures the native memory allocated bygetaddrinfois properly released, even ifaddrinfoCanonamethrows an exception. This is the correct pattern for FFM native memory management.
28-38: LGTM ongetHostName()implementation.Proper use of confined arena for buffer allocation, correct buffer size with null terminator, and graceful fallback to
super.getHostName()on any failure. TheThrowablecatch is appropriate for FFM calls that can throw various exceptions.
49-62: Code correctly setsai_flagsat offset 0.The
ADDRINFO_LAYOUTdefinition confirmsai_flagsis the first field in the struct, so offset 0 is correct. No changes needed.oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java (2)
47-59: LGTM on gettid capability detection.The static initialization properly detects syscall availability with a fallback chain: first checks if
gettid()function exists directly, then triessyscallGettid()as a fallback. The> 0check is correct since thread IDs are always positive integers.
113-125: LGTM ongetThreadCount()implementation.Proper use of confined arena for the
sysinfostruct allocation, correct error checking on the return value, and appropriate error logging with a0fallback. TheThrowablecatch handles FFM-specific exceptions.oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java (3)
45-83: LGTM on static capability detection.The static initialization properly detects library availability with appropriate error handling:
HAS_UDEV: Respects config flag and catchesUnsatisfiedLinkErrorHAS_GETTID/HAS_SYSCALL_GETTID: Progressive fallback detectionNoClassDefFoundErrorcatch at line 77 handles missing JNA classes gracefullyThe logging levels (warn for udev, debug for gettid fallbacks, error for JNA class issues) are appropriately chosen.
128-140: LGTM ongetThreadCount()with proper resource management.The
CloseableSysinfofromoshi.jna.Struct(per the relevant code snippet) properly implementsAutoCloseablewithUtil.freeMemory(getPointer()), ensuring no native memory leak. The error handling withNative.getLastError()provides useful diagnostic information.
114-126: LGTM ongetThreadId()fallback chain.Mirrors the FFM implementation with the same logic: prefers
gettid()when available, falls back tosyscall(SYS_GETTID), and ultimately reads from/proc/thread-selfif syscalls are unavailable. TheProcPath.THREAD_SELFconstant correctly resolves to/proc/thread-self.oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java (3)
60-64: LGTM on udev initialization with proper null check.Unlike the JNA counterpart, this implementation correctly checks for
MemorySegment.NULL.equals(udev)before proceeding. Per the retrieved learnings, the subsequentudev_enumerate_new()at line 66 does not need a null guard since a successfuludev_new()implies it will succeed.
107-117: LGTM on parent device handling.Correctly identifies root controllers vs. hub-connected devices. The parent reference from
getParentWithSubsystemDevtypeis a borrowed reference in libudev semantics, so it correctly doesn't get unref'd. TheparentPathnull check at line 114 is a good defensive measure.
118-130: LGTM on resource cleanup.Proper nested try/finally blocks ensure all udev resources are released in reverse order of allocation: device → enumerate → udev context. The
Throwablecatch at line 128 handles FFM exceptions gracefully.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.java (3)
21-34: LGTM on abstract class structure.The refactoring cleanly extracts the USB enumeration logic into an abstract base class with:
- Protected constants shared between JNA and FFM implementations
- Protected constructor restricting instantiation to subclasses
- Well-documented abstract methods for the template method pattern
78-106: LGTM on template method implementation.The
queryUsbDevicesmethod properly orchestrates the USB discovery flow:
- Calls subclass
enumerateUsbDevices()to populate maps- Builds device tree via
getDeviceAndChildren()- Handles both tree and flat list modes correctly
The flat list at lines 98-105 intentionally includes controllers, which is the documented behavior per the retrieved learnings.
115-129: LGTM on recursive tree building.The
getDeviceAndChildrenmethod correctly:
- Inherits vendor/product IDs from parent when not specified
- Uses
createDevice()factory for polymorphic instantiation- Handles missing hub entries gracefully with
getOrDefaultoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.java (5)
38-38: LGTM!Clean refactoring to abstract class enabling the template method pattern for JNA/FFM implementations.
58-67: LGTM!The abstract method is well-documented with clear contract for the array structure. The null-on-failure semantic enables clean fallback logic in the caller.
69-107: LGTM!Good extraction of
buildUuidMap()as a reusable helper. ThegetFileStoresmethod correctly passesthisto enable polymorphic native calls.
109-115: LGTM!Clean overload pattern maintaining backward compatibility. The comment on line 109 helpfully documents the null-instance use case from
LinuxOSFileStore.
194-208: LGTM!The null guards are properly placed and the fallback logic is preserved. The array access relies on the documented contract in
queryStatvfs, which is appropriate for this internal protected API.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java (1)
55-58: Consider logging unknown architectures for easier debugging.When the architecture doesn't match any known case, silently defaulting to 224 could make troubleshooting difficult on exotic platforms. A debug-level log would help identify when the fallback is used.
💡 Optional: Log unknown architecture
+ } else if (arch.contains("x86") || arch.contains("i386") || arch.contains("arm")) { + // x86-32, ARM32 — 224 is correct + SYS_GETTID = 224L; } else { - // x86-32, ARM32, and other arches — 224 is correct for these + // Unknown architecture — 224 is common fallback for 32-bit arches + LOG.debug("Unknown architecture '{}', using SYS_GETTID=224", arch); SYS_GETTID = 224L; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java` around lines 55 - 58, In LinuxLibcFunctions, when falling back to the default SYS_GETTID = 224L (the else branch), add a debug-level log that records the unexpected architecture string (e.g., from System.getProperty("os.arch") or the existing architecture variable) so maintainers can see when the fallback is used; update the else block that sets SYS_GETTID to 224L to call the class logger (or create/use the existing LOG) with a message like "Unknown architecture, defaulting SYS_GETTID to 224" plus the architecture value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.java`:
- Around line 47-53: The check after calling LIBC.getaddrinfo in
LinuxNetworkParamsJNA (the variable res from LIBC.getaddrinfo(hostname, null,
hint, ptr)) only catches positive errors; change the condition from "res > 0" to
"res != 0" so all non-zero return codes (including negative EAI_SYSTEM) are
treated as failures, log the error with LOG.error("Failed getaddrinfo(): {}",
LIBC.gai_strerror(res)) as before, and return early to avoid dereferencing ptr
when getaddrinfo failed.
---
Nitpick comments:
In `@oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java`:
- Around line 55-58: In LinuxLibcFunctions, when falling back to the default
SYS_GETTID = 224L (the else branch), add a debug-level log that records the
unexpected architecture string (e.g., from System.getProperty("os.arch") or the
existing architecture variable) so maintainers can see when the fallback is
used; update the else block that sets SYS_GETTID to 224L to call the class
logger (or create/use the existing LOG) with a message like "Unknown
architecture, defaulting SYS_GETTID to 224" plus the architecture value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 81fd870b-964c-4a79-9ff3-a70ca3bc8ec1
📒 Files selected for processing (7)
CHANGELOG.mdoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.java
✅ Files skipped from review due to trivial changes (1)
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (4)
- oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.java
- oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.java
- oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.java
- oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: Test JDK 11, macos-latest
- GitHub Check: Test JDK 25, windows-latest
- GitHub Check: Test JDK 25, macos-latest
- GitHub Check: Analyze (java)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java11/src/main/java/module-info.java:10-17
Timestamp: 2026-03-29T20:01:06.452Z
Learning: In the oshi project, `oshi-core-java25/src/main/java/module-info.java` intentionally does NOT export `oshi.util.platform.unix.freebsd`, `oshi.util.platform.unix.openbsd`, or `oshi.util.platform.unix.solaris`, because the FFM (Foreign Function & Memory) implementation only supports Windows, macOS, and Linux. This differs from `oshi-core-java11/src/main/java/module-info.java` which exports all Unix platform packages. The asymmetry is by design.
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, only interfaces and classes in the root packages `oshi`, `oshi.hardware`, and `oshi.software.os` are considered the public API. Code in subpackages that represent specific implementations/platforms (e.g., `oshi.software.os.linux`, `oshi.hardware.platform.linux`, and similar subpackages) is implementation detail. When reviewing, do not treat changes to classes in these platform-specific subpackages as public API breaks (for example: making `LinuxOperatingSystem` abstract, narrowing constructor visibility, or adding/removing abstract methods should not be flagged as breaking public API).
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.java
📚 Learning: 2026-03-29T20:01:06.452Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java11/src/main/java/module-info.java:10-17
Timestamp: 2026-03-29T20:01:06.452Z
Learning: In the oshi project, `oshi-core-java25/src/main/java/module-info.java` intentionally does NOT export `oshi.util.platform.unix.freebsd`, `oshi.util.platform.unix.openbsd`, or `oshi.util.platform.unix.solaris`, because the FFM (Foreign Function & Memory) implementation only supports Windows, macOS, and Linux. This differs from `oshi-core-java11/src/main/java/module-info.java` which exports all Unix platform packages. The asymmetry is by design.
Applied to files:
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, the public API is strictly limited to interfaces and classes in the `oshi`, `oshi.hardware`, and `oshi.software.os` packages. All platform-specific code under subpackages like `oshi.software.os.linux`, `oshi.hardware.platform.linux`, etc., is considered implementation detail — not public API. Do not flag changes to platform-specific classes (e.g., making `LinuxOperatingSystem` abstract, narrowing constructor visibility, adding abstract methods) as public API breaks.
Applied to files:
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-03-29T20:03:00.830Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java25/src/main/java/oshi/util/platform/windows/PdhUtilFFM.java:87-89
Timestamp: 2026-03-29T20:03:00.830Z
Learning: In the OSHI FFM codebase (oshi-core-java25), all PDH/Kernel32/COM wrapper methods in classes like PdhFFM, Kernel32FFM, etc. declare `throws Throwable` solely as a compiler artifact of `MethodHandle.invokeExact`. They are native calls and do not throw Java checked exceptions in practice. The enclosing `getOpenFileDescriptors()` method in PdhUtilFFM already has an outer `catch (Throwable t)` that covers the entire method body including any `finally` blocks, so no exception-masking concern exists for cleanup calls like `PdhCloseQuery` in `finally`.
Applied to files:
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-04-05T05:40:43.357Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Applied to files:
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-04-05T05:39:18.791Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
Applied to files:
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
🔇 Additional comments (10)
oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.java (1)
57-59: Native cleanup is correctly placed infinally.Good call freeing
getaddrinforesults withfreeaddrinfoin all return paths.oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java (9)
85-96: LGTM!The
SYSINFO_LAYOUTcorrectly models the 64-bit Linuxstruct sysinfowith proper padding for 8-byte alignment.
100-117: LGTM!The
STATVFS_LAYOUTand its field accessors correctly model the 64-bit Linuxstruct statvfs.
119-150: LGTM!
RLIMIT_LAYOUTandADDRINFO_LAYOUTare correctly defined. The modeling ofai_addrlenasJAVA_LONG(combining the 4-bytesocklen_twith its alignment padding) maintains correct field offsets for accessingai_canonname.
168-201: LGTM!The static initializer correctly uses
LINKER.defaultLookup()for libc symbols and implements a clean fallback pattern forgettidavailability detection.
269-271: Unsignedprocshandling is now correct.The use of
Short.toUnsignedInt()properly handles the unsigned 16-bitprocsfield, preventing negative values when process counts exceed 32,767.
351-353:gethostnameABI is now correct.The
long lenparameter correctly matches the LP64size_ttype on 64-bit Linux.
284-342: LGTM!The
statvfsfield accessors correctly returnlongvalues matching theunsigned longC types.
407-436: LGTM!The
getrlimitbinding andrlimitfield accessors are correctly implemented for 64-bit Linux.
385-388: No action required.getStringFromNativePointeris inherited from the parent classForeignFunctions(whichLinuxLibcFunctionsextends) and is properly accessible to bothgaiStrerror()andaddrinfoCanoname().
- LinuxLibcFunctions: add SYS_GETTID mappings for riscv64/loongarch64 (178), s390x (236), ppc64le (207); log unknown arch at debug level rather than silently using a potentially wrong value - LinuxLibcFunctions: sysinfoProcs returns int via Short.toUnsignedInt to correctly expose the unsigned 16-bit procs field - LinuxLibcFunctions: gethostname size_t parameter changed from JAVA_INT to JAVA_LONG to match LP64 Linux ABI; wrapper updated to accept long - LinuxNetworkParamsFFM: pass long literal to gethostname call - LinuxNetworkParamsJNA: fix getaddrinfo error check from res > 0 to res != 0 to catch negative EAI_SYSTEM codes; call freeaddrinfo() explicitly to release C-allocated addrinfo memory (Addrinfo.close() is a no-op for native allocations) - LinuxUsbDeviceJNA: null-check udev_new() return before use - LinuxOSProcessJNA: check getrlimit() return value; fall back to getProcessOpenFileLimit() on failure - LinuxOSProcessFFM: same getrlimit() return value check and fallback
|
@CodeRabbit full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.java (1)
487-501:⚠️ Potential issue | 🟠 MajorHandle
"unlimited"in the procfs fallback.Line 500 assumes the
Max open filesrow always contains numeric soft/hard values. When/proc/<pid>/limitsreportsunlimited, this split yields too few elements and throwsArrayIndexOutOfBoundsExceptioninstead of returning a sentinel value. That becomes more reachable now that the new JNA/FFM implementations fall back to this helper.Possible fix
- final String[] split = maxOpenFilesLine.get().split("\\D+"); - return ParseUtil.parseLongOrDefault(split[index], -1); + final String[] split = ParseUtil.whitespaces.split(maxOpenFilesLine.get().trim()); + if (split.length <= index + 2) { + return -1L; + } + final String value = split[index + 2]; + return "unlimited".equalsIgnoreCase(value) ? -1L : ParseUtil.parseLongOrDefault(value, -1L);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.java` around lines 487 - 501, The helper LinuxOSProcess.getProcessOpenFileLimit currently assumes the "Max open files" line always has numeric values; update it to handle "unlimited" and avoid ArrayIndexOutOfBounds by first checking maxOpenFilesLine.get() for the literal "unlimited" (return -1) and then guarding the split array length before indexing; if split.length <= index or the split[index] is empty/non-numeric, return the sentinel -1, otherwise pass split[index] to ParseUtil.parseLongOrDefault as before.
🧹 Nitpick comments (1)
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java (1)
72-83: RoutegetProcess()throughcreateOSProcess().
getProcess(int pid)is bypassing the helper you just added below and re-encoding the constructor choice inline. CallingcreateOSProcess(pid)here keeps the single-process and bulk-query paths aligned if process construction changes again. The same cleanup applies to the JNA sibling.♻️ Proposed cleanup
`@Override` public OSProcess getProcess(int pid) { - OSProcess proc = new LinuxOSProcessFFM(pid, this); + OSProcess proc = createOSProcess(pid); if (!proc.getState().equals(State.INVALID)) { return proc; } return null; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java` around lines 72 - 83, getProcess(int pid) currently constructs a LinuxOSProcessFFM directly instead of using the helper createOSProcess(pid); update getProcess to call createOSProcess(pid) (so it becomes OSProcess proc = createOSProcess(pid)) and retain the existing validity check (proc.getState().equals(State.INVALID))/return logic; also make the analogous change in the JNA sibling so both single-process and bulk-query paths use the same factory method.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.java`:
- Around line 109-115: The current helper call hardcodes a null LinuxFileSystem
instance (via getFileStoreMatching(nameToMatch, uuidMap, localOnly) delegating
to the 4-arg overload with null), which prevents
LinuxOSFileStore.updateAttributes() from reaching queryStatvfs() on refresh;
change callers (notably LinuxOSFileStore.updateAttributes()) to call the
4-argument getFileStoreMatching(...) passing the active LinuxFileSystem
instance, or convert the matching logic into an instance method on
LinuxFileSystem so both initial enumeration and refresh paths use the same
instance-backed queryStatvfs() code; ensure the other duplicate call site region
(the similar 194-200 block) is updated the same way so inode/space values
continue to come from statvfs.
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java`:
- Around line 129-135: The method getThreadCount currently returns info.procs
directly which can sign-extend the unsigned short value; change the return to
convert the unsigned short to an int by applying Short.toUnsignedInt(info.procs)
before returning (within the existing try-with-resources using CloseableSysinfo
and keeping the existing error handling and logging).
---
Outside diff comments:
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.java`:
- Around line 487-501: The helper LinuxOSProcess.getProcessOpenFileLimit
currently assumes the "Max open files" line always has numeric values; update it
to handle "unlimited" and avoid ArrayIndexOutOfBounds by first checking
maxOpenFilesLine.get() for the literal "unlimited" (return -1) and then guarding
the split array length before indexing; if split.length <= index or the
split[index] is empty/non-numeric, return the sentinel -1, otherwise pass
split[index] to ParseUtil.parseLongOrDefault as before.
---
Nitpick comments:
In
`@oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java`:
- Around line 72-83: getProcess(int pid) currently constructs a
LinuxOSProcessFFM directly instead of using the helper createOSProcess(pid);
update getProcess to call createOSProcess(pid) (so it becomes OSProcess proc =
createOSProcess(pid)) and retain the existing validity check
(proc.getState().equals(State.INVALID))/return logic; also make the analogous
change in the JNA sibling so both single-process and bulk-query paths use the
same factory method.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c3ad1532-1ad2-4769-adc0-91151400e98e
📒 Files selected for processing (26)
CHANGELOG.mdoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessor.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParams.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core/src/main/java/oshi/util/platform/linux/ProcPath.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Codacy Static Code Analysis
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
📚 Learning: 2026-04-05T15:37:16.042Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java:59-65
Timestamp: 2026-04-05T15:37:16.042Z
Learning: In OSHI's Linux USB device implementations (LinuxUsbDeviceFFM, and the JNA equivalent), when `getUsbDevices(boolean tree)` is called with `tree=false`, the returned flat list intentionally **includes** controller nodes — it does not exclude them. The existing Javadoc that says "returns a flat list excluding controllers" is incorrect. Do not flag the implementation for including controllers in flat mode; instead, flag only the Javadoc if it claims controllers are excluded.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.java
📚 Learning: 2026-04-05T05:40:43.357Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaCHANGELOG.mdoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java
📚 Learning: 2026-04-05T05:39:18.791Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaCHANGELOG.mdoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, only interfaces and classes in the root packages `oshi`, `oshi.hardware`, and `oshi.software.os` are considered the public API. Code in subpackages that represent specific implementations/platforms (e.g., `oshi.software.os.linux`, `oshi.hardware.platform.linux`, and similar subpackages) is implementation detail. When reviewing, do not treat changes to classes in these platform-specific subpackages as public API breaks (for example: making `LinuxOperatingSystem` abstract, narrowing constructor visibility, or adding/removing abstract methods should not be flagged as breaking public API).
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessor.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParams.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, the public API is strictly limited to interfaces and classes in the `oshi`, `oshi.hardware`, and `oshi.software.os` packages. All platform-specific code under subpackages like `oshi.software.os.linux`, `oshi.hardware.platform.linux`, etc., is considered implementation detail — not public API. Do not flag changes to platform-specific classes (e.g., making `LinuxOperatingSystem` abstract, narrowing constructor visibility, adding abstract methods) as public API breaks.
Applied to files:
oshi-core/src/main/java/oshi/util/platform/linux/ProcPath.javaCHANGELOG.mdoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.javaoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-03-29T20:01:06.452Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java11/src/main/java/module-info.java:10-17
Timestamp: 2026-03-29T20:01:06.452Z
Learning: In the oshi project, `oshi-core-java25/src/main/java/module-info.java` intentionally does NOT export `oshi.util.platform.unix.freebsd`, `oshi.util.platform.unix.openbsd`, or `oshi.util.platform.unix.solaris`, because the FFM (Foreign Function & Memory) implementation only supports Windows, macOS, and Linux. This differs from `oshi-core-java11/src/main/java/module-info.java` which exports all Unix platform packages. The asymmetry is by design.
Applied to files:
oshi-core/src/main/java/oshi/util/platform/linux/ProcPath.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessor.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.javaoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java
📚 Learning: 2026-04-05T16:15:03.230Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java:95-97
Timestamp: 2026-04-05T16:15:03.230Z
Learning: In `LinuxLogicalVolumeGroupJNA.getLogicalVolumeGroups()` (oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java), `physicalVolumesMap.get(e.getKey())` in the final stream mapping cannot return null: both `logicalVolumesMap` and `physicalVolumesMap` are populated via `computeIfAbsent` inside the same conditional block (`!Util.isBlank(vgName) && !Util.isBlank(lvName)`), so every VG key in `logicalVolumesMap` is guaranteed to have a corresponding entry in `physicalVolumesMap`. Do not flag this `.get()` call as a potential null-return issue. The FFM version uses `getOrDefault` as extra defensiveness, not because null is possible here.
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystemJNA.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.java
📚 Learning: 2026-04-05T05:40:43.357Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI’s Linux FFM implementations (e.g., LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the corresponding JNA udev code, do not require/flag a missing null check around `udev_enumerate_new()`/`enumerateNew()`. Per libudev semantics, `udev_enumerate_new()` returns NULL only if udev itself is broken (e.g., OOM). Since `udev_new()` is already guarded and is the successful prerequisite for enumeration, treating `udev_enumerate_new()` as non-null is consistent with the established pattern; adding a redundant null guard would be inconsistent.
Applied to files:
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java
📚 Learning: 2026-04-05T05:39:18.791Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: When reviewing OSHI Linux FFM/JNA code that uses libudev, do not flag a missing null check on `udev_enumerate_new()` if `udev_new()` has already been guarded. Per libudev semantics, `udev_enumerate_new()` returns NULL only when the udev context itself is broken (e.g., OOM), so a successful `udev_new()` implies `udev_enumerate_new()` should succeed as well. Therefore, lack of a redundant null guard on `udev_enumerate_new()` is acceptable in this pattern.
Applied to files:
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java
📚 Learning: 2026-04-03T02:07:47.621Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3110
File: oshi-core-java25/src/main/java/oshi/hardware/platform/mac/MacHWDiskStoreFFM.java:119-121
Timestamp: 2026-04-03T02:07:47.621Z
Learning: In OSHI’s Java FFM/API implementation classes (e.g., *FFM.java) that implement/override `updateAttributes()`, preserve the intentional failure-handling pattern: catch `Throwable` and return `false` without logging. `updateAttributes()` is a public API whose contract is to signal failure via the boolean return value, and callers rely on that return value (so emitting logs from this path is not desired and should not be introduced during review unless the method contract changes).
Applied to files:
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOSProcessFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java
📚 Learning: 2026-03-29T20:03:00.830Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java25/src/main/java/oshi/util/platform/windows/PdhUtilFFM.java:87-89
Timestamp: 2026-03-29T20:03:00.830Z
Learning: In the OSHI FFM codebase (oshi-core-java25), all PDH/Kernel32/COM wrapper methods in classes like PdhFFM, Kernel32FFM, etc. declare `throws Throwable` solely as a compiler artifact of `MethodHandle.invokeExact`. They are native calls and do not throw Java checked exceptions in practice. The enclosing `getOpenFileDescriptors()` method in PdhUtilFFM already has an outer `catch (Throwable t)` that covers the entire method body including any `finally` blocks, so no exception-masking concern exists for cleanup calls like `PdhCloseQuery` in `finally`.
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcessJNA.javaoshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java
📚 Learning: 2026-04-05T15:37:16.042Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java:59-65
Timestamp: 2026-04-05T15:37:16.042Z
Learning: For OSHI Linux USB device implementations, the behavior of `getUsbDevices(boolean tree)` with `tree=false` is intentional: the returned flat list includes controller nodes (it is not meant to exclude them). In code review, do not flag the implementation for including controllers in flat mode; instead, only flag/update documentation/JavaDoc that incorrectly claims controllers are excluded (e.g., Javadoc text like "returns a flat list excluding controllers" should be corrected).
Applied to files:
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceJNA.javaoshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.java
📚 Learning: 2026-04-03T18:43:50.370Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3112
File: oshi-core/src/main/java/oshi/PlatformEnum.java:99-100
Timestamp: 2026-04-03T18:43:50.370Z
Learning: In oshi/oshi PlatformEnum.java, the DragonFly BSD detection uses `osName.equalsIgnoreCase("dragonflybsd")` intentionally, mirroring the exact same check in JNA's `Platform.java` source. Java's `os.name` property on DragonFly BSD is "dragonflybsd" (no space), so `startsWith("DragonFly")` is NOT the correct pattern here. Do not suggest changing it to `startsWith`.
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java
📚 Learning: 2026-04-03T18:44:46.910Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3112
File: oshi-core/src/main/java/oshi/PlatformEnum.java:63-66
Timestamp: 2026-04-03T18:44:46.910Z
Learning: In oshi/oshi PlatformEnum.java, the DRAGONFLYBSD enum constant is intentionally added for platform detection only (no implementation classes exist yet). It allows UnsupportedOperationException messages to say "DragonFly BSD" rather than "Unknown". Full DragonFly BSD support is tracked in issue `#2583`. Do not flag the missing switch-case implementations as a bug.
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java
📚 Learning: 2026-04-03T02:07:47.621Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3110
File: oshi-core-java25/src/main/java/oshi/hardware/platform/mac/MacHWDiskStoreFFM.java:119-121
Timestamp: 2026-04-03T02:07:47.621Z
Learning: In `oshi-core-java25/src/main/java/oshi/hardware/platform/mac/MacHWDiskStoreFFM.java` (and similar FFM/API implementations in OSHI), the `updateAttributes()` method intentionally uses `catch (Throwable e) { return false; }` without logging. This is by design: `updateAttributes()` is a public API method whose contract is to return `false` on failure; callers consume the boolean and would never see log output, so adding a log statement is not desired.
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java
🔇 Additional comments (26)
oshi-core/src/main/java/oshi/util/platform/linux/ProcPath.java (1)
30-30: LGTM!The new
LOADAVGconstant follows the established naming and ordering conventions for this utility class. The placement betweenDISKSTATSandMEMINFOmaintains alphabetical ordering.CHANGELOG.md (1)
5-7: LGTM!Clean consolidation of related PR entries into a single changelog item describing the Linux FFM migration work.
oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParams.java (1)
15-19: LGTM!Clean refactoring to an abstract base class. The Javadoc correctly documents that subclasses provide
getDomainName()andgetHostName()via native calls, while this class retains the command-line-based gateway implementations.oshi-core/src/main/java/oshi/software/os/linux/LinuxNetworkParamsJNA.java (2)
36-62: LGTM!The
getDomainName()implementation correctly:
- Uses
AI_CANONNAMEhint to request canonical name resolution- Checks for non-zero return from
getaddrinfo()(handles all error codes)- Properly frees the native
addrinfolinked list withLIBC.freeaddrinfo()in afinallyblock before exiting- Handles null
ai_canonnameby falling back to the original hostname
64-71: LGTM!The
getHostName()implementation correctly allocatesHOST_NAME_MAX + 1bytes for the null terminator and falls back tosuper.getHostName()on failure, which uses Java'sInetAddressfacilities.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.java (3)
21-34: LGTM!Clean refactoring to an abstract base class with protected constants and constructor. The shared USB attribute constants (
SUBSYSTEM_USB,DEVTYPE_USB_DEVICE, etc.) are correctly extracted for use by both JNA and FFM subclasses.
47-64: LGTM!Well-designed template method pattern with clear abstractions:
enumerateUsbDevices()lets subclasses populate the device maps via platform-specific udev bindingscreateDevice()provides a factory method for instantiating the correct concrete subclassThe Javadoc clearly documents the expected behavior of each hook.
78-106: LGTM!The
queryUsbDevices()template method cleanly orchestrates enumeration via the abstract hook, then builds the device tree or flat list as needed. The use ofgetOrDefault(..., Collections.emptyList())at line 121 is a nice defensive improvement.oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxUsbDeviceFFM.java (2)
42-50: LGTM!The static
getUsbDevices()entry point correctly delegates to the inheritedqueryUsbDevices()template method, andcreateDevice()properly instantiates the FFM-specific subclass.
52-131: LGTM!The
enumerateUsbDevices()implementation correctly:
- Guards against missing udev support with early return
- Properly manages udev resources with nested try-finally blocks
- Follows the established pattern of not null-checking
udev_enumerate_new()after successfuludev_new()- Uses inherited constants for attribute names ensuring consistency with the JNA implementation
oshi-core-java25/src/main/java/oshi/ffm/linux/LinuxLibcFunctions.java (4)
44-60: LGTM!The
SYS_GETTIDsyscall number mapping correctly handles the major Linux architectures:
- aarch64/arm64/riscv64/loongarch64 → 178 (asm-generic)
- amd64/x86_64 → 186 (x86-64 custom table)
- s390x → 236
- ppc64le → 207
The fallback to 224 (x86-32/ARM32) with debug logging for unknown architectures is a reasonable defensive default.
169-202: LGTM!The static initializer correctly:
- Uses
LINKER.defaultLookup()for libc symbols (avoiding the libc.so vs libc.so.6 issue on Linux)- Binds
gethostnamewithJAVA_LONGfor thesize_tparameter- Gracefully handles missing
gettid()by falling back tosyscall(SYS_GETTID)
270-272: LGTM!Correctly exposes the unsigned 16-bit
sysinfo.procsfield as a JavaintusingShort.toUnsignedInt(), preventing negative wrap-around on systems with more than 32,767 processes.
398-406: No null check needed forcanonPtr.The
getStringFromNativePointermethod already handles NULL segments gracefully (lines 75-77 in ForeignFunctions.java). It checks if the pointer is null or equalsMemorySegment.NULLand returns null, making the additional null check inaddrinfoCanonameunnecessary.> Likely an incorrect or invalid review comment.oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxFileSystemFFM.java (1)
24-40: LGTM!The
queryStatvfs()implementation correctly:
- Returns the array in the expected order:
[totalInodes, freeInodes, totalSpace, usableSpace, freeSpace]- Properly scales block counts by fragment size (
frsize) for space calculations- Returns
nullon failure, allowing the caller to fall back tojava.io.Filemethods- Uses confined arena for deterministic resource cleanup
The field mapping matches the JNA implementation exactly, ensuring consistent behavior.
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxNetworkParamsFFM.java (2)
28-38: LGTM ongetHostName()implementation.The FFM-based hostname retrieval correctly allocates a buffer with
HOST_NAME_MAX + 1for null termination, uses a confined arena for automatic cleanup, and properly falls back to the superclass on any failure.
58-70:⚠️ Potential issue | 🔴 Critical
freeaddrinfocalled even whengetaddrinfofails — undefined behavior.When
getaddrinforeturns non-zero (failure), the output pointerresPtris not allocated by libc and must not be passed tofreeaddrinfo. However, the current structure placesfreeaddrinfoin afinallyblock that executes unconditionally after therc != 0early return, causing potential crashes or undefined behavior.The
finallyblock at lines 68-70 will execute after thereturn ""at line 61, callingfreeaddrinfoon an invalid pointer.🐛 Proposed fix: move freeaddrinfo inside success path only
int rc = LinuxLibcFunctions.getaddrinfo(nodeSeg, MemorySegment.NULL, hints, resPP); if (rc != 0) { LOG.error("Failed getaddrinfo(): {}", LinuxLibcFunctions.gaiStrerror(rc, arena)); return ""; } // resPP holds the pointer to the first addrinfo struct MemorySegment resPtr = resPP.get(ValueLayout.ADDRESS, 0); try { String canonname = LinuxLibcFunctions.addrinfoCanoname(resPtr, arena); return canonname == null ? hostname : canonname.trim(); } finally { - LinuxLibcFunctions.freeaddrinfo(resPtr); + if (!MemorySegment.NULL.equals(resPtr)) { + LinuxLibcFunctions.freeaddrinfo(resPtr); + } }Alternatively, restructure to only enter the try-finally block after confirming success:
int rc = LinuxLibcFunctions.getaddrinfo(nodeSeg, MemorySegment.NULL, hints, resPP); if (rc != 0) { LOG.error("Failed getaddrinfo(): {}", LinuxLibcFunctions.gaiStrerror(rc, arena)); return ""; } // resPP holds the pointer to the first addrinfo struct MemorySegment resPtr = resPP.get(ValueLayout.ADDRESS, 0); - try { - String canonname = LinuxLibcFunctions.addrinfoCanoname(resPtr, arena); - return canonname == null ? hostname : canonname.trim(); - } finally { + String canonname = LinuxLibcFunctions.addrinfoCanoname(resPtr, arena); + String result = canonname == null ? hostname : canonname.trim(); + LinuxLibcFunctions.freeaddrinfo(resPtr); + return result; - LinuxLibcFunctions.freeaddrinfo(resPtr); - }> Likely an incorrect or invalid review comment.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHardwareAbstractionLayerJNA.java (1)
39-41: LGTM on USB device delegation update.The change correctly delegates to
LinuxUsbDeviceJNA.getUsbDevices(tree)now thatLinuxUsbDeviceis an abstract base class. This aligns with the JNA/FFM refactor pattern used throughout this PR.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java (1)
7-7: LGTM onHAS_UDEVimport source update.Correctly sources the udev capability flag from
LinuxOperatingSystemJNArather than the now-abstractLinuxOperatingSystem. This is consistent with the JNA/FFM architecture split where each implementation path has its own capability detection.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxNetworkIFJNA.java (1)
7-7: LGTM onHAS_UDEVimport source update.Consistent with the JNA/FFM refactor pattern applied across other Linux JNA classes.
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessor.java (2)
8-8: LGTM on newLOADAVGimport.Adding the static import for
ProcPath.LOADAVGsupports the refactoredgetSystemLoadAverageimplementation.
500-511: LGTM on/proc/loadavg-based implementation.This procfs-based fallback correctly:
- Reads and parses
/proc/loadavgwithout native calls- Handles missing or malformed entries by defaulting to
-1d- Serves as a reliable base implementation for JNA/FFM subclasses to fall back on
This aligns well with the JNA/FFM split where subclasses use native
getloadavg()and fall back to this pure-Java implementation on failure.oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxHWDiskStoreJNA.java (1)
7-7: LGTM onHAS_UDEVimport source update.Consistent with the JNA/FFM refactor pattern. JNA-based disk store implementation correctly references the JNA-specific udev capability flag.
oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceJNA.java (1)
7-7: LGTM onHAS_UDEVimport source update.Consistent with the JNA/FFM refactor pattern applied across all Linux JNA classes in this PR.
oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxCentralProcessorFFM.java (2)
11-11: LGTM on new FFM imports.Added imports support the FFM-based
getSystemLoadAverageimplementation.Also applies to: 23-23
38-55: LGTM on FFM-basedgetSystemLoadAverageimplementation.The implementation correctly:
- Validates
nelembounds (1-3) consistent with the base class- Allocates a properly-sized native double array using
ValueLayout.JAVA_DOUBLE- Handles partial results by checking
retval > ibefore reading each value- Falls back gracefully to the procfs-based superclass implementation on any failure
The
catch (Throwable e)with logging and fallback is appropriate here since this is not a boolean-returning API likeupdateAttributes().
…oring - LinuxOperatingSystemJNA: fix unsigned short sign-extension in getThreadCount via Short.toUnsignedInt - LinuxOperatingSystemJNA/FFM: use createOSProcess() in getProcess() - LinuxFileSystem: make getFileStoreMatching a non-static instance method so queryStatvfs dispatches polymorphically; remove null- instance overload - LinuxOSFileStore: store LinuxFileSystem reference; call fs.getFileStoreMatching() in updateAttributes() so statvfs is used on refresh - LinuxOSProcess: handle 'unlimited' and guard array bounds in getProcessOpenFileLimit() - Revert USB class refactoring (LinuxUsbDeviceJNA, abstract LinuxUsbDevice base) back to master branch state; fix HAS_UDEV import in LinuxUsbDevice to reference LinuxOperatingSystemJNA; USB consolidation deferred to a follow-up PR
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java (1)
47-59: Consider cachinghasGettid()result like the JNA version.The JNA implementation caches
HAS_GETTIDas a separate constant, allowinggetThreadId()to use it directly. Here,LinuxLibcFunctions.hasGettid()is called dynamically on eachgetThreadId()invocation (line 99). For consistency and to avoid repeated checks, consider caching the result:private static final boolean HAS_SYSCALL_GETTID; + private static final boolean HAS_GETTID; static { - boolean hasSyscallGettid = LinuxLibcFunctions.hasGettid(); + boolean hasGettid = LinuxLibcFunctions.hasGettid(); + boolean hasSyscallGettid = hasGettid; - if (!hasSyscallGettid) { + if (!hasGettid) { try { hasSyscallGettid = LinuxLibcFunctions.syscallGettid() > 0; } catch (Throwable e) { LOG.debug("Did not find working syscall gettid via FFM. Using procfs"); } } HAS_SYSCALL_GETTID = hasSyscallGettid; + HAS_GETTID = hasGettid; }Then use
HAS_GETTIDingetThreadId():- return LinuxLibcFunctions.hasGettid() ? LinuxLibcFunctions.gettid() + return HAS_GETTID ? LinuxLibcFunctions.gettid()Also applies to: 95-104
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java` around lines 47 - 59, The code currently calls LinuxLibcFunctions.hasGettid() dynamically in getThreadId(), causing repeated checks; instead use the already-initialized static HAS_SYSCALL_GETTID constant (set in the static block) to decide the path. Update getThreadId() to reference HAS_SYSCALL_GETTID and only call LinuxLibcFunctions.syscallGettid() when true (with the same try/catch behavior), and fall back to the procfs path otherwise; remove the repeated LinuxLibcFunctions.hasGettid() invocation so the cached result is used consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java`:
- Around line 77-79: In the catch block handling NoClassDefFoundError in
LinuxOperatingSystemJNA.java, the LOG.error message has a typo ("Did not JNA
classes..."); update the LOG.error call inside the catch (NoClassDefFoundError
e) to a proper, clear message such as "Did not find JNA classes. Investigate
incompatible version or missing native library." (keep the LOG.error(...)
invocation and existing catch handling intact).
---
Nitpick comments:
In
`@oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java`:
- Around line 47-59: The code currently calls LinuxLibcFunctions.hasGettid()
dynamically in getThreadId(), causing repeated checks; instead use the
already-initialized static HAS_SYSCALL_GETTID constant (set in the static block)
to decide the path. Update getThreadId() to reference HAS_SYSCALL_GETTID and
only call LinuxLibcFunctions.syscallGettid() when true (with the same try/catch
behavior), and fall back to the procfs path otherwise; remove the repeated
LinuxLibcFunctions.hasGettid() invocation so the cached result is used
consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 41366325-2773-43d0-b41f-fb69c4b5e692
📒 Files selected for processing (6)
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSFileStore.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java
✅ Files skipped from review due to trivial changes (1)
- oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxUsbDevice.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: Test JDK 11, windows-latest
- GitHub Check: Test JDK 25, macos-latest
- GitHub Check: Test JDK 21, macos-latest
- GitHub Check: Test JDK 25, windows-latest
- GitHub Check: Test JDK 11, macos-latest
- GitHub Check: Analyze (java)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, only interfaces and classes in the root packages `oshi`, `oshi.hardware`, and `oshi.software.os` are considered the public API. Code in subpackages that represent specific implementations/platforms (e.g., `oshi.software.os.linux`, `oshi.hardware.platform.linux`, and similar subpackages) is implementation detail. When reviewing, do not treat changes to classes in these platform-specific subpackages as public API breaks (for example: making `LinuxOperatingSystem` abstract, narrowing constructor visibility, or adding/removing abstract methods should not be flagged as breaking public API).
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxOSFileStore.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java
📚 Learning: 2026-04-05T16:15:03.230Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java:95-97
Timestamp: 2026-04-05T16:15:03.230Z
Learning: In `LinuxLogicalVolumeGroupJNA.getLogicalVolumeGroups()` (oshi-core/src/main/java/oshi/hardware/platform/linux/LinuxLogicalVolumeGroupJNA.java), `physicalVolumesMap.get(e.getKey())` in the final stream mapping cannot return null: both `logicalVolumesMap` and `physicalVolumesMap` are populated via `computeIfAbsent` inside the same conditional block (`!Util.isBlank(vgName) && !Util.isBlank(lvName)`), so every VG key in `logicalVolumesMap` is guaranteed to have a corresponding entry in `physicalVolumesMap`. Do not flag this `.get()` call as a potential null-return issue. The FFM version uses `getOrDefault` as extra defensiveness, not because null is possible here.
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxOSFileStore.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.java
📚 Learning: 2026-04-05T05:40:43.357Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:40:43.357Z
Learning: In OSHI's Linux FFM and JNA udev code, a null guard on `udev_enumerate_new()` is intentionally absent and should not be flagged. This is consistent across all four FFM classes (LinuxPowerSourceFFM, LinuxHWDiskStoreFFM, LinuxLogicalVolumeGroupFFM, LinuxUsbDeviceFFM) and the JNA implementation (which also does not guard `enumerateNew()` for null). Per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` (which is guarded) implies `udev_enumerate_new()` will succeed. Adding a null guard would be both redundant and inconsistent with the established pattern.
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java
📚 Learning: 2026-04-05T05:39:18.791Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3117
File: oshi-core-java25/src/main/java/oshi/hardware/platform/linux/LinuxPowerSourceFFM.java:62-65
Timestamp: 2026-04-05T05:39:18.791Z
Learning: In OSHI's Linux FFM/JNA udev code, a null guard on `udev_enumerate_new()` is unnecessary if `udev_new()` has already been guarded: per libudev semantics, `udev_enumerate_new()` only returns NULL when udev itself is broken (e.g. OOM), so a successful `udev_new()` implies `udev_enumerate_new()` will succeed as well. Do not flag missing null checks on `udev_enumerate_new()` as an issue.
Applied to files:
oshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.javaoshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.javaoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java
📚 Learning: 2026-04-06T04:45:47.644Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3121
File: oshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystem.java:53-53
Timestamp: 2026-04-06T04:45:47.644Z
Learning: In the oshi/oshi project, the public API is strictly limited to interfaces and classes in the `oshi`, `oshi.hardware`, and `oshi.software.os` packages. All platform-specific code under subpackages like `oshi.software.os.linux`, `oshi.hardware.platform.linux`, etc., is considered implementation detail — not public API. Do not flag changes to platform-specific classes (e.g., making `LinuxOperatingSystem` abstract, narrowing constructor visibility, adding abstract methods) as public API breaks.
Applied to files:
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java
📚 Learning: 2026-03-29T20:01:06.452Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java11/src/main/java/module-info.java:10-17
Timestamp: 2026-03-29T20:01:06.452Z
Learning: In the oshi project, `oshi-core-java25/src/main/java/module-info.java` intentionally does NOT export `oshi.util.platform.unix.freebsd`, `oshi.util.platform.unix.openbsd`, or `oshi.util.platform.unix.solaris`, because the FFM (Foreign Function & Memory) implementation only supports Windows, macOS, and Linux. This differs from `oshi-core-java11/src/main/java/module-info.java` which exports all Unix platform packages. The asymmetry is by design.
Applied to files:
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java
📚 Learning: 2026-04-03T02:07:47.621Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3110
File: oshi-core-java25/src/main/java/oshi/hardware/platform/mac/MacHWDiskStoreFFM.java:119-121
Timestamp: 2026-04-03T02:07:47.621Z
Learning: In OSHI’s Java FFM/API implementation classes (e.g., *FFM.java) that implement/override `updateAttributes()`, preserve the intentional failure-handling pattern: catch `Throwable` and return `false` without logging. `updateAttributes()` is a public API whose contract is to signal failure via the boolean return value, and callers rely on that return value (so emitting logs from this path is not desired and should not be introduced during review unless the method contract changes).
Applied to files:
oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java
🔇 Additional comments (12)
oshi-core/src/main/java/oshi/software/os/linux/LinuxOSProcess.java (5)
49-49: LGTM!Making the class abstract to enable JNA and FFM subclass implementations is appropriate. Per project conventions, this is implementation detail in a platform-specific subpackage, not a public API change.
69-76: LGTM!Clean accessor for subclasses to access the OS instance for polymorphic dispatch to JNA/FFM implementations.
287-296: LGTM!The delegation pattern correctly distinguishes between the current process (using native
getrlimitvia abstract methods) and other processes (parsing/proc/[pid]/limits). This aligns with the interface contract.
298-310: LGTM!Clean abstraction for native
getrlimitcalls with proper Javadoc. Subclasses (JNA/FFM) will provide the native implementations.
487-508: LGTM!Good improvements:
- Visibility change to
protectedenables subclass reuse for fallback logic- Handling "unlimited" correctly returns -1 per the
OSProcessinterface contract- Bounds check before array access prevents potential
ArrayIndexOutOfBoundsExceptionoshi-core/src/main/java/oshi/software/os/linux/LinuxOperatingSystemJNA.java (2)
128-140: LGTM! Unsigned conversion fix applied correctly.The use of
Short.toUnsignedInt(info.procs)properly handles values above 32767, preventing sign-extension to negative integers. This aligns with the FFM implementation and correctly addresses the unsigned short handling.
45-83: Well-structured capability detection with comprehensive error handling.The static initialization block properly probes for udev, gettid, and syscall availability with appropriate logging at each level. The outer
NoClassDefFoundErrorcatch ensures graceful degradation if JNA classes are missing entirely.oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java (3)
85-93: LGTM! Appropriate error handling with fallback.The broad
Throwablecatch is consistent with FFM error handling patterns in this codebase, and logging at warn level is appropriate forgetProcessId()failures since this isn't a boolean-return API method likeupdateAttributes().
113-125: LGTM! Proper Arena lifecycle and FFM error handling.The use of
Arena.ofConfined()with try-with-resources ensures proper memory management. The delegation toLinuxLibcFunctions.sysinfoProcs(info)(which handles the unsigned short conversion) maintains consistency with the JNA implementation'sShort.toUnsignedInt()fix.
61-83: LGTM! Factory methods correctly delegate to FFM implementations.The overrides properly instantiate FFM-specific classes (
LinuxFileSystemFFM,LinuxNetworkParamsFFM,LinuxOSProcessFFM) and thegetProcess()implementation correctly filters out processes withINVALIDstate.oshi-core/src/main/java/oshi/software/os/linux/LinuxOSFileStore.java (1)
17-17: Nice fix for refresh-time filesystem dispatch.Holding the originating
LinuxFileSystemhere keepsupdateAttributes()on the same JNA/FFM-backed path, so refreshed inode and space values continue to come from the nativestatvfs()implementation.Also applies to: 28-32, 84-85
oshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.java (1)
58-72: Nice abstraction boundary for filesystem stats.
queryStatvfs()cleanly isolates the native call while this base class keeps mount parsing, UUID resolution, and JVM fallback centralized. That makes the JNA/FFM subclasses thinner and keeps enumeration and refresh behavior aligned.Also applies to: 74-107, 109-109, 188-206
Completes the FFM port of all remaining Linux-specific classes, following the established pattern: abstract base (no JNA) in
oshi-core→*JNAsubclass inoshi-core→*FFMsubclass inoshi-core-java25.Changes
New FFM bindings (
oshi-core-java25)LinuxLibcFunctions— FFM bindings forgetpid,gettid,syscall(SYS_GETTID),getloadavg,sysinfo,statvfs,gethostname,getaddrinfo/freeaddrinfo/gai_strerror,getrlimit.Includes struct layouts:
SYSINFO_LAYOUT,STATVFS_LAYOUT,RLIMIT_LAYOUT,ADDRINFO_LAYOUT.Refactored classes
LinuxCentralProcessorgetSystemLoadAveragereads/proc/loadavgas fallbackLinuxCentralProcessorJNAgetloadavg()via JNA; falls back tosuperon failureLinuxCentralProcessorFFMLinuxLibcFunctions.getloadavg; falls back tosuperon anyThrowableLinuxUsbDeviceLinuxUsbDeviceJNA; new abstractLinuxUsbDevicebase holds shared template method, constants, and tree-building logicLinuxUsbDeviceFFMLinuxUsbDevice; implementsenumerateUsbDevicesviaUdevFunctionsLinuxFileSystemLinuxFileSystemJNAandLinuxFileSystemFFMaddedLinuxNetworkParamsLinuxNetworkParamsJNAandLinuxNetworkParamsFFMaddedLinuxOSProcessLinuxOSProcessJNAandLinuxOSProcessFFMaddedLinuxOperatingSystemLinuxOperatingSystemJNAcleaned up (removed redundant override)LinuxOperatingSystemFFMLinuxLibcFunctionsMinor fixes
ProcPath.LOADAVGconstant.getProcessCountoverride inLinuxOperatingSystemJNA(was identical to base class).
LinuxHardwareAbstractionLayerJNAto referenceLinuxUsbDeviceJNA.Summary by CodeRabbit
Release Notes
New Features
Refactoring
Bug Fixes