Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/windows/native/libjava/ProcessImpl_md.c
41119 views
1
/*
2
* Copyright (c) 1997, 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 <assert.h>
27
#include "java_lang_ProcessImpl.h"
28
29
#include "jni.h"
30
#include "jvm.h"
31
#include "jni_util.h"
32
#include "io_util.h"
33
#include "io_util_md.h"
34
#include <windows.h>
35
#include <io.h>
36
37
/* We try to make sure that we can read and write 4095 bytes (the
38
* fixed limit on Linux) to the pipe on all operating systems without
39
* deadlock. Windows 2000 inexplicably appears to need an extra 24
40
* bytes of slop to avoid deadlock.
41
*/
42
#define PIPE_SIZE (4096+24)
43
44
/* We have THREE locales in action:
45
* 1. Thread default locale - dictates UNICODE-to-8bit conversion
46
* 2. System locale that defines the message localization
47
* 3. The file name locale
48
* Each locale could be an extended locale, that means that text cannot be
49
* mapped to 8bit sequence without multibyte encoding.
50
* VM is ready for that, if text is UTF-8.
51
* Here we make the work right from the beginning.
52
*/
53
size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
54
size_t n = (size_t)FormatMessageW(
55
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
56
NULL,
57
(DWORD)errnum,
58
0,
59
utf16_OSErrorMsg,
60
(DWORD)maxMsgLength,
61
NULL);
62
if (n > 3) {
63
// Drop final '.', CR, LF
64
if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
65
if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
66
if (utf16_OSErrorMsg[n - 1] == L'.') --n;
67
utf16_OSErrorMsg[n] = L'\0';
68
}
69
return n;
70
}
71
72
#define MESSAGE_LENGTH (256 + 100)
73
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
74
75
static void
76
win32Error(JNIEnv *env, const WCHAR *functionName)
77
{
78
WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
79
WCHAR utf16_javaMessage[MESSAGE_LENGTH];
80
/*Good suggestion about 2-bytes-per-symbol in localized error reports*/
81
char utf8_javaMessage[MESSAGE_LENGTH*2];
82
const int errnum = (int)GetLastError();
83
size_t n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
84
n = (n > 0)
85
? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
86
: swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
87
88
if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
89
n = WideCharToMultiByte(
90
CP_UTF8,
91
0,
92
utf16_javaMessage,
93
(int)n, /*by creation n <= MESSAGE_LENGTH*/
94
utf8_javaMessage,
95
MESSAGE_LENGTH*2,
96
NULL,
97
NULL);
98
99
/*no way to die*/
100
{
101
const char *errorMessage = "Secondary error while OS message extraction";
102
if (n > 0) {
103
utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
104
errorMessage = utf8_javaMessage;
105
}
106
JNU_ThrowIOException(env, errorMessage);
107
}
108
}
109
110
static void
111
closeSafely(HANDLE handle)
112
{
113
if (handle != INVALID_HANDLE_VALUE)
114
CloseHandle(handle);
115
}
116
117
static BOOL hasInheritFlag(HANDLE handle)
118
{
119
DWORD mask;
120
if (GetHandleInformation(handle, &mask)) {
121
return mask & HANDLE_FLAG_INHERIT;
122
}
123
return FALSE;
124
}
125
126
#define HANDLE_STORAGE_SIZE 6
127
#define OFFSET_READ 0
128
#define OFFSET_WRITE 1
129
//long signed version of INVALID_HANDLE_VALUE
130
#define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)
131
#define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
132
133
/* Pipe holder structure */
134
typedef struct _STDHOLDER {
135
HANDLE pipe[2];
136
int offset;
137
} STDHOLDER;
138
139
/* Responsible for correct initialization of the [pHolder] structure
140
(that is used for handles recycling) if needs,
141
and appropriate setup of IOE handle [phStd] for child process based
142
on created pipe or Java handle. */
143
static BOOL initHolder(
144
JNIEnv *env,
145
jlong *pjhandles, /* IN OUT - the handle form Java,
146
that can be a file, console or undefined */
147
STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe
148
handles */
149
HANDLE *phStd /* OUT - initialized handle for child process */
150
) {
151
/* Here we test the value from Java against invalid
152
handle value. We are not using INVALID_HANDLE_VALUE macro
153
due to double signed/unsigned and 32/64bit ambiguity.
154
Otherwise it will be easy to get the wrong
155
value 0x00000000FFFFFFFF
156
instead 0xFFFFFFFFFFFFFFFF. */
157
if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
158
/* Java file or console redirection */
159
*phStd = (HANDLE) *pjhandles;
160
/* Here we set the related Java stream (Process.getXXXXStream())
161
to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
162
The initial Java handle [*pjhandles] will be closed in
163
ANY case. It is not a handle leak. */
164
*pjhandles = JAVA_INVALID_HANDLE_VALUE;
165
} else {
166
/* Creation of parent-child pipe */
167
if (!CreatePipe(
168
&pHolder->pipe[OFFSET_READ],
169
&pHolder->pipe[OFFSET_WRITE],
170
NULL, /* we would like to inherit
171
default process access,
172
instead of 'Everybody' access */
173
PIPE_SIZE))
174
{
175
win32Error(env, L"CreatePipe");
176
return FALSE;
177
} else {
178
/* [thisProcessEnd] has no the inherit flag because
179
the [lpPipeAttributes] param of [CreatePipe]
180
had the NULL value. */
181
HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
182
*phStd = pHolder->pipe[pHolder->offset];
183
*pjhandles = (jlong) thisProcessEnd;
184
}
185
}
186
/* Pipe handle will be closed in the [releaseHolder] call,
187
file handle will be closed in Java.
188
The long-live handle need to restore the inherit flag,
189
we do it later in the [prepareIOEHandleState] call. */
190
SetHandleInformation(
191
*phStd,
192
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
193
return TRUE;
194
}
195
196
/* Smart recycling of pipe handles in [pHolder]. For the failed
197
create process attempts, both ends of pipe need to be released.
198
The [complete] has the [TRUE] value in the failed attempt. */
199
static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
200
closeSafely(pHolder->pipe[pHolder->offset]);
201
if (complete) {
202
/* Error occur, close this process pipe end */
203
closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
204
}
205
}
206
207
/* Stores and drops the inherit flag of handles that should not
208
be shared with the child process by default, but can hold the
209
inherit flag due to MS process birth specific. */
210
static void prepareIOEHandleState(
211
HANDLE *stdIOE,
212
BOOL *inherit)
213
{
214
int i;
215
for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
216
HANDLE hstd = stdIOE[i];
217
if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
218
/* FALSE by default */
219
inherit[i] = TRUE;
220
/* Java does not need implicit inheritance for IOE handles,
221
so we drop inherit flag that probably was installed by
222
previous CreateProcess call that launched current process.
223
We will return the handle state back after CreateProcess call.
224
By clearing inherit flag we prevent "greedy grandchild" birth.
225
The explicit inheritance for child process IOE handles is
226
implemented in the [initHolder] call. */
227
SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
228
}
229
}
230
}
231
232
/* Restores the inheritance flag of handles from stored values. */
233
static void restoreIOEHandleState(
234
const HANDLE *stdIOE,
235
const BOOL *inherit)
236
{
237
/* The set of current process standard IOE handles and
238
the set of child process IOE handles can intersect.
239
To restore the inherit flag right, we use backward
240
array iteration. */
241
int i;
242
for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
243
if (INVALID_HANDLE_VALUE != stdIOE[i]) {
244
/* Restore inherit flag for any case.
245
The handle can be changed by explicit inheritance.*/
246
SetHandleInformation(stdIOE[i],
247
HANDLE_FLAG_INHERIT,
248
inherit[i] ? HANDLE_FLAG_INHERIT : 0);
249
}
250
}
251
252
/*
253
* Class: java_lang_ProcessImpl
254
* Method: getProcessId0
255
* Signature: (J)I
256
*/
257
JNIEXPORT jint JNICALL Java_java_lang_ProcessImpl_getProcessId0
258
(JNIEnv *env, jclass clazz, jlong handle) {
259
DWORD pid = GetProcessId((HANDLE) jlong_to_ptr(handle));
260
return (jint)pid;
261
}
262
263
/* Please, read about the MS inheritance problem
264
http://support.microsoft.com/kb/315939
265
and critical section/synchronized block solution. */
266
static jlong processCreate(
267
JNIEnv *env,
268
const jchar *pcmd,
269
const jchar *penvBlock,
270
const jchar *pdir,
271
jlong *handles,
272
jboolean redirectErrorStream)
273
{
274
jlong ret = 0L;
275
STARTUPINFOW si = {sizeof(si)};
276
277
/* Handles for which the inheritance flag must be restored. */
278
HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
279
/* Current process standard IOE handles: JDK-7147084 */
280
INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
281
/* Child process IOE handles: JDK-6921885 */
282
(HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
283
BOOL inherit[HANDLE_STORAGE_SIZE] = {
284
FALSE, FALSE, FALSE,
285
FALSE, FALSE, FALSE};
286
287
/* These three should not be closed by CloseHandle! */
288
stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE);
289
stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE);
290
stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE);
291
292
prepareIOEHandleState(stdIOE, inherit);
293
{
294
/* Input */
295
STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
296
if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {
297
298
/* Output */
299
STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
300
if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {
301
302
/* Error */
303
STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
304
BOOL success;
305
if (redirectErrorStream) {
306
si.hStdError = si.hStdOutput;
307
/* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]
308
value. That is in accordance with Java Doc for the redirection case.
309
The Java file for the [ handles[2] ] will be closed in ANY case. It is not
310
a handle leak. */
311
handles[2] = JAVA_INVALID_HANDLE_VALUE;
312
success = TRUE;
313
} else {
314
success = initHolder(env, &handles[2], &holderErr, &si.hStdError);
315
}
316
317
if (success) {
318
PROCESS_INFORMATION pi;
319
DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
320
321
/* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */
322
if (GetConsoleWindow() != NULL &&
323
(si.hStdInput == stdIOE[0] ||
324
si.hStdOutput == stdIOE[1] ||
325
si.hStdError == (redirectErrorStream ? stdIOE[1] : stdIOE[2])))
326
{
327
processFlag &= ~CREATE_NO_WINDOW;
328
}
329
330
si.dwFlags = STARTF_USESTDHANDLES;
331
if (!CreateProcessW(
332
NULL, /* executable name */
333
(LPWSTR)pcmd, /* command line */
334
NULL, /* process security attribute */
335
NULL, /* thread security attribute */
336
TRUE, /* inherits system handles */
337
processFlag, /* selected based on exe type */
338
(LPVOID)penvBlock,/* environment block */
339
(LPCWSTR)pdir, /* change to the new current directory */
340
&si, /* (in) startup information */
341
&pi)) /* (out) process information */
342
{
343
win32Error(env, L"CreateProcess");
344
} else {
345
closeSafely(pi.hThread);
346
ret = (jlong)pi.hProcess;
347
}
348
}
349
releaseHolder(ret == 0, &holderErr);
350
releaseHolder(ret == 0, &holderOut);
351
}
352
releaseHolder(ret == 0, &holderIn);
353
}
354
}
355
restoreIOEHandleState(stdIOE, inherit);
356
357
return ret;
358
}
359
360
JNIEXPORT jlong JNICALL
361
Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
362
jstring cmd,
363
jstring envBlock,
364
jstring dir,
365
jlongArray stdHandles,
366
jboolean redirectErrorStream)
367
{
368
jlong ret = 0;
369
if (cmd != NULL && stdHandles != NULL) {
370
const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
371
if (pcmd != NULL) {
372
const jchar *penvBlock = (envBlock != NULL)
373
? (*env)->GetStringChars(env, envBlock, NULL)
374
: NULL;
375
if (!(*env)->ExceptionCheck(env)) {
376
const jchar *pdir = (dir != NULL)
377
? (*env)->GetStringChars(env, dir, NULL)
378
: NULL;
379
if (!(*env)->ExceptionCheck(env)) {
380
jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
381
if (handles != NULL) {
382
ret = processCreate(
383
env,
384
pcmd,
385
penvBlock,
386
pdir,
387
handles,
388
redirectErrorStream);
389
(*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
390
}
391
if (pdir != NULL)
392
(*env)->ReleaseStringChars(env, dir, pdir);
393
}
394
if (penvBlock != NULL)
395
(*env)->ReleaseStringChars(env, envBlock, penvBlock);
396
}
397
(*env)->ReleaseStringChars(env, cmd, pcmd);
398
}
399
}
400
return ret;
401
}
402
403
JNIEXPORT jint JNICALL
404
Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
405
{
406
DWORD exit_code;
407
if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
408
win32Error(env, L"GetExitCodeProcess");
409
return exit_code;
410
}
411
412
JNIEXPORT jint JNICALL
413
Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
414
{
415
return STILL_ACTIVE;
416
}
417
418
JNIEXPORT void JNICALL
419
Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
420
{
421
HANDLE events[2];
422
events[0] = (HANDLE) handle;
423
events[1] = JVM_GetThreadInterruptEvent();
424
425
if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
426
FALSE, /* Wait for ANY event */
427
INFINITE) /* Wait forever */
428
== WAIT_FAILED)
429
win32Error(env, L"WaitForMultipleObjects");
430
}
431
432
JNIEXPORT void JNICALL
433
Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
434
jclass ignored,
435
jlong handle,
436
jlong timeoutMillis)
437
{
438
HANDLE events[2];
439
DWORD dwTimeout = (DWORD)timeoutMillis;
440
DWORD result;
441
events[0] = (HANDLE) handle;
442
events[1] = JVM_GetThreadInterruptEvent();
443
result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
444
FALSE, /* Wait for ANY event */
445
dwTimeout); /* Wait for dwTimeout */
446
447
if (result == WAIT_FAILED)
448
win32Error(env, L"WaitForMultipleObjects");
449
}
450
451
JNIEXPORT void JNICALL
452
Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
453
{
454
TerminateProcess((HANDLE) handle, 1);
455
}
456
457
JNIEXPORT jboolean JNICALL
458
Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
459
{
460
DWORD dwExitStatus;
461
GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
462
return dwExitStatus == STILL_ACTIVE;
463
}
464
465
JNIEXPORT jboolean JNICALL
466
Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
467
{
468
return (jboolean) CloseHandle((HANDLE) handle);
469
}
470
471
JNIEXPORT jlong JNICALL
472
Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
473
{
474
const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
475
const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
476
const DWORD disposition = OPEN_ALWAYS;
477
const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
478
HANDLE h;
479
WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
480
if (pathbuf == NULL) {
481
/* Exception already pending */
482
return -1;
483
}
484
h = CreateFileW(
485
pathbuf, /* Wide char path name */
486
access, /* Read and/or write permission */
487
sharing, /* File sharing flags */
488
NULL, /* Security attributes */
489
disposition, /* creation disposition */
490
flagsAndAttributes, /* flags and attributes */
491
NULL);
492
free(pathbuf);
493
if (h == INVALID_HANDLE_VALUE) {
494
JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
495
}
496
return ptr_to_jlong(h);
497
}
498
499