Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/windows/native/libjava/ProcessHandleImpl_win.c
41119 views
1
/*
2
* Copyright (c) 2014, 2020, 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
27
#include "jni.h"
28
#include "jvm.h"
29
#include "jni_util.h"
30
#include "java_lang_ProcessHandleImpl.h"
31
#include "java_lang_ProcessHandleImpl_Info.h"
32
33
#include <windows.h>
34
#include <tlhelp32.h>
35
#include <sddl.h>
36
37
static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
38
static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
39
static void procToUser(JNIEnv *env, HANDLE handle, jobject jinfo);
40
41
/**************************************************************
42
* Implementation of ProcessHandleImpl_Info native methods.
43
*/
44
45
/* Field id for jString 'command' in java.lang.ProcessHandle.Info */
46
static jfieldID ProcessHandleImpl_Info_commandID;
47
48
/* Field id for jString 'commandLine' in java.lang.ProcessHandleImpl.Info */
49
static jfieldID ProcessHandleImpl_Info_commandLineID;
50
51
/* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
52
static jfieldID ProcessHandleImpl_Info_argumentsID;
53
54
/* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
55
static jfieldID ProcessHandleImpl_Info_totalTimeID;
56
57
/* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
58
static jfieldID ProcessHandleImpl_Info_startTimeID;
59
60
/* Field id for jString 'accountName' in java.lang.ProcessHandleImpl.UserPrincipal */
61
static jfieldID ProcessHandleImpl_Info_userID;
62
63
/**************************************************************
64
* Static method to initialize field IDs.
65
*
66
* Class: java_lang_ProcessHandleImpl_Info
67
* Method: initIDs
68
* Signature: ()V
69
*/
70
JNIEXPORT void JNICALL
71
Java_java_lang_ProcessHandleImpl_00024Info_initIDs(JNIEnv *env, jclass clazz) {
72
73
CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
74
clazz, "command", "Ljava/lang/String;"));
75
CHECK_NULL(ProcessHandleImpl_Info_commandLineID = (*env)->GetFieldID(env,
76
clazz, "commandLine", "Ljava/lang/String;"));
77
CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
78
clazz, "arguments", "[Ljava/lang/String;"));
79
CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env,
80
clazz, "totalTime", "J"));
81
CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
82
clazz, "startTime", "J"));
83
CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
84
clazz, "user", "Ljava/lang/String;"));
85
}
86
/**************************************************************
87
* Static method to initialize native.
88
*
89
* Class: java_lang_ProcessHandleImpl
90
* Method: initNative
91
* Signature: ()V
92
*/
93
JNIEXPORT void JNICALL
94
Java_java_lang_ProcessHandleImpl_initNative(JNIEnv *env, jclass clazz) {
95
}
96
97
/*
98
* Block until a child process exits and return its exit code.
99
*/
100
JNIEXPORT jint JNICALL
101
Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
102
jclass junk,
103
jlong jpid,
104
jboolean reapStatus) {
105
DWORD pid = (DWORD)jpid;
106
DWORD exitValue = -1;
107
HANDLE handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION,
108
FALSE, pid);
109
if (handle == NULL) {
110
return exitValue; // No process with that pid is alive
111
}
112
do {
113
if (!GetExitCodeProcess(handle, &exitValue)) {
114
JNU_ThrowByNameWithLastError(env,
115
"java/lang/RuntimeException", "GetExitCodeProcess");
116
break;
117
}
118
if (exitValue == STILL_ACTIVE) {
119
HANDLE events[2];
120
events[0] = handle;
121
events[1] = JVM_GetThreadInterruptEvent();
122
123
if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
124
FALSE, /* Wait for ANY event */
125
INFINITE) /* Wait forever */
126
== WAIT_FAILED) {
127
JNU_ThrowByNameWithLastError(env,
128
"java/lang/RuntimeException", "WaitForMultipleObjects");
129
break;
130
}
131
}
132
} while (exitValue == STILL_ACTIVE);
133
CloseHandle(handle); // Ignore return code
134
return exitValue;
135
}
136
137
/*
138
* Returns the pid of the caller.
139
*
140
* Class: java_lang_ProcessHandleImpl
141
* Method: getCurrentPid0
142
* Signature: ()J
143
*/
144
JNIEXPORT jlong JNICALL
145
Java_java_lang_ProcessHandleImpl_getCurrentPid0(JNIEnv *env, jclass clazz) {
146
DWORD pid = GetCurrentProcessId();
147
return (jlong)pid;
148
}
149
150
/*
151
* Returns the parent pid of the requested pid.
152
*
153
* Class: java_lang_ProcessHandleImpl
154
* Method: parent0
155
* Signature: (J)J
156
*/
157
JNIEXPORT jlong JNICALL
158
Java_java_lang_ProcessHandleImpl_parent0(JNIEnv *env,
159
jclass clazz,
160
jlong jpid,
161
jlong startTime) {
162
DWORD ppid = 0;
163
DWORD wpid = (DWORD)jpid;
164
PROCESSENTRY32 pe32;
165
HANDLE hProcessSnap;
166
jlong start;
167
168
start = Java_java_lang_ProcessHandleImpl_isAlive0(env, clazz, jpid);
169
if (start != startTime && start != 0 && startTime != 0) {
170
return -1;
171
}
172
173
// Take a snapshot of all processes in the system.
174
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
175
if (hProcessSnap == INVALID_HANDLE_VALUE) {
176
JNU_ThrowByName(env,
177
"java/lang/RuntimeException", "snapshot not available");
178
return -1;
179
}
180
181
// Retrieve information about the first process,
182
pe32.dwSize = sizeof (PROCESSENTRY32);
183
if (Process32First(hProcessSnap, &pe32)) {
184
// Now walk the snapshot of processes, and
185
do {
186
if (wpid == pe32.th32ProcessID) {
187
// The parent PID may be stale if that process has exited
188
// and may have been reused.
189
// A valid parent's start time is the same or before the child's
190
jlong ppStartTime = Java_java_lang_ProcessHandleImpl_isAlive0(env,
191
clazz, pe32.th32ParentProcessID);
192
if (ppStartTime > 0 && ppStartTime <= startTime) {
193
ppid = pe32.th32ParentProcessID;
194
}
195
break;
196
}
197
} while (Process32Next(hProcessSnap, &pe32));
198
} else {
199
JNU_ThrowByName(env,
200
"java/lang/RuntimeException", "snapshot not available");
201
ppid = (DWORD)-1;
202
}
203
CloseHandle(hProcessSnap); // Ignore return code
204
return (jlong)ppid;
205
}
206
207
/*
208
* Returns the children of the requested pid and optionally each parent.
209
*
210
* Class: java_lang_ProcessHandleImpl
211
* Method: getChildPids
212
* Signature: (J[J[J)I
213
*/
214
JNIEXPORT jint JNICALL
215
Java_java_lang_ProcessHandleImpl_getProcessPids0(JNIEnv *env,
216
jclass clazz,
217
jlong jpid,
218
jlongArray jarray,
219
jlongArray jparentArray,
220
jlongArray jstimesArray) {
221
HANDLE hProcessSnap;
222
PROCESSENTRY32 pe32;
223
DWORD ppid = (DWORD)jpid;
224
jlong* pids = NULL;
225
jlong* ppids = NULL;
226
jlong* stimes = NULL;
227
jsize parentArraySize = 0;
228
jsize arraySize = 0;
229
jsize stimesSize = 0;
230
jsize count = 0;
231
232
arraySize = (*env)->GetArrayLength(env, jarray);
233
JNU_CHECK_EXCEPTION_RETURN(env, -1);
234
if (jparentArray != NULL) {
235
parentArraySize = (*env)->GetArrayLength(env, jparentArray);
236
JNU_CHECK_EXCEPTION_RETURN(env, -1);
237
238
if (arraySize != parentArraySize) {
239
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
240
return 0;
241
}
242
}
243
if (jstimesArray != NULL) {
244
stimesSize = (*env)->GetArrayLength(env, jstimesArray);
245
JNU_CHECK_EXCEPTION_RETURN(env, -1);
246
247
if (arraySize != stimesSize) {
248
JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
249
return 0;
250
}
251
}
252
253
// Take a snapshot of all processes in the system.
254
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
255
if (hProcessSnap == INVALID_HANDLE_VALUE) {
256
JNU_ThrowByName(env,
257
"java/lang/RuntimeException", "snapshot not available");
258
return 0;
259
}
260
261
// Retrieve information about the first process,
262
pe32.dwSize = sizeof (PROCESSENTRY32);
263
if (Process32First(hProcessSnap, &pe32)) {
264
do { // Block to break out of on Exception
265
pids = (*env)->GetLongArrayElements(env, jarray, NULL);
266
if (pids == NULL) {
267
break;
268
}
269
if (jparentArray != NULL) {
270
ppids = (*env)->GetLongArrayElements(env, jparentArray, NULL);
271
if (ppids == NULL) {
272
break;
273
}
274
}
275
if (jstimesArray != NULL) {
276
stimes = (*env)->GetLongArrayElements(env, jstimesArray, NULL);
277
if (stimes == NULL) {
278
break;
279
}
280
}
281
// Now walk the snapshot of processes, and
282
// save information about each process in turn
283
do {
284
if (ppid == 0 ||
285
(pe32.th32ParentProcessID > 0
286
&& (pe32.th32ParentProcessID == ppid))) {
287
if (count < arraySize) {
288
// Only store if it fits
289
pids[count] = (jlong) pe32.th32ProcessID;
290
if (ppids != NULL) {
291
// Store the parentPid
292
ppids[count] = (jlong) pe32.th32ParentProcessID;
293
}
294
if (stimes != NULL) {
295
// Store the process start time
296
stimes[count] =
297
Java_java_lang_ProcessHandleImpl_isAlive0(env,
298
clazz, (jlong) pe32.th32ProcessID);
299
}
300
}
301
count++; // Count to tabulate size needed
302
}
303
} while (Process32Next(hProcessSnap, &pe32));
304
} while (0);
305
306
if (pids != NULL) {
307
(*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
308
}
309
if (ppids != NULL) {
310
(*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
311
}
312
if (stimes != NULL) {
313
(*env)->ReleaseLongArrayElements(env, jstimesArray, stimes, 0);
314
}
315
} else {
316
JNU_ThrowByName(env,
317
"java/lang/RuntimeException", "snapshot not available");
318
count = 0;
319
}
320
CloseHandle(hProcessSnap);
321
// If more pids than array had size for; count will be greater than array size
322
return (jint)count;
323
}
324
325
/**
326
* Assemble a 64 bit value from two 32 bit values.
327
*/
328
static jlong jlong_from(jint high, jint low) {
329
jlong result = 0;
330
result = ((jlong)high << 32) | ((0x000000000ffffffff) & (jlong)low);
331
return result;
332
}
333
334
/*
335
* Get the start time in ms from 1970 from the handle.
336
*/
337
static jlong getStartTime(HANDLE handle) {
338
FILETIME CreationTime, ExitTime, KernelTime, UserTime;
339
if (GetProcessTimes(handle, &CreationTime, &ExitTime, &KernelTime, &UserTime)) {
340
jlong start = jlong_from(CreationTime.dwHighDateTime,
341
CreationTime.dwLowDateTime) / 10000;
342
start -= 11644473600000L; // Rebase Epoch from 1601 to 1970
343
return start;
344
} else {
345
return 0;
346
}
347
}
348
349
/*
350
* Destroy the process.
351
*
352
* Class: java_lang_ProcessHandleImpl
353
* Method: destroy0
354
* Signature: (Z)V
355
*/
356
JNIEXPORT jboolean JNICALL
357
Java_java_lang_ProcessHandleImpl_destroy0(JNIEnv *env,
358
jclass clazz,
359
jlong jpid,
360
jlong startTime,
361
jboolean force) {
362
DWORD pid = (DWORD)jpid;
363
jboolean ret = JNI_FALSE;
364
HANDLE handle = OpenProcess(PROCESS_TERMINATE | THREAD_QUERY_INFORMATION
365
| PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
366
if (handle != NULL) {
367
jlong start = getStartTime(handle);
368
if (start == startTime || startTime == 0) {
369
ret = TerminateProcess(handle, 1) ? JNI_TRUE : JNI_FALSE;
370
}
371
CloseHandle(handle); // Ignore return code
372
}
373
return ret;
374
}
375
376
/*
377
* Check if a process is alive.
378
* Return the start time (ms since 1970) if it is available.
379
* If the start time is not available return 0.
380
* If the pid is invalid, return -1.
381
*
382
* Class: java_lang_ProcessHandleImpl
383
* Method: isAlive0
384
* Signature: (J)J
385
*/
386
JNIEXPORT jlong JNICALL
387
Java_java_lang_ProcessHandleImpl_isAlive0(JNIEnv *env, jclass clazz, jlong jpid) {
388
DWORD pid = (DWORD)jpid;
389
390
jlong ret = -1;
391
HANDLE handle =
392
OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
393
FALSE, pid);
394
if (handle != NULL) {
395
DWORD dwExitStatus;
396
397
GetExitCodeProcess(handle, &dwExitStatus);
398
if (dwExitStatus == STILL_ACTIVE) {
399
ret = getStartTime(handle);
400
} else {
401
ret = -1;
402
}
403
CloseHandle(handle); // Ignore return code
404
}
405
return ret;
406
}
407
408
/*
409
* Fill in the Info object from the OS information about the process.
410
*
411
* Class: java_lang_ProcessHandleImpl
412
* Method: info0
413
* Signature: (J)V
414
*/
415
JNIEXPORT void JNICALL
416
Java_java_lang_ProcessHandleImpl_00024Info_info0(JNIEnv *env,
417
jobject jinfo,
418
jlong jpid) {
419
DWORD pid = (DWORD)jpid;
420
int ret = 0;
421
HANDLE handle =
422
OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
423
FALSE, pid);
424
if (handle == NULL) {
425
return;
426
}
427
getStatInfo(env, handle, jinfo);
428
getCmdlineInfo(env, handle, jinfo);
429
procToUser(env, handle, jinfo);
430
431
CloseHandle(handle); // Ignore return code
432
}
433
434
/**
435
* Read /proc/<pid>/stat and fill in the fields of the Info object.
436
* The executable name, plus the user, system, and start times are gathered.
437
*/
438
static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
439
FILETIME CreationTime;
440
FILETIME ExitTime;
441
FILETIME KernelTime;
442
FILETIME UserTime;
443
jlong userTime; // nanoseconds
444
jlong totalTime; // nanoseconds
445
jlong startTime; // nanoseconds
446
UserTime.dwHighDateTime = 0;
447
UserTime.dwLowDateTime = 0;
448
KernelTime.dwHighDateTime = 0;
449
KernelTime.dwLowDateTime = 0;
450
CreationTime.dwHighDateTime = 0;
451
CreationTime.dwLowDateTime = 0;
452
453
if (GetProcessTimes(handle, &CreationTime, &ExitTime, &KernelTime, &UserTime)) {
454
userTime = jlong_from(UserTime.dwHighDateTime, UserTime.dwLowDateTime);
455
totalTime = jlong_from( KernelTime.dwHighDateTime, KernelTime.dwLowDateTime);
456
totalTime = (totalTime + userTime) * 100; // convert sum to nano-seconds
457
458
startTime = jlong_from(CreationTime.dwHighDateTime,
459
CreationTime.dwLowDateTime) / 10000;
460
startTime -= 11644473600000L; // Rebase Epoch from 1601 to 1970
461
462
(*env)->SetLongField(env, jinfo,
463
ProcessHandleImpl_Info_totalTimeID, totalTime);
464
JNU_CHECK_EXCEPTION(env);
465
(*env)->SetLongField(env, jinfo,
466
ProcessHandleImpl_Info_startTimeID, startTime);
467
JNU_CHECK_EXCEPTION(env);
468
}
469
}
470
471
static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
472
WCHAR exeName[1024];
473
WCHAR *longPath;
474
DWORD bufsize = sizeof(exeName)/sizeof(WCHAR);
475
jstring commandObj = NULL;
476
477
if (QueryFullProcessImageNameW(handle, 0, exeName, &bufsize)) {
478
commandObj = (*env)->NewString(env, (const jchar *)exeName,
479
(jsize)wcslen(exeName));
480
} else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
481
bufsize = 32768;
482
longPath = (WCHAR*)malloc(bufsize * sizeof(WCHAR));
483
if (longPath != NULL) {
484
if (QueryFullProcessImageNameW(handle, 0, longPath, &bufsize)) {
485
commandObj = (*env)->NewString(env, (const jchar *)longPath,
486
(jsize)wcslen(longPath));
487
}
488
free(longPath);
489
}
490
}
491
CHECK_NULL(commandObj);
492
(*env)->SetObjectField(env, jinfo,
493
ProcessHandleImpl_Info_commandID, commandObj);
494
}
495
496
static void procToUser(JNIEnv *env, HANDLE handle, jobject jinfo) {
497
#define TOKEN_LEN 256
498
DWORD token_len = TOKEN_LEN;
499
char token_buf[TOKEN_LEN];
500
TOKEN_USER *token_user = (TOKEN_USER*)token_buf;
501
HANDLE tokenHandle;
502
WCHAR domain[255 + 1 + 255 + 1]; // large enough to concat with '/' and name
503
WCHAR name[255 + 1];
504
DWORD domainLen = sizeof(domain) - sizeof(name);
505
DWORD nameLen = sizeof(name);
506
SID_NAME_USE use;
507
jstring s;
508
int ret;
509
510
if (!OpenProcessToken(handle, TOKEN_READ, &tokenHandle)) {
511
return;
512
}
513
514
ret = GetTokenInformation(tokenHandle, TokenUser, token_user,
515
token_len, &token_len);
516
CloseHandle(tokenHandle); // always close handle
517
if (!ret) {
518
JNU_ThrowByNameWithLastError(env,
519
"java/lang/RuntimeException", "GetTokenInformation");
520
return;
521
}
522
523
if (LookupAccountSidW(NULL, token_user->User.Sid, &name[0], &nameLen,
524
&domain[0], &domainLen, &use) == 0) {
525
// Name not available, convert to a String
526
LPWSTR str;
527
if (ConvertSidToStringSidW(token_user->User.Sid, &str) == 0) {
528
return;
529
}
530
s = (*env)->NewString(env, (const jchar *)str, (jsize)wcslen(str));
531
LocalFree(str);
532
} else {
533
wcscat(domain, L"\\");
534
wcscat(domain, name);
535
s = (*env)->NewString(env, (const jchar *)domain, (jsize)wcslen(domain));
536
}
537
CHECK_NULL(s);
538
(*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, s);
539
}
540
541