1
2
3
4
5 package oshi.software.common;
6
7 import static oshi.software.os.OperatingSystem.ProcessFiltering.ALL_PROCESSES;
8 import static oshi.software.os.OperatingSystem.ProcessSorting.NO_SORTING;
9 import static oshi.util.Memoizer.memoize;
10
11 import java.util.ArrayDeque;
12 import java.util.Collection;
13 import java.util.Comparator;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.Queue;
19 import java.util.Set;
20 import java.util.function.Predicate;
21 import java.util.function.Supplier;
22 import java.util.stream.Collectors;
23
24 import com.sun.jna.Platform;
25
26 import oshi.software.os.OSProcess;
27 import oshi.software.os.OperatingSystem;
28 import oshi.util.GlobalConfig;
29 import oshi.util.tuples.Pair;
30
31
32
33
34 public abstract class AbstractOperatingSystem implements OperatingSystem {
35
36 protected static final boolean USE_WHO_COMMAND = GlobalConfig.get(GlobalConfig.OSHI_OS_UNIX_WHOCOMMAND, false);
37
38 private final Supplier<String> manufacturer = memoize(this::queryManufacturer);
39 private final Supplier<Pair<String, OSVersionInfo>> familyVersionInfo = memoize(this::queryFamilyVersionInfo);
40 private final Supplier<Integer> bitness = memoize(this::queryPlatformBitness);
41
42 @Override
43 public String getManufacturer() {
44 return manufacturer.get();
45 }
46
47 protected abstract String queryManufacturer();
48
49 @Override
50 public String getFamily() {
51 return familyVersionInfo.get().getA();
52 }
53
54 @Override
55 public OSVersionInfo getVersionInfo() {
56 return familyVersionInfo.get().getB();
57 }
58
59 protected abstract Pair<String, OSVersionInfo> queryFamilyVersionInfo();
60
61 @Override
62 public int getBitness() {
63 return bitness.get();
64 }
65
66 private int queryPlatformBitness() {
67 if (Platform.is64Bit()) {
68 return 64;
69 }
70
71
72 int jvmBitness = System.getProperty("os.arch").contains("64") ? 64 : 32;
73 return queryBitness(jvmBitness);
74 }
75
76
77
78
79
80
81
82 protected abstract int queryBitness(int jvmBitness);
83
84 @Override
85 public List<OSProcess> getProcesses(Predicate<OSProcess> filter, Comparator<OSProcess> sort, int limit) {
86 return queryAllProcesses().stream().filter(filter == null ? ALL_PROCESSES : filter)
87 .sorted(sort == null ? NO_SORTING : sort).limit(limit > 0 ? limit : Long.MAX_VALUE)
88 .collect(Collectors.toList());
89 }
90
91 protected abstract List<OSProcess> queryAllProcesses();
92
93 @Override
94 public List<OSProcess> getChildProcesses(int parentPid, Predicate<OSProcess> filter, Comparator<OSProcess> sort,
95 int limit) {
96
97 List<OSProcess> childProcs = queryChildProcesses(parentPid);
98
99 OSProcess parent = childProcs.stream().filter(p -> p.getProcessID() == parentPid).findAny().orElse(null);
100
101 long parentStartTime = parent == null ? 0 : parent.getStartTime();
102
103 return queryChildProcesses(parentPid).stream().filter(filter == null ? ALL_PROCESSES : filter)
104 .filter(p -> p.getProcessID() != parentPid && p.getStartTime() >= parentStartTime)
105 .sorted(sort == null ? NO_SORTING : sort).limit(limit > 0 ? limit : Long.MAX_VALUE)
106 .collect(Collectors.toList());
107 }
108
109 protected abstract List<OSProcess> queryChildProcesses(int parentPid);
110
111 @Override
112 public List<OSProcess> getDescendantProcesses(int parentPid, Predicate<OSProcess> filter,
113 Comparator<OSProcess> sort, int limit) {
114
115 List<OSProcess> descendantProcs = queryDescendantProcesses(parentPid);
116
117 OSProcess parent = descendantProcs.stream().filter(p -> p.getProcessID() == parentPid).findAny().orElse(null);
118
119 long parentStartTime = parent == null ? 0 : parent.getStartTime();
120
121 return queryDescendantProcesses(parentPid).stream().filter(filter == null ? ALL_PROCESSES : filter)
122 .filter(p -> p.getProcessID() != parentPid && p.getStartTime() >= parentStartTime)
123 .sorted(sort == null ? NO_SORTING : sort).limit(limit > 0 ? limit : Long.MAX_VALUE)
124 .collect(Collectors.toList());
125 }
126
127 protected abstract List<OSProcess> queryDescendantProcesses(int parentPid);
128
129
130
131
132
133
134
135
136
137
138 protected static Set<Integer> getChildrenOrDescendants(Collection<OSProcess> allProcs, int parentPid,
139 boolean allDescendants) {
140 Map<Integer, Integer> parentPidMap = allProcs.stream()
141 .collect(Collectors.toMap(OSProcess::getProcessID, OSProcess::getParentProcessID));
142 return getChildrenOrDescendants(parentPidMap, parentPid, allDescendants);
143 }
144
145
146
147
148
149
150
151
152
153
154 protected static Set<Integer> getChildrenOrDescendants(Map<Integer, Integer> parentPidMap, int parentPid,
155 boolean allDescendants) {
156
157 Set<Integer> descendantPids = new HashSet<>();
158 descendantPids.add(parentPid);
159
160 Queue<Integer> queue = new ArrayDeque<>();
161 queue.add(parentPid);
162
163 do {
164 for (int pid : getChildren(parentPidMap, queue.poll())) {
165 if (!descendantPids.contains(pid)) {
166 descendantPids.add(pid);
167 queue.add(pid);
168 }
169 }
170 } while (allDescendants && !queue.isEmpty());
171 return descendantPids;
172 }
173
174 private static Set<Integer> getChildren(Map<Integer, Integer> parentPidMap, int parentPid) {
175 return parentPidMap.entrySet().stream()
176 .filter(e -> e.getValue().equals(parentPid) && !e.getKey().equals(parentPid)).map(Entry::getKey)
177 .collect(Collectors.toSet());
178 }
179
180 @Override
181 public String toString() {
182 StringBuilder sb = new StringBuilder();
183 sb.append(getManufacturer()).append(' ').append(getFamily()).append(' ').append(getVersionInfo());
184 return sb.toString();
185 }
186 }