View Javadoc
1   /*
2    * Copyright 2016-2025 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.software.os;
6   
7   import java.util.ArrayList;
8   import java.util.Collection;
9   import java.util.Collections;
10  import java.util.Comparator;
11  import java.util.List;
12  import java.util.Objects;
13  import java.util.function.Predicate;
14  import java.util.stream.Collectors;
15  
16  import oshi.annotation.concurrent.Immutable;
17  import oshi.annotation.concurrent.ThreadSafe;
18  import oshi.driver.unix.Who;
19  import oshi.driver.unix.Xwininfo;
20  import oshi.software.os.OSProcess.State;
21  import oshi.util.Constants;
22  import oshi.util.UserGroupInfo;
23  import oshi.util.Util;
24  
25  /**
26   * An operating system (OS) is the software on a computer that manages the way different programs use its hardware, and
27   * regulates the ways that a user controls the computer.
28   * <p>
29   * Considered thread safe, but see remarks for the {@link #getSessions()} method.
30   */
31  @ThreadSafe
32  public interface OperatingSystem {
33  
34      /**
35       * Constants which may be used to filter Process lists in {@link #getProcesses(Predicate, Comparator, int)},
36       * {@link #getChildProcesses(int, Predicate, Comparator, int)}, and
37       * {@link #getDescendantProcesses(int, Predicate, Comparator, int)}.
38       */
39      final class ProcessFiltering {
40          private ProcessFiltering() {
41          }
42  
43          /**
44           * No filtering.
45           */
46          public static final Predicate<OSProcess> ALL_PROCESSES = p -> true;
47          /**
48           * Exclude processes with {@link State#INVALID} process state.
49           */
50          public static final Predicate<OSProcess> VALID_PROCESS = p -> !p.getState().equals(State.INVALID);
51          /**
52           * Exclude child processes. Only include processes which are their own parent.
53           */
54          public static final Predicate<OSProcess> NO_PARENT = p -> p.getParentProcessID() == p.getProcessID();
55          /**
56           * Only incude 64-bit processes.
57           */
58          public static final Predicate<OSProcess> BITNESS_64 = p -> p.getBitness() == 64;
59          /**
60           * Only include 32-bit processes.
61           */
62          public static final Predicate<OSProcess> BITNESS_32 = p -> p.getBitness() == 32;
63      }
64  
65      /**
66       * Constants which may be used to sort Process lists in {@link #getProcesses(Predicate, Comparator, int)},
67       * {@link #getChildProcesses(int, Predicate, Comparator, int)}, and
68       * {@link #getDescendantProcesses(int, Predicate, Comparator, int)}.
69       */
70      final class ProcessSorting {
71          private ProcessSorting() {
72          }
73  
74          /**
75           * No sorting
76           */
77          public static final Comparator<OSProcess> NO_SORTING = (p1, p2) -> 0;
78          /**
79           * Sort by decreasing cumulative CPU percentage
80           */
81          public static final Comparator<OSProcess> CPU_DESC = Comparator
82                  .comparingDouble(OSProcess::getProcessCpuLoadCumulative).reversed();
83          /**
84           * Sort by decreasing Resident Set Size (RSS)
85           */
86          public static final Comparator<OSProcess> RSS_DESC = Comparator.comparingLong(OSProcess::getResidentSetSize)
87                  .reversed();
88          /**
89           * Sort by up time, newest processes first
90           */
91          public static final Comparator<OSProcess> UPTIME_ASC = Comparator.comparingLong(OSProcess::getUpTime);
92          /**
93           * Sort by up time, oldest processes first
94           */
95          public static final Comparator<OSProcess> UPTIME_DESC = UPTIME_ASC.reversed();
96          /**
97           * Sort by Process Id
98           */
99          public static final Comparator<OSProcess> PID_ASC = Comparator.comparingInt(OSProcess::getProcessID);
100         /**
101          * Sort by Parent Process Id
102          */
103         public static final Comparator<OSProcess> PARENTPID_ASC = Comparator
104                 .comparingInt(OSProcess::getParentProcessID);
105         /**
106          * Sort by Process Name (case insensitive)
107          */
108         public static final Comparator<OSProcess> NAME_ASC = Comparator.comparing(OSProcess::getName,
109                 String.CASE_INSENSITIVE_ORDER);
110     }
111 
112     /**
113      * Get the Operating System family.
114      *
115      * @return the family
116      */
117     String getFamily();
118 
119     /**
120      * Get the Operating System manufacturer.
121      *
122      * @return the manufacturer
123      */
124     String getManufacturer();
125 
126     /**
127      * Get Operating System version information.
128      *
129      * @return version information
130      */
131     OSVersionInfo getVersionInfo();
132 
133     /**
134      * Instantiates a {@link oshi.software.os.FileSystem} object.
135      *
136      * @return A {@link oshi.software.os.FileSystem} object.
137      */
138     FileSystem getFileSystem();
139 
140     /**
141      * Instantiates a {@link oshi.software.os.InternetProtocolStats} object.
142      *
143      * @return a {@link oshi.software.os.InternetProtocolStats} object.
144      */
145     InternetProtocolStats getInternetProtocolStats();
146 
147     /**
148      * Gets currently running processes. No order is guaranteed.
149      *
150      * @return A list of {@link oshi.software.os.OSProcess} objects for the specified number (or all) of currently
151      *         running processes, sorted as specified. The list may contain null elements or processes with a state of
152      *         {@link OSProcess.State#INVALID} if a process terminates during iteration.
153      */
154     default List<OSProcess> getProcesses() {
155         return getProcesses(null, null, 0);
156     }
157 
158     /**
159      * Gets currently running processes, optionally filtering, sorting, and limited to the top "N".
160      *
161      * @param filter An optional {@link Predicate} limiting the results to the specified filter. Some common predicates
162      *               are available in {@link ProcessSorting}. May be {@code null} for no filtering.
163      * @param sort   An optional {@link Comparator} specifying the sorting order. Some common comparators are available
164      *               in {@link ProcessSorting}. May be {@code null} for no sorting.
165      * @param limit  Max number of results to return, or 0 to return all results
166      * @return A list of {@link oshi.software.os.OSProcess} objects, optionally filtered, sorted, and limited to the
167      *         specified number.
168      *         <p>
169      *         The list may contain processes with a state of {@link OSProcess.State#INVALID} if a process terminates
170      *         during iteration.
171      */
172     List<OSProcess> getProcesses(Predicate<OSProcess> filter, Comparator<OSProcess> sort, int limit);
173 
174     /**
175      * Gets information on a {@link Collection} of currently running processes. This has potentially improved
176      * performance vs. iterating individual processes.
177      *
178      * @param pids A collection of process IDs
179      * @return A list of {@link oshi.software.os.OSProcess} objects for the specified process ids if it is running
180      */
181     default List<OSProcess> getProcesses(Collection<Integer> pids) {
182         return pids.stream().map(this::getProcess).filter(Objects::nonNull).filter(ProcessFiltering.VALID_PROCESS)
183                 .collect(Collectors.toList());
184     }
185 
186     /**
187      * Gets information on a currently running process
188      *
189      * @param pid A process ID
190      * @return An {@link oshi.software.os.OSProcess} object for the specified process id if it is running; null
191      *         otherwise
192      */
193     OSProcess getProcess(int pid);
194 
195     /**
196      * Gets currently running child processes of provided parent PID, optionally filtering, sorting, and limited to the
197      * top "N".
198      *
199      * @param parentPid The Process ID whose children to list.
200      * @param filter    An optional {@link Predicate} limiting the results to the specified filter. Some common
201      *                  predicates are available in {@link ProcessSorting}. May be {@code null} for no filtering.
202      * @param sort      An optional {@link Comparator} specifying the sorting order. Some common comparators are
203      *                  available in {@link ProcessSorting}. May be {@code null} for no sorting.
204      * @param limit     Max number of results to return, or 0 to return all results
205      * @return A list of {@link oshi.software.os.OSProcess} objects representing the currently running child processes
206      *         of the provided PID, optionally filtered, sorted, and limited to the specified number.
207      *         <p>
208      *         The list may contain processes with a state of {@link OSProcess.State#INVALID} if a process terminates
209      *         during iteration.
210      */
211     List<OSProcess> getChildProcesses(int parentPid, Predicate<OSProcess> filter, Comparator<OSProcess> sort,
212             int limit);
213 
214     /**
215      * Gets currently running processes of provided parent PID's descendants, including their children, the children's
216      * children, etc., optionally filtering, sorting, and limited to the top "N".
217      *
218      * @param parentPid The Process ID whose children to list.
219      * @param filter    An optional {@link Predicate} limiting the results to the specified filter. Some common
220      *                  predicates are available in {@link ProcessSorting}. May be {@code null} for no filtering.
221      * @param sort      An optional {@link Comparator} specifying the sorting order. Some common comparators are
222      *                  available in {@link ProcessSorting}. May be {@code null} for no sorting.
223      * @param limit     Max number of results to return, or 0 to return all results
224      * @return A list of {@link oshi.software.os.OSProcess} objects representing the currently running descendant
225      *         processes of the provided PID, optionally filtered, sorted, and limited to the specified number.
226      *         <p>
227      *         The list may contain processes with a state of {@link OSProcess.State#INVALID} if a process terminates
228      *         during iteration.
229      */
230     List<OSProcess> getDescendantProcesses(int parentPid, Predicate<OSProcess> filter, Comparator<OSProcess> sort,
231             int limit);
232 
233     /**
234      * Gets the current process ID (PID).
235      *
236      * @return the Process ID of the current process
237      */
238     int getProcessId();
239 
240     /**
241      * Gets the current process.
242      *
243      * @return the current process
244      */
245     default OSProcess getCurrentProcess() {
246         return getProcess(getProcessId());
247     }
248 
249     /**
250      * Get the number of processes currently running
251      *
252      * @return The number of processes running
253      */
254     int getProcessCount();
255 
256     /**
257      * Makes a best effort to get the current thread ID (TID). May not be useful in a multithreaded environment. The
258      * thread ID returned may have been short lived and no longer exist.
259      * <p>
260      * Thread IDs on macOS are not correlated with any other Operating System output.
261      *
262      * @return the Thread ID of the current thread if known, 0 otherwise.
263      */
264     int getThreadId();
265 
266     /**
267      * Makes a best effort to get the current thread. May not be useful in a multithreaded environment. The thread
268      * returned may have been short lived and no longer exist.
269      * <p>
270      * On macOS, returns the oldest thread in the calling process.
271      *
272      * @return the current thread if known; an invalid thread otherwise.
273      */
274     OSThread getCurrentThread();
275 
276     /**
277      * Get the number of threads currently running
278      *
279      * @return The number of threads running
280      */
281     int getThreadCount();
282 
283     /**
284      * Gets the bitness (32 or 64) of the operating system.
285      *
286      * @return The number of bits supported by the operating system.
287      */
288     int getBitness();
289 
290     /**
291      * Get the System up time (time since boot).
292      *
293      * @return Number of seconds since boot.
294      */
295     long getSystemUptime();
296 
297     /**
298      * Get Unix time of boot.
299      *
300      * @return The approximate time at which the system booted, in seconds since the Unix epoch.
301      */
302     long getSystemBootTime();
303 
304     /**
305      * Determine whether the current process has elevated permissions such as sudo / Administrator
306      *
307      * @return True if this process has elevated permissions
308      */
309     default boolean isElevated() {
310         return UserGroupInfo.isElevated();
311     }
312 
313     /**
314      * Instantiates a {@link oshi.software.os.NetworkParams} object.
315      *
316      * @return A {@link oshi.software.os.NetworkParams} object.
317      */
318     NetworkParams getNetworkParams();
319 
320     /**
321      * Gets the all services on the system. The definition of what is a service is platform-dependent.
322      *
323      * @return An array of {@link OSService} objects
324      */
325     default List<OSService> getServices() {
326         return new ArrayList<>();
327     }
328 
329     /**
330      * Gets currently logged in users.
331      * <p>
332      * On macOS, Linux, and Unix systems, the default implementation uses native code (see {@code man getutxent}) that
333      * is not thread safe. OSHI's use of this code is synchronized and may be used in a multi-threaded environment
334      * without introducing any additional conflicts. Users should note, however, that other operating system code may
335      * access the same native code.
336      * <p>
337      * The {@link oshi.driver.unix.Who#queryWho()} method produces similar output parsing the output of the
338      * Posix-standard {@code who} command, and may internally employ reentrant code on some platforms. Users may opt to
339      * use this command-line variant by default using the {@code oshi.os.unix.whoCommand} configuration property.
340      *
341      * @return A list of {@link oshi.software.os.OSSession} objects representing logged-in users
342      */
343     default List<OSSession> getSessions() {
344         return Who.queryWho();
345     }
346 
347     /**
348      * Gets windows on the operating system's GUI desktop.
349      * <p>
350      * On Unix-like systems, reports X11 windows only, which may be limited to the current display and will not report
351      * windows used by other window managers.
352      * <p>
353      * While not a guarantee, a best effort is made to return windows in foreground-to-background order. This ordering
354      * may be used along with {@link OSDesktopWindow#getOrder()} to (probably) determine the frontmost window.
355      *
356      * @param visibleOnly Whether to restrict the list to only windows visible to the user.
357      *                    <p>
358      *                    This is a best effort attempt at a reasonable definition of visibility. Visible windows may be
359      *                    completely transparent.
360      * @return A list of {@link oshi.software.os.OSDesktopWindow} objects representing the desktop windows.
361      */
362     default List<OSDesktopWindow> getDesktopWindows(boolean visibleOnly) {
363         // Default X11 implementation for Unix-like operating systems.
364         // Overridden on Windows and macOS
365         return Xwininfo.queryXWindows(visibleOnly);
366     }
367 
368     /**
369      * Retrieves a list of installed applications on the system.
370      * <p>
371      * This method is implemented per OS. If the OS does not support this feature, it returns an empty list.
372      *
373      * @return A list of installed applications or an empty list if unsupported.
374      */
375     default List<ApplicationInfo> getInstalledApplications() {
376         return Collections.emptyList();
377     }
378 
379     /**
380      * A class representing the Operating System version details.
381      */
382     @Immutable
383     class OSVersionInfo {
384         private final String version;
385         private final String codeName;
386         private final String buildNumber;
387         private final String versionStr;
388 
389         public OSVersionInfo(String version, String codeName, String buildNumber) {
390             this.version = version;
391             this.codeName = codeName;
392             this.buildNumber = buildNumber;
393 
394             StringBuilder sb = new StringBuilder(getVersion() != null ? getVersion() : Constants.UNKNOWN);
395             if (!Util.isBlank(getCodeName())) {
396                 sb.append(" (").append(getCodeName()).append(')');
397             }
398             if (!Util.isBlank(getBuildNumber())) {
399                 sb.append(" build ").append(getBuildNumber());
400             }
401             this.versionStr = sb.toString();
402         }
403 
404         /**
405          * Gets the operating system version.
406          *
407          * @return The version, if any. May be {@code null}.
408          */
409         public String getVersion() {
410             return version;
411         }
412 
413         /**
414          * Gets the operating system codename.
415          *
416          * @return The code name, if any. May be {@code null}.
417          */
418         public String getCodeName() {
419             return codeName;
420         }
421 
422         /**
423          * Gets the operating system build number.
424          *
425          * @return The build number, if any. May be {@code null}.
426          */
427         public String getBuildNumber() {
428             return buildNumber;
429         }
430 
431         @Override
432         public String toString() {
433             return this.versionStr;
434         }
435     }
436 }