jdk

Форк
0
1063 строки · 32.0 Кб
1
/*
2
 * Copyright (c) 1997, 2024, 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 <windows.h>
27
#include <io.h>
28
#include <process.h>
29
#include <stdlib.h>
30
#include <stdio.h>
31
#include <stdarg.h>
32
#include <string.h>
33
#include <sys/types.h>
34
#include <sys/stat.h>
35
#include <wtypes.h>
36
#include <commctrl.h>
37
#include <assert.h>
38

39
#include <jni.h>
40
#include "java.h"
41

42
#define JVM_DLL "jvm.dll"
43
#define JAVA_DLL "java.dll"
44

45
/*
46
 * Prototypes.
47
 */
48
static jboolean GetJVMPath(const char *jrepath, const char *jvmtype,
49
                           char *jvmpath, jint jvmpathsize);
50
static jboolean GetJREPath(char *path, jint pathsize);
51

52
/* We supports warmup for UI stack that is performed in parallel
53
 * to VM initialization.
54
 * This helps to improve startup of UI application as warmup phase
55
 * might be long due to initialization of OS or hardware resources.
56
 * It is not CPU bound and therefore it does not interfere with VM init.
57
 * Obviously such warmup only has sense for UI apps and therefore it needs
58
 * to be explicitly requested by passing -Dsun.awt.warmup=true property
59
 * (this is always the case for plugin/javaws).
60
 *
61
 * Implementation launches new thread after VM starts and use it to perform
62
 * warmup code (platform dependent).
63
 * This thread is later reused as AWT toolkit thread as graphics toolkit
64
 * often assume that they are used from the same thread they were launched on.
65
 *
66
 * At the moment we only support warmup for D3D. It only possible on windows
67
 * and only if other flags do not prohibit this (e.g. OpenGL support requested).
68
 */
69
#undef ENABLE_AWT_PRELOAD
70
#ifndef JAVA_ARGS /* turn off AWT preloading for javac, jar, etc */
71
    /* CR6999872: fastdebug crashes if awt library is loaded before JVM is
72
     * initialized*/
73
    #if !defined(DEBUG)
74
        #define ENABLE_AWT_PRELOAD
75
    #endif
76
#endif
77

78
#ifdef ENABLE_AWT_PRELOAD
79
/* "AWT was preloaded" flag;
80
 * turned on by AWTPreload().
81
 */
82
int awtPreloaded = 0;
83

84
/* Calls a function with the name specified
85
 * the function must be int(*fn)(void).
86
 */
87
int AWTPreload(const char *funcName);
88
/* stops AWT preloading */
89
void AWTPreloadStop();
90

91
/* D3D preloading */
92
/* -1: not initialized; 0: OFF, 1: ON */
93
int awtPreloadD3D = -1;
94
/* command line parameter to switch D3D preloading on */
95
#define PARAM_PRELOAD_D3D "-Dsun.awt.warmup"
96
/* D3D/OpenGL management parameters */
97
#define PARAM_NODDRAW "-Dsun.java2d.noddraw"
98
#define PARAM_D3D "-Dsun.java2d.d3d"
99
#define PARAM_OPENGL "-Dsun.java2d.opengl"
100
/* function in awt.dll (src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp) */
101
#define D3D_PRELOAD_FUNC "preloadD3D"
102

103
/* Extracts value of a parameter with the specified name
104
 * from command line argument (returns pointer in the argument).
105
 * Returns NULL if the argument does not contains the parameter.
106
 * e.g.:
107
 * GetParamValue("theParam", "theParam=value") returns pointer to "value".
108
 */
109
const char * GetParamValue(const char *paramName, const char *arg) {
110
    size_t nameLen = JLI_StrLen(paramName);
111
    if (JLI_StrNCmp(paramName, arg, nameLen) == 0) {
112
        /* arg[nameLen] is valid (may contain final NULL) */
113
        if (arg[nameLen] == '=') {
114
            return arg + nameLen + 1;
115
        }
116
    }
117
    return NULL;
118
}
119

120
/* Checks if commandline argument contains property specified
121
 * and analyze it as boolean property (true/false).
122
 * Returns -1 if the argument does not contain the parameter;
123
 * Returns 1 if the argument contains the parameter and its value is "true";
124
 * Returns 0 if the argument contains the parameter and its value is "false".
125
 */
126
int GetBoolParamValue(const char *paramName, const char *arg) {
127
    const char * paramValue = GetParamValue(paramName, arg);
128
    if (paramValue != NULL) {
129
        if (JLI_StrCaseCmp(paramValue, "true") == 0) {
130
            return 1;
131
        }
132
        if (JLI_StrCaseCmp(paramValue, "false") == 0) {
133
            return 0;
134
        }
135
    }
136
    return -1;
137
}
138
#endif /* ENABLE_AWT_PRELOAD */
139

140

141
static jboolean _isjavaw = JNI_FALSE;
142

143

