Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c
41119 views
1
/*
2
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#include "jni.h"
27
#include "jni_util.h"
28
#include "java_lang_ProcessHandleImpl.h"
29
#include "java_lang_ProcessHandleImpl_Info.h"
30
31
#include "ProcessHandleImpl_unix.h"
32
33
#include <stdio.h>
34
#include <errno.h>
35
#include <signal.h>
36
#include <stdlib.h>
37
#include <unistd.h>
38
#include <string.h>
39
40
#include <sys/sysctl.h>
41
42
/**
43
* Implementation of native ProcessHandleImpl functions for MAC OS X.
44
* See ProcessHandleImpl_unix.c for more details.
45
*/
46
47
void os_initNative(JNIEnv *env, jclass clazz) {}
48
49
/*
50
* Returns the children of the requested pid and optionally each parent.
51
*
52
* Use sysctl to accumulate any process whose parent pid is zero or matches.
53
* The resulting pids are stored into the array of longs.
54
* The number of pids is returned if they all fit.
55
* If the parentArray is non-null, store the parent pid.
56
* If the array is too short, excess pids are not stored and
57
* the desired length is returned.
58
*/
59
jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
60
jlongArray jparentArray, jlongArray jstimesArray) {
61
jlong* pids = NULL;
62
jlong* ppids = NULL;
63
jlong* stimes = NULL;
64
jsize parentArraySize = 0;
65
jsize arraySize = 0;
66
jsize stimesSize = 0;
67
jsize count = 0;
68
size_t bufSize = 0;
69
pid_t pid = (pid_t) jpid;
70
71
arraySize = (*env)->GetArrayLength(env, jarray);
72
JNU_CHECK_EXCEPTION_RETURN(env, -1);
73
if (jparentArray != NULL) {
74
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
75
JNU_CHECK_EXCEPTION_RETURN(env, -1);
76
77
if (arraySize != parentArraySize) {
78
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
79
return 0;
80
}
81
}
82
if (jstimesArray != NULL) {
83
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
84
JNU_CHECK_EXCEPTION_RETURN(env, -1);
85
86
if (arraySize != stimesSize) {
87
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
88
return 0;
89
}
90
}
91
92
// Get buffer size needed to read all processes
93
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
94
if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
95
JNU_ThrowByNameWithLastError(env,
96
"java/lang/RuntimeException", "sysctl failed");
97
return -1;
98
}
99
100
// Allocate buffer big enough for all processes
101
void *buffer = malloc(bufSize);
102
if (buffer == NULL) {
103
JNU_ThrowOutOfMemoryError(env, "malloc failed");
104
return -1;
105
}
106
107
// Read process info for all processes
108
if (sysctl(mib, 4, buffer, &bufSize, NULL, 0) < 0) {
109
JNU_ThrowByNameWithLastError(env,
110
"java/lang/RuntimeException", "sysctl failed");
111
free(buffer);
112
return -1;
113
}
114
115
do { // Block to break out of on Exception
116
struct kinfo_proc *kp = (struct kinfo_proc *) buffer;
117
unsigned long nentries = bufSize / sizeof (struct kinfo_proc);
118
long i;
119
120
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
121
if (pids == NULL) {
122
break;
123
}
124
if (jparentArray != NULL) {
125
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
126
if (ppids == NULL) {
127
break;
128
}
129
}
130
if (jstimesArray != NULL) {
131
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
132
if (stimes == NULL) {
133
break;
134
}
135
}
136
137
// Process each entry in the buffer
138
for (i = nentries; --i >= 0; ++kp) {
139
if (pid == 0 || kp->kp_eproc.e_ppid == pid) {
140
if (count < arraySize) {
141
// Only store if it fits
142
pids[count] = (jlong) kp->kp_proc.p_pid;
143
if (ppids != NULL) {
144
// Store the parentPid
145
ppids[count] = (jlong) kp->kp_eproc.e_ppid;
146
}
147
if (stimes != NULL) {
148
// Store the process start time
149
jlong startTime = kp->kp_proc.p_starttime.tv_sec * 1000 +
150
kp->kp_proc.p_starttime.tv_usec / 1000;
151
stimes[count] = startTime;
152
}
153
}
154
count++; // Count to tabulate size needed
155
}
156
}
157
} while (0);
158
159
if (pids != NULL) {
160
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
161
}
162
if (ppids != NULL) {
163
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
164
}
165
if (stimes != NULL) {
166
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
167
}
168
169
free(buffer);
170
// If more pids than array had size for; count will be greater than array size
171
return count;
172
}
173
174
/**
175
* Use sysctl and return the ppid, total cputime and start time.
176
* Return: -1 is fail; >= 0 is parent pid
177
* 'total' will contain the running time of 'pid' in nanoseconds.
178
* 'start' will contain the start time of 'pid' in milliseconds since epoch.
179
*/
180
pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t jpid,
181
jlong *totalTime, jlong *startTime) {
182
183
const pid_t pid = (pid_t) jpid;
184
pid_t ppid = -1;
185
struct kinfo_proc kp;
186
size_t bufSize = sizeof kp;
187
188
// Read the process info for the specific pid
189
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
190
191
if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
192
JNU_ThrowByNameWithLastError(env,
193
"java/lang/RuntimeException", "sysctl failed");
194
return -1;
195
}
196
if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
197
*startTime = (jlong) (kp.kp_proc.p_starttime.tv_sec * 1000 +
198
kp.kp_proc.p_starttime.tv_usec / 1000);
199
ppid = kp.kp_eproc.e_ppid;
200
}
201
202
// Get cputime if for current process
203
if (pid == getpid()) {
204
struct rusage usage;
205
if (getrusage(RUSAGE_SELF, &usage) == 0) {
206
jlong microsecs =
207
usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
208
usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
209
*totalTime = microsecs * 1000;
210
}
211
}
212
213
return ppid;
214
215
}
216
217
/**
218
* Return the uid of a process or -1 on error
219
*/
220
static uid_t getUID(pid_t pid) {
221
struct kinfo_proc kp;
222
size_t bufSize = sizeof kp;
223
224
// Read the process info for the specific pid
225
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
226
227
if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) == 0) {
228
if (bufSize > 0 && kp.kp_proc.p_pid == pid) {
229
return kp.kp_eproc.e_ucred.cr_uid;
230
}
231
}
232
return (uid_t)-1;
233
}
234
235
/**
236
* Retrieve the command and arguments for the process and store them
237
* into the Info object.
238
*/
239
void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
240
int mib[3], maxargs, nargs, i;
241
size_t size;
242
char *args, *cp, *sp, *np;
243
244
// Get the UID first. This is done here because it is cheap to do it here
245
// on other platforms like Linux/Solaris/AIX where the uid comes from the
246
// same source like the command line info.
247
unix_getUserInfo(env, jinfo, getUID(pid));
248
249
// Get the maximum size of the arguments
250
mib[0] = CTL_KERN;
251
mib[1] = KERN_ARGMAX;
252
size = sizeof(maxargs);
253
if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
254
JNU_ThrowByNameWithLastError(env,
255
"java/lang/RuntimeException", "sysctl failed");
256
return;
257
}
258
259
// Allocate an args buffer and get the arguments
260
args = (char *)malloc(maxargs);
261
if (args == NULL) {
262
JNU_ThrowOutOfMemoryError(env, "malloc failed");
263
return;
264
}
265
266
do { // a block to break out of on error
267
char *argsEnd;
268
jstring cmdexe = NULL;
269
270
mib[0] = CTL_KERN;
271
mib[1] = KERN_PROCARGS2;
272
mib[2] = pid;
273
size = (size_t) maxargs;
274
if (sysctl(mib, 3, args, &size, NULL, 0) == -1) {
275
if (errno != EINVAL) {
276
JNU_ThrowByNameWithLastError(env,
277
"java/lang/RuntimeException", "sysctl failed");
278
}
279
break;
280
}
281
memcpy(&nargs, args, sizeof(nargs));
282
283
cp = &args[sizeof(nargs)]; // Strings start after nargs
284
argsEnd = &args[size];
285
286
// Store the command executable path
287
if ((cmdexe = JNU_NewStringPlatform(env, cp)) == NULL) {
288
break;
289
}
290
291
// Skip trailing nulls after the executable path
292
for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
293
if (*cp != '\0') {
294
break;
295
}
296
}
297
298
unix_fillArgArray(env, jinfo, nargs, cp, argsEnd, cmdexe, NULL);
299
} while (0);
300
// Free the arg buffer
301
free(args);
302
}
303
304
305