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 }