144
jboolean
145
IsJavaw()
146
{
147
    return _isjavaw;
148
}
149

150
/*
151
 *
152
 */
153
void
154
CreateExecutionEnvironment(int *pargc, char ***pargv,
155
                           char *jrepath, jint so_jrepath,
156
                           char *jvmpath, jint so_jvmpath,
157
                           char *jvmcfg,  jint so_jvmcfg) {
158

159
    char *jvmtype;
160
    int i = 0;
161
    char** argv = *pargv;
162

163
    /* Find out where the JRE is that we will be using. */
164
    if (!GetJREPath(jrepath, so_jrepath)) {
165
        JLI_ReportErrorMessage(JRE_ERROR1);
166
        exit(2);
167
    }
168

169
    JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
170
        jrepath, FILESEP, FILESEP);
171

172
    /* Find the specified JVM type */
173
    if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
174
        JLI_ReportErrorMessage(CFG_ERROR7);
175
        exit(1);
176
    }
177

178
    jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
179
    if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
180
        JLI_ReportErrorMessage(CFG_ERROR9);
181
        exit(4);
182
    }
183

184
    jvmpath[0] = '\0';
185
    if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {
186
        JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
187
        exit(4);
188
    }
189
    /* If we got here, jvmpath has been correctly initialized. */
190

191
    /* Check if we need preload AWT */
192
#ifdef ENABLE_AWT_PRELOAD
193
    argv = *pargv;
194
    for (i = 0; i < *pargc ; i++) {
195
        /* Tests the "turn on" parameter only if not set yet. */
196
        if (awtPreloadD3D < 0) {
197
            if (GetBoolParamValue(PARAM_PRELOAD_D3D, argv[i]) == 1) {
198
                awtPreloadD3D = 1;
199
            }
200
        }
201
        /* Test parameters which can disable preloading if not already disabled. */
202
        if (awtPreloadD3D != 0) {
203
            if (GetBoolParamValue(PARAM_NODDRAW, argv[i]) == 1
204
                || GetBoolParamValue(PARAM_D3D, argv[i]) == 0
205
                || GetBoolParamValue(PARAM_OPENGL, argv[i]) == 1)
206
            {
207
                awtPreloadD3D = 0;
208
                /* no need to test the rest of the parameters */
209
                break;
210
            }
211
        }
212
    }
213
#endif /* ENABLE_AWT_PRELOAD */
214
}
215

216

217
static jboolean
218
LoadMSVCRT()
219
{
220
    // Only do this once
221
    static int loaded = 0;
222
    char crtpath[MAXPATHLEN];
223

224
    if (!loaded) {
225
        /*
226
         * The Microsoft C Runtime Library needs to be loaded first.  A copy is
227
         * assumed to be present in the "JRE path" directory.  If it is not found
228
         * there (or "JRE path" fails to resolve), skip the explicit load and let
229
         * nature take its course, which is likely to be a failure to execute.
230
         * The makefiles will provide the correct lib contained in quotes in the
231
         * macro MSVCR_DLL_NAME.
232
         */
233
#ifdef MSVCR_DLL_NAME
234
        if (GetJREPath(crtpath, MAXPATHLEN)) {
235
            if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") +
236
                    JLI_StrLen(MSVCR_DLL_NAME) >= MAXPATHLEN) {
237
                JLI_ReportErrorMessage(JRE_ERROR11);
238
                return JNI_FALSE;
239
            }
240
            (void)JLI_StrCat(crtpath, "\\bin\\" MSVCR_DLL_NAME);   /* Add crt dll */
241
            JLI_TraceLauncher("CRT path is %s\n", crtpath);
242
            if (_access(crtpath, 0) == 0) {
243
                if (LoadLibrary(crtpath) == 0) {
244
                    JLI_ReportErrorMessage(DLL_ERROR4, crtpath);
245
                    return JNI_FALSE;
246
                }
247
            }
248
        }
249
#endif /* MSVCR_DLL_NAME */
250
#ifdef VCRUNTIME_1_DLL_NAME
251
        if (GetJREPath(crtpath, MAXPATHLEN)) {
252
            if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") +
253
                    JLI_StrLen(VCRUNTIME_1_DLL_NAME) >= MAXPATHLEN) {
254
                JLI_ReportErrorMessage(JRE_ERROR11);
255
                return JNI_FALSE;
256
            }
257
            (void)JLI_StrCat(crtpath, "\\bin\\" VCRUNTIME_1_DLL_NAME);   /* Add crt dll */
258
            JLI_TraceLauncher("CRT path is %s\n", crtpath);
259
            if (_access(crtpath, 0) == 0) {
260
                if (LoadLibrary(crtpath) == 0) {
261
                    JLI_ReportErrorMessage(DLL_ERROR4, crtpath);
262
                    return JNI_FALSE;
263
                }
264
            }
265
        }
266
#endif /* VCRUNTIME_1_DLL_NAME */
267
#ifdef MSVCP_DLL_NAME
268
        if (GetJREPath(crtpath, MAXPATHLEN)) {
269
            if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") +
270
                    JLI_StrLen(MSVCP_DLL_NAME) >= MAXPATHLEN) {
271
                JLI_ReportErrorMessage(JRE_ERROR11);
272
                return JNI_FALSE;
273
            }
274
            (void)JLI_StrCat(crtpath, "\\bin\\" MSVCP_DLL_NAME);   /* Add prt dll */
275
            JLI_TraceLauncher("PRT path is %s\n", crtpath);
276
            if (_access(crtpath, 0) == 0) {
277
                if (LoadLibrary(crtpath) == 0) {
278
                    JLI_ReportErrorMessage(DLL_ERROR4, crtpath);
279
                    return JNI_FALSE;
280
                }
281
            }
282
        }
283
#endif /* MSVCP_DLL_NAME */
284
        loaded = 1;
285
    }
286
    return JNI_TRUE;
287
}
288

289

290
/*
291
 * Find path to JRE based on .exe's location or registry settings.
292
 */
293
jboolean
294
GetJREPath(char *path, jint pathsize)
295
{
296
    char javadll[MAXPATHLEN];
297
    struct stat s;
298

299
    JLI_TraceLauncher("Attempt to get JRE path from launcher executable path\n");
300

301
    if (GetApplicationHome(path, pathsize)) {
302
        /* Is JRE co-located with the application? */
303
        JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path);
304
        if (stat(javadll, &s) == 0) {
305
            JLI_TraceLauncher("JRE path is %s\n", path);
306
            return JNI_TRUE;
307
        }
308
    }
309

310
    JLI_TraceLauncher("Attempt to get JRE path from shared lib of the image\n");
311

312
    /* Try getting path to JRE from path to JLI.DLL */
313
    if (GetApplicationHomeFromDll(path, pathsize)) {
314
        JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path);
315
        if (stat(javadll, &s) == 0) {
316
            JLI_TraceLauncher("JRE path is %s\n", path);
317
            return JNI_TRUE;
318
        }
319
    }
320

321
    JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
322
    return JNI_FALSE;
323
}
324

325
/*
326
 * Given a JRE location and a JVM type, construct what the name the
327
 * JVM shared library will be.  Return true, if such a library
328
 * exists, false otherwise.
329
 */
330
static jboolean
331
GetJVMPath(const char *jrepath, const char *jvmtype,
332
           char *jvmpath, jint jvmpathsize)
333
{
334
    struct stat s;
335
    if (JLI_StrChr(jvmtype, '/') || JLI_StrChr(jvmtype, '\\')) {
336
        JLI_Snprintf(jvmpath, jvmpathsize, "%s\\" JVM_DLL, jvmtype);
337
    } else {
338
        JLI_Snprintf(jvmpath, jvmpathsize, "%s\\bin\\%s\\" JVM_DLL,
339
                     jrepath, jvmtype);
340
    }
341
    if (stat(jvmpath, &s) == 0) {
342
        return JNI_TRUE;
343
    } else {
344
        return JNI_FALSE;
345
    }
346
}
347

348
/*
349
 * Load a jvm from "jvmpath" and initialize the invocation functions.
350
 */
351
jboolean
352
LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
353
{
354
    HINSTANCE handle;
355

356
    JLI_TraceLauncher("JVM path is %s\n", jvmpath);
357

358
    /*
359
     * The Microsoft C Runtime Library needs to be loaded first.  A copy is
360
     * assumed to be present in the "JRE path" directory.  If it is not found
361
     * there (or "JRE path" fails to resolve), skip the explicit load and let
362
     * nature take its course, which is likely to be a failure to execute.
363
     *
364
     */
365
    LoadMSVCRT();
366

367
    /* Load the Java VM DLL */
368
    if ((handle = LoadLibrary(jvmpath)) == 0) {
369
        JLI_ReportErrorMessage(DLL_ERROR4, (char *)jvmpath);
370
        return JNI_FALSE;
371
    }
372

373
    /* Now get the function addresses */
374
    ifn->CreateJavaVM =
375
        (void *)GetProcAddress(handle, "JNI_CreateJavaVM");
376
    ifn->GetDefaultJavaVMInitArgs =
377
        (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs");
378
    if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) {
379
        JLI_ReportErrorMessage(JNI_ERROR1, (char *)jvmpath);
380
        return JNI_FALSE;
381
    }
382

383
    return JNI_TRUE;
384
}
385

386
/*
387
 * Removes the trailing file name and one sub-folder from a path.
388
 * If buf is "c:\foo\bin\javac", then put "c:\foo" into buf.
389
 */
390
jboolean
391
TruncatePath(char *buf)
392
{
393
    char *cp;
394
    *JLI_StrRChr(buf, '\\') = '\0'; /* remove .exe file name */
395
    if ((cp = JLI_StrRChr(buf, '\\')) == 0) {
396
        /* This happens if the application is in a drive root, and
397
         * there is no bin directory. */
398
        buf[0] = '\0';
399
        return JNI_FALSE;
400
    }
401
    *cp = '\0'; /* remove the bin\ part */
402
    return JNI_TRUE;
403
}
404

405
/*
406
 * Retrieves the path to the JRE home by locating the executable file
407
 * of the current process and then truncating the path to the executable
408
 */
409
jboolean
410
GetApplicationHome(char *buf, jint bufsize)
411
{
412
    GetModuleFileName(NULL, buf, bufsize);
413
    return TruncatePath(buf);
414
}
415

416
/*
417
 * Retrieves the path to the JRE home by locating JLI.DLL and
418
 * then truncating the path to JLI.DLL
419
 */
420
jboolean
421
GetApplicationHomeFromDll(char *buf, jint bufsize)
422
{
423
    HMODULE module;
424
    DWORD flags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
425
                  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
426

427
    if (GetModuleHandleEx(flags, (LPCSTR)&GetJREPath, &module) != 0) {
428
        if (GetModuleFileName(module, buf, bufsize) != 0) {
429
            return TruncatePath(buf);
430
        }
431
    }
432
    return JNI_FALSE;
433
}
434

435
/*
436
 * Support for doing cheap, accurate interval timing.
437
 */
438
static jboolean counterAvailable = JNI_FALSE;
439
static jboolean counterInitialized = JNI_FALSE;
440
static LARGE_INTEGER counterFrequency;
441

442
jlong CurrentTimeMicros()
443
{
444
    LARGE_INTEGER count;
445

446
    if (!counterInitialized) {
447
        counterAvailable = QueryPerformanceFrequency(&counterFrequency);
448
        counterInitialized = JNI_TRUE;
449
    }
450
    if (!counterAvailable) {
451
        return 0;
452
    }
453
    QueryPerformanceCounter(&count);
454

455
    return (jlong)(count.QuadPart * 1000 * 1000 / counterFrequency.QuadPart);
456
}
457

458
static errno_t convert_to_unicode(const char* path, const wchar_t* prefix, wchar_t** wpath) {
459
    int unicode_path_len;
460
    size_t prefix_len, wpath_len;
461

462
    /*
463
     * Get required buffer size to convert to Unicode.
464
     * The return value includes the terminating null character.
465
     */
466
    unicode_path_len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
467
                                           path, -1, NULL, 0);
468
    if (unicode_path_len == 0) {
469
        return EINVAL;
470
    }
471

472
    prefix_len = wcslen(prefix);
473
    wpath_len = prefix_len + unicode_path_len;
474
    *wpath = (wchar_t*)JLI_MemAlloc(wpath_len * sizeof(wchar_t));
475
    if (*wpath == NULL) {
476
        return ENOMEM;
477
    }
478

479
    wcsncpy(*wpath, prefix, prefix_len);
480
    if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
481
                            path, -1, &((*wpath)[prefix_len]), (int)wpath_len) == 0) {
482
        JLI_MemFree(*wpath);
483
        *wpath = NULL;
484
        return EINVAL;
485
    }
486

487
    return ERROR_SUCCESS;
488
}
489

490
/* taken from hotspot and slightly adjusted for jli lib;
491
 * creates a UNC/ELP path from input 'path'
492
 * the return buffer is allocated in C heap and needs to be freed using
493
 * JLI_MemFree by the caller.
494
 */
495
static wchar_t* create_unc_path(const char* path, errno_t* err) {
496
    wchar_t* wpath = NULL;
497
    if (path[0] == '\\' && path[1] == '\\') {
498
        if (path[2] == '?' && path[3] == '\\') {
499
            /* if it already has a \\?\ don't do the prefix */
500
            *err = convert_to_unicode(path, L"", &wpath);
501
        } else {
502
            /* only UNC pathname includes double slashes here */
503
            *err = convert_to_unicode(path, L"\\\\?\\UNC", &wpath);
504
        }
505
    } else {
506
        *err = convert_to_unicode(path, L"\\\\?\\", &wpath);
507
    }
508
    return wpath;
509
}
510

511
int JLI_Open(const char* name, int flags) {
512
    int fd;
513
    if (strlen(name) < MAX_PATH) {
514
        fd = _open(name, flags);
515
    } else {
516
        errno_t err = ERROR_SUCCESS;
517
        wchar_t* wpath = create_unc_path(name, &err);
518
        if (err != ERROR_SUCCESS) {
519
            if (wpath != NULL) JLI_MemFree(wpath);
520
            errno = err;
521
            return -1;
522
        }
523
        fd = _wopen(wpath, flags);
524
        if (fd == -1) {
525
            errno = GetLastError();
526
        }
527
        JLI_MemFree(wpath);
528
    }
529
    return fd;
530
}
531

532
JNIEXPORT void JNICALL
533
JLI_ReportErrorMessage(const char* fmt, ...) {
534
    va_list vl;
535
    va_start(vl,fmt);
536

537
    if (IsJavaw()) {
538
        char *message;
539

540
        /* get the length of the string we need */
541
        int n = _vscprintf(fmt, vl);
542

543
        message = (char *)JLI_MemAlloc(n + 1);
544
        _vsnprintf(message, n, fmt, vl);
545
        message[n]='\0';
546
        MessageBox(NULL, message, "Java Virtual Machine Launcher",
547
            (MB_OK|MB_ICONSTOP|MB_APPLMODAL));
548
        JLI_MemFree(message);
549
    } else {
550
        vfprintf(stderr, fmt, vl);
551
        fprintf(stderr, "\n");
552
    }
553
    va_end(vl);
554
}
555

556
/*
557
 * Just like JLI_ReportErrorMessage, except that it concatenates the system
558
 * error message if any, it's up to the calling routine to correctly
559
 * format the separation of the messages.
560
 */
561
JNIEXPORT void JNICALL
562
JLI_ReportErrorMessageSys(const char *fmt, ...)
563
{
564
    va_list vl;
565

566
    int save_errno = errno;
567
    DWORD       errval;
568
    jboolean freeit = JNI_FALSE;
569
    char  *errtext = NULL;
570

571
    va_start(vl, fmt);
572

573
    if ((errval = GetLastError()) != 0) {               /* Platform SDK / DOS Error */
574
        int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|
575
            FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER,
576
            NULL, errval, 0, (LPTSTR)&errtext, 0, NULL);
577
        if (errtext == NULL || n == 0) {                /* Paranoia check */
578
            errtext = "";
579
            n = 0;
580
        } else {
581
            freeit = JNI_TRUE;
582
            if (n > 2) {                                /* Drop final CR, LF */
583
                if (errtext[n - 1] == '\n') n--;
584
                if (errtext[n - 1] == '\r') n--;
585
                errtext[n] = '\0';
586
            }
587
        }
588
    } else {   /* C runtime error that has no corresponding DOS error code */
589
        errtext = strerror(save_errno);
590
    }
591

592
    if (IsJavaw()) {
593
        char *message;
594
        int mlen;
595
        /* get the length of the string we need */
596
        int len = mlen =  _vscprintf(fmt, vl) + 1;
597
        if (freeit) {
598
           mlen += (int)JLI_StrLen(errtext);
599
        }
600

601
        message = (char *)JLI_MemAlloc(mlen);
602
        _vsnprintf(message, len, fmt, vl);
603
        message[len]='\0';
604

605
        if (freeit) {
606
           JLI_StrCat(message, errtext);
607
        }
608

609
        MessageBox(NULL, message, "Java Virtual Machine Launcher",
610
            (MB_OK|MB_ICONSTOP|MB_APPLMODAL));
611

612
        JLI_MemFree(message);
613
    } else {
614
        vfprintf(stderr, fmt, vl);
615
        if (freeit) {
616
           fprintf(stderr, "%s", errtext);
617
        }
618
    }
619
    if (freeit) {
620
        (void)LocalFree((HLOCAL)errtext);
621
    }
622
    va_end(vl);
623
}
624

625
JNIEXPORT void JNICALL
626
JLI_ReportExceptionDescription(JNIEnv * env) {
627
    if (IsJavaw()) {
628
       /*
629
        * This code should be replaced by code which opens a window with
630
        * the exception detail message, for now at least put a dialog up.
631
        */
632
        MessageBox(NULL, "A Java Exception has occurred.", "Java Virtual Machine Launcher",
633
               (MB_OK|MB_ICONSTOP|MB_APPLMODAL));
634
    } else {
635
        (*env)->ExceptionDescribe(env);
636
    }
637
}
638

639
/*
640
 * Wrapper for platform dependent unsetenv function.
641
 */
642
int
643
UnsetEnv(char *name)
644
{
645
    int ret;
646
    char *buf = JLI_MemAlloc(JLI_StrLen(name) + 2);
647
    buf = JLI_StrCat(JLI_StrCpy(buf, name), "=");
648
    ret = _putenv(buf);
649
    JLI_MemFree(buf);
650
    return (ret);
651
}
652

653
/* --- Splash Screen shared library support --- */
654

655
static const char* SPLASHSCREEN_SO = "\\bin\\splashscreen.dll";
656

657
static HMODULE hSplashLib = NULL;
658

659
void* SplashProcAddress(const char* name) {
660
    char libraryPath[MAXPATHLEN]; /* some extra space for JLI_StrCat'ing SPLASHSCREEN_SO */
661

662
    if (!GetJREPath(libraryPath, MAXPATHLEN)) {
663
        return NULL;
664
    }
665
    if (JLI_StrLen(libraryPath)+JLI_StrLen(SPLASHSCREEN_SO) >= MAXPATHLEN) {
666
        return NULL;
667
    }
668
    JLI_StrCat(libraryPath, SPLASHSCREEN_SO);
669

670
    if (!hSplashLib) {
671
        hSplashLib = LoadLibrary(libraryPath);
672
    }
673
    if (hSplashLib) {
674
        return GetProcAddress(hSplashLib, name);
675
    } else {
676
        return NULL;
677
    }
678
}
679

680
/*
681
 * Signature adapter for _beginthreadex().
682
 */
683
static unsigned __stdcall ThreadJavaMain(void* args) {
684
    return (unsigned)JavaMain(args);
685
}
686

687
/*
688
 * Block current thread and continue execution in a new thread.
689
 */
690
int
691
CallJavaMainInNewThread(jlong stack_size, void* args) {
692
    int rslt = 0;
693
    unsigned thread_id;
694

695
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
696
#define STACK_SIZE_PARAM_IS_A_RESERVATION  (0x10000)
697
#endif
698

699
    /*
700
     * STACK_SIZE_PARAM_IS_A_RESERVATION is what we want, but it's not
701
     * supported on older version of Windows. Try first with the flag; and
702
     * if that fails try again without the flag. See MSDN document or HotSpot
703
     * source (os_win32.cpp) for details.
704
     */
705
    HANDLE thread_handle =
706
        (HANDLE)_beginthreadex(NULL,
707
                               (unsigned)stack_size,
708
                               ThreadJavaMain,
709
                               args,
710
                               STACK_SIZE_PARAM_IS_A_RESERVATION,
711
                               &thread_id);
712
    if (thread_handle == NULL) {
713
        thread_handle =
714
        (HANDLE)_beginthreadex(NULL,
715
                               (unsigned)stack_size,
716
                               ThreadJavaMain,
717
                               args,
718
                               0,
719
                               &thread_id);
720
    }
721

722
    /* AWT preloading (AFTER main thread start) */
723
#ifdef ENABLE_AWT_PRELOAD
724
    /* D3D preloading */
725
    if (awtPreloadD3D != 0) {
726
        char *envValue;
727
        /* D3D routines checks env.var J2D_D3D if no appropriate
728
         * command line params was specified
729
         */
730
        envValue = getenv("J2D_D3D");
731
        if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) {
732
            awtPreloadD3D = 0;
733
        }
734
        /* Test that AWT preloading isn't disabled by J2D_D3D_PRELOAD env.var */
735
        envValue = getenv("J2D_D3D_PRELOAD");
736
        if (envValue != NULL && JLI_StrCaseCmp(envValue, "false") == 0) {
737
            awtPreloadD3D = 0;
738
        }
739
        if (awtPreloadD3D < 0) {
740
            /* If awtPreloadD3D is still undefined (-1), test
741
             * if it is turned on by J2D_D3D_PRELOAD env.var.
742
             * By default it's turned OFF.
743
             */
744
            awtPreloadD3D = 0;
745
            if (envValue != NULL && JLI_StrCaseCmp(envValue, "true") == 0) {
746
                awtPreloadD3D = 1;
747
            }
748
         }
749
    }
750
    if (awtPreloadD3D) {
751
        AWTPreload(D3D_PRELOAD_FUNC);
752
    }
753
#endif /* ENABLE_AWT_PRELOAD */
754

755
    if (thread_handle) {
756
        WaitForSingleObject(thread_handle, INFINITE);
757
        GetExitCodeThread(thread_handle, &rslt);
758
        CloseHandle(thread_handle);
759
    } else {
760
        rslt = JavaMain(args);
761
    }
762

763
#ifdef ENABLE_AWT_PRELOAD
764
    if (awtPreloaded) {
765
        AWTPreloadStop();
766
    }
767
#endif /* ENABLE_AWT_PRELOAD */
768

769
    return rslt;
770
}
771

772
/*
773
 * The implementation for finding classes from the bootstrap
774
 * class loader, refer to java.h
775
 */
776
static FindClassFromBootLoader_t *findBootClass = NULL;
777

778
jclass FindBootStrapClass(JNIEnv *env, const char *classname)
779
{
780
   HMODULE hJvm;
781

782
   if (findBootClass == NULL) {
783
       hJvm = GetModuleHandle(JVM_DLL);
784
       if (hJvm == NULL) return NULL;
785
       /* need to use the demangled entry point */
786
       findBootClass = (FindClassFromBootLoader_t *)GetProcAddress(hJvm,
787
            "JVM_FindClassFromBootLoader");
788
       if (findBootClass == NULL) {
789
          JLI_ReportErrorMessage(DLL_ERROR4, "JVM_FindClassFromBootLoader");
790
          return NULL;
791
       }
792
   }
793
   return findBootClass(env, classname);
794
}
795

796
void
797
InitLauncher(jboolean javaw)
798
{
799
    INITCOMMONCONTROLSEX icx;
800

801
    /*
802
     * Required for javaw mode MessageBox output as well as for
803
     * HotSpot -XX:+ShowMessageBoxOnError in java mode, an empty
804
     * flag field is sufficient to perform the basic UI initialization.
805
     */
806
    memset(&icx, 0, sizeof(INITCOMMONCONTROLSEX));
807
    icx.dwSize = sizeof(INITCOMMONCONTROLSEX);
808
    InitCommonControlsEx(&icx);
809
    _isjavaw = javaw;
810
    JLI_SetTraceLauncher();
811
}
812

813

814
/* ============================== */
815
/* AWT preloading */
816
#ifdef ENABLE_AWT_PRELOAD
817

818
typedef int FnPreloadStart(void);
819
typedef void FnPreloadStop(void);
820
static FnPreloadStop *fnPreloadStop = NULL;
821
static HMODULE hPreloadAwt = NULL;
822

823
/*
824
 * Starts AWT preloading
825
 */
826
int AWTPreload(const char *funcName)
827
{
828
    int result = -1;
829
    /* load AWT library once (if several preload function should be called) */
830
    if (hPreloadAwt == NULL) {
831
        /* awt.dll is not loaded yet */
832
        char libraryPath[MAXPATHLEN];
833
        size_t jrePathLen = 0;
834
        HMODULE hJava = NULL;
835
        HMODULE hVerify = NULL;
836

837
        while (1) {
838
            /* awt.dll depends on jvm.dll & java.dll;
839
             * jvm.dll is already loaded, so we need only java.dll;
840
             * java.dll depends on MSVCRT lib & verify.dll.
841
             */
842
            if (!GetJREPath(libraryPath, MAXPATHLEN)) {
843
                break;
844
            }
845

846
            /* save path length */
847
            jrePathLen = JLI_StrLen(libraryPath);
848

849
            if (jrePathLen + JLI_StrLen("\\bin\\verify.dll") >= MAXPATHLEN) {
850
              /* jre path is too long, the library path will not fit there;
851
               * report and abort preloading
852
               */
853
              JLI_ReportErrorMessage(JRE_ERROR11);
854
              break;
855
            }
856

857
            /* load msvcrt 1st */
858
            LoadMSVCRT();
859

860
            /* load verify.dll */
861
            JLI_StrCat(libraryPath, "\\bin\\verify.dll");
862
            hVerify = LoadLibrary(libraryPath);
863
            if (hVerify == NULL) {
864
                break;
865
            }
866

867
            /* restore jrePath */
868
            libraryPath[jrePathLen] = 0;
869
            /* load java.dll */
870
            JLI_StrCat(libraryPath, "\\bin\\" JAVA_DLL);
871
            hJava = LoadLibrary(libraryPath);
872
            if (hJava == NULL) {
873
                break;
874
            }
875

876
            /* restore jrePath */
877
            libraryPath[jrePathLen] = 0;
878
            /* load awt.dll */
879
            JLI_StrCat(libraryPath, "\\bin\\awt.dll");
880
            hPreloadAwt = LoadLibrary(libraryPath);
881
            if (hPreloadAwt == NULL) {
882
                break;
883
            }
884

885
            /* get "preloadStop" func ptr */
886
            fnPreloadStop = (FnPreloadStop *)GetProcAddress(hPreloadAwt, "preloadStop");
887

888
            break;
889
        }
890
    }
891

892
    if (hPreloadAwt != NULL) {
893
        FnPreloadStart *fnInit = (FnPreloadStart *)GetProcAddress(hPreloadAwt, funcName);
894
        if (fnInit != NULL) {
895
            /* don't forget to stop preloading */
896
            awtPreloaded = 1;
897

898
            result = fnInit();
899
        }
900
    }
901

902
    return result;
903
}
904

905
/*
906
 * Terminates AWT preloading
907
 */
908
void AWTPreloadStop() {
909
    if (fnPreloadStop != NULL) {
910
        fnPreloadStop();
911
    }
912
}
913

914
#endif /* ENABLE_AWT_PRELOAD */
915

916
int
917
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
918
        int argc, char **argv,
919
        int mode, char *what, int ret)
920
{
921
    ShowSplashScreen();
922
    return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
923
}
924

925
void
926
PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm)
927
{
928
    // stubbed out for windows and *nixes.
929
}
930

931
void
932
RegisterThread()
933
{
934
    // stubbed out for windows and *nixes.
935
}
936

937
/*
938
 * on windows, we return a false to indicate this option is not applicable
939
 */
940
jboolean
941
ProcessPlatformOption(const char *arg)
942
{
943
    return JNI_FALSE;
944
}
945

946
/*
947
 * At this point we have the arguments to the application, and we need to
948
 * check with original stdargs in order to compare which of these truly
949
 * needs expansion. cmdtoargs will specify this if it finds a bare
950
 * (unquoted) argument containing a glob character(s) ie. * or ?
951
 */
952
jobjectArray
953
CreateApplicationArgs(JNIEnv *env, char **strv, int argc)
954
{
955
    int i, j, idx;
956
    size_t tlen;
957
    jobjectArray outArray, inArray;
958
    char *arg, **nargv;
959
    jboolean needs_expansion = JNI_FALSE;
960
    jmethodID mid;
961
    int stdargc;
962
    StdArg *stdargs;
963
    int *appArgIdx;
964
    int isTool;
965
    jclass cls = GetLauncherHelperClass(env);
966
    NULL_CHECK0(cls);
967

968
    if (argc == 0) {
969
        return NewPlatformStringArray(env, strv, argc);
970
    }
971
    // the holy grail we need to compare with.
972
    stdargs = JLI_GetStdArgs();
973
    stdargc = JLI_GetStdArgc();
974

975
    // sanity check, this should never happen
976
    if (argc > stdargc) {
977
        JLI_TraceLauncher("Warning: app args is larger than the original, %d %d\n", argc, stdargc);
978
        JLI_TraceLauncher("passing arguments as-is.\n");
979
        return NewPlatformStringArray(env, strv, argc);
980
    }
981

982
    // sanity check, match the args we have, to the holy grail
983
    idx = JLI_GetAppArgIndex();
984

985
    // First arg index is NOT_FOUND
986
    if (idx < 0) {
987
        // The only allowed value should be NOT_FOUND (-1) unless another change introduces
988
        // a different negative index
989
        assert (idx == -1);
990
        JLI_TraceLauncher("Warning: first app arg index not found, %d\n", idx);
991
        JLI_TraceLauncher("passing arguments as-is.\n");
992
        return NewPlatformStringArray(env, strv, argc);
993
    }
994

995
    isTool = (idx == 0);
996
    if (isTool) { idx++; } // skip tool name
997
    JLI_TraceLauncher("AppArgIndex: %d points to %s\n", idx, stdargs[idx].arg);
998

999
    appArgIdx = calloc(argc, sizeof(int));
1000
    for (i = idx, j = 0; i < stdargc; i++) {
1001
        if (isTool) { // filter -J used by tools to pass JVM options
1002
            arg = stdargs[i].arg;
1003
            if (arg[0] == '-' && arg[1] == 'J') {
1004
                continue;
1005
            }
1006
        }
1007
        appArgIdx[j++] = i;
1008
    }
1009
    // sanity check, ensure same number of arguments for application
1010
    if (j != argc) {
1011
        JLI_TraceLauncher("Warning: app args count doesn't match, %d %d\n", j, argc);
1012
        JLI_TraceLauncher("passing arguments as-is.\n");
1013
        JLI_MemFree(appArgIdx);
1014
        return NewPlatformStringArray(env, strv, argc);
1015
    }
1016

1017
    // make a copy of the args which will be expanded in java if required.
1018
    nargv = (char **)JLI_MemAlloc(argc * sizeof(char*));
1019
    for (i = 0; i < argc; i++) {
1020
        jboolean arg_expand;
1021
        j = appArgIdx[i];
1022
        arg_expand = (JLI_StrCmp(stdargs[j].arg, strv[i]) == 0)
1023
            ? stdargs[j].has_wildcard
1024
            : JNI_FALSE;
1025
        if (needs_expansion == JNI_FALSE)
1026
            needs_expansion = arg_expand;
1027

1028
        // indicator char + String + NULL terminator, the java method will strip
1029
        // out the first character, the indicator character, so no matter what
1030
        // we add the indicator
1031
        tlen = 1 + JLI_StrLen(strv[i]) + 1;
1032
        nargv[i] = (char *) JLI_MemAlloc(tlen);
1033
        if (JLI_Snprintf(nargv[i], tlen, "%c%s", arg_expand ? 'T' : 'F',
1034
                         strv[i]) < 0) {
1035
            return NULL;
1036
        }
1037
        JLI_TraceLauncher("%s\n", nargv[i]);
1038
    }
1039

1040
    if (!needs_expansion) {
1041
        // clean up any allocated memory and return back the old arguments
1042
        for (i = 0 ; i < argc ; i++) {
1043
            JLI_MemFree(nargv[i]);
1044
        }
1045
        JLI_MemFree(nargv);
1046
        JLI_MemFree(appArgIdx);
1047
        return NewPlatformStringArray(env, strv, argc);
1048
    }
1049
    NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
1050
                                                "expandArgs",
1051
                                                "([Ljava/lang/String;)[Ljava/lang/String;"));
1052

1053
    // expand the arguments that require expansion, the java method will strip
1054
    // out the indicator character.
1055
    NULL_CHECK0(inArray = NewPlatformStringArray(env, nargv, argc));
1056
    outArray = (*env)->CallStaticObjectMethod(env, cls, mid, inArray);
1057
    for (i = 0; i < argc; i++) {
1058
        JLI_MemFree(nargv[i]);
1059
    }
1060
    JLI_MemFree(nargv);
1061
    JLI_MemFree(appArgIdx);
1062
    return outArray;
1063
}
1064

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.