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