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 }