Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/macosx/native/libjli/java_md_macosx.m
67760 views
1
/*
2
* Copyright (c) 2012, 2021, 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 "java.h"
27
#include "jvm_md.h"
28
#include <dirent.h>
29
#include <dlfcn.h>
30
#include <fcntl.h>
31
#include <inttypes.h>
32
#include <stdio.h>
33
#include <string.h>
34
#include <stdlib.h>
35
#include <sys/stat.h>
36
#include <unistd.h>
37
#include <sys/types.h>
38
#include <sys/time.h>
39
40
#include "manifest_info.h"
41
42
/* Support Cocoa event loop on the main thread */
43
#include <Cocoa/Cocoa.h>
44
#include <objc/objc-runtime.h>
45
#include <objc/objc-auto.h>
46
47
#include <errno.h>
48
#include <spawn.h>
49
50
struct NSAppArgs {
51
int argc;
52
char **argv;
53
};
54
55
#define JVM_DLL "libjvm.dylib"
56
#define JAVA_DLL "libjava.dylib"
57
/* FALLBACK avoids naming conflicts with system libraries
58
* (eg, ImageIO's libJPEG.dylib) */
59
#define LD_LIBRARY_PATH "DYLD_FALLBACK_LIBRARY_PATH"
60
61
/*
62
* If a processor / os combination has the ability to run binaries of
63
* two data models and cohabitation of jre/jdk bits with both data
64
* models is supported, then DUAL_MODE is defined. MacOSX is a hybrid
65
* system in that, the universal library can contain all types of libraries
66
* 32/64 and client/server, thus the spawn is capable of linking with the
67
* appropriate library as requested.
68
*
69
* Notes:
70
* 1. VM. DUAL_MODE is disabled, and not supported, however, it is left here in
71
* for experimentation and perhaps enable it in the future.
72
* 2. At the time of this writing, the universal library contains only
73
* a server 64-bit server JVM.
74
* 3. "-client" command line option is supported merely as a command line flag,
75
* for, compatibility reasons, however, a server VM will be launched.
76
*/
77
78
/*
79
* Flowchart of launcher execs and options processing on unix
80
*
81
* The selection of the proper vm shared library to open depends on
82
* several classes of command line options, including vm "flavor"
83
* options (-client, -server) and the data model options, -d32 and
84
* -d64, as well as a version specification which may have come from
85
* the command line or from the manifest of an executable jar file.
86
* The vm selection options are not passed to the running
87
* virtual machine; they must be screened out by the launcher.
88
*
89
* The version specification (if any) is processed first by the
90
* platform independent routine SelectVersion. This may result in
91
* the exec of the specified launcher version.
92
*
93
* Now, in most cases,the launcher will dlopen the target libjvm.so. All
94
* required libraries are loaded by the runtime linker, using the known paths
95
* baked into the shared libraries at compile time. Therefore,
96
* in most cases, the launcher will only exec, if the data models are
97
* mismatched, and will not set any environment variables, regardless of the
98
* data models.
99
*
100
*
101
*
102
* Main
103
* (incoming argv)
104
* |
105
* \|/
106
* CreateExecutionEnvironment
107
* (determines desired data model)
108
* |
109
* |
110
* \|/
111
* Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error)
112
* | |
113
* | |
114
* | \|/
115
* | YES
116
* | |
117
* | |
118
* | \|/
119
* | CheckJvmType
120
* | (removes -client, -server etc.)
121
* | |
122
* | |
123
* \|/ \|/
124
* YES Find the desired executable/library
125
* | |
126
* | |
127
* \|/ \|/
128
* CheckJvmType POINT A
129
* (removes -client, -server, etc.)
130
* |
131
* |
132
* \|/
133
* TranslateDashJArgs...
134
* (Prepare to pass args to vm)
135
* |
136
* |
137
* \|/
138
* ParseArguments
139
* (processes version options,
140
* creates argument list for vm,
141
* etc.)
142
* |
143
* |
144
* \|/
145
* POINT A
146
* |
147
* |
148
* \|/
149
* Path is desired JRE ? YES --> Continue
150
* NO
151
* |
152
* |
153
* \|/
154
* Paths have well known
155
* jvm paths ? --> NO --> Continue
156
* YES
157
* |
158
* |
159
* \|/
160
* Does libjvm.so exist
161
* in any of them ? --> NO --> Continue
162
* YES
163
* |
164
* |
165
* \|/
166
* Re-exec / Spawn
167
* |
168
* |
169
* \|/
170
* Main
171
*/
172
173
/* Store the name of the executable once computed */
174
static char *execname = NULL;
175
176
/*
177
* execname accessor from other parts of platform dependent logic
178
*/
179
const char *
180
GetExecName() {
181
return execname;
182
}
183
184
/*
185
* Exports the JNI interface from libjli
186
*
187
* This allows client code to link against the .jre/.jdk bundles,
188
* and not worry about trying to pick a HotSpot to link against.
189
*
190
* Switching architectures is unsupported, since client code has
191
* made that choice before the JVM was requested.
192
*/
193
194
static InvocationFunctions *sExportedJNIFunctions = NULL;
195
static char *sPreferredJVMType = NULL;
196
197
static InvocationFunctions *GetExportedJNIFunctions() {
198
if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;
199
200
char jrePath[PATH_MAX];
201
jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE);
202
if (!gotJREPath) {
203
JLI_ReportErrorMessage("Failed to GetJREPath()");
204
return NULL;
205
}
206
207
char *preferredJVM = sPreferredJVMType;
208
if (preferredJVM == NULL) {
209
#if defined(__i386__)
210
preferredJVM = "client";
211
#elif defined(__x86_64__)
212
preferredJVM = "server";
213
#elif defined(__aarch64__)
214
preferredJVM = "server";
215
#else
216
#error "Unknown architecture - needs definition"
217
#endif
218
}
219
220
char jvmPath[PATH_MAX];
221
jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath));
222
if (!gotJVMPath) {
223
JLI_ReportErrorMessage("Failed to GetJVMPath()");
224
return NULL;
225
}
226
227
InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));
228
jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);
229
if (!vmLoaded) {
230
JLI_ReportErrorMessage("Failed to LoadJavaVM()");
231
return NULL;
232
}
233
234
return sExportedJNIFunctions = fxns;
235
}
236
237
#ifndef STATIC_BUILD
238
239
JNIEXPORT jint JNICALL
240
JNI_GetDefaultJavaVMInitArgs(void *args) {
241
InvocationFunctions *ifn = GetExportedJNIFunctions();
242
if (ifn == NULL) return JNI_ERR;
243
return ifn->GetDefaultJavaVMInitArgs(args);
244
}
245
246
JNIEXPORT jint JNICALL
247
JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
248
InvocationFunctions *ifn = GetExportedJNIFunctions();
249
if (ifn == NULL) return JNI_ERR;
250
return ifn->CreateJavaVM(pvm, penv, args);
251
}
252
253
JNIEXPORT jint JNICALL
254
JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
255
InvocationFunctions *ifn = GetExportedJNIFunctions();
256
if (ifn == NULL) return JNI_ERR;
257
return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
258
}
259
#endif
260
261
/*
262
* Allow JLI-aware launchers to specify a client/server preference
263
*/
264
JNIEXPORT void JNICALL
265
JLI_SetPreferredJVM(const char *prefJVM) {
266
if (sPreferredJVMType != NULL) {
267
free(sPreferredJVMType);
268
sPreferredJVMType = NULL;
269
}
270
271
if (prefJVM == NULL) return;
272
sPreferredJVMType = strdup(prefJVM);
273
}
274
275
static BOOL awtLoaded = NO;
276
static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;
277
static pthread_cond_t awtLoaded_cv = PTHREAD_COND_INITIALIZER;
278
279
JNIEXPORT void JNICALL
280
JLI_NotifyAWTLoaded()
281
{
282
pthread_mutex_lock(&awtLoaded_mutex);
283
awtLoaded = YES;
284
pthread_cond_signal(&awtLoaded_cv);
285
pthread_mutex_unlock(&awtLoaded_mutex);
286
}
287
288
static int (*main_fptr)(int argc, char **argv) = NULL;
289
290
/*
291
* Unwrap the arguments and re-run main()
292
*/
293
static void *apple_main (void *arg)
294
{
295
if (main_fptr == NULL) {
296
#ifdef STATIC_BUILD
297
extern int main(int argc, char **argv);
298
main_fptr = &main;
299
#else
300
main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
301
#endif
302
if (main_fptr == NULL) {
303
JLI_ReportErrorMessageSys("error locating main entrypoint\n");
304
exit(1);
305
}
306
}
307
308
struct NSAppArgs *args = (struct NSAppArgs *) arg;
309
exit(main_fptr(args->argc, args->argv));
310
}
311
312
static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}
313
314
static void ParkEventLoop() {
315
// RunLoop needs at least one source, and 1e20 is pretty far into the future
316
CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
317
CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
318
CFRelease(t);
319
320
// Park this thread in the main run loop.
321
int32_t result;
322
do {
323
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e20, false);
324
} while (result != kCFRunLoopRunFinished);
325
}
326
327
/*
328
* Mac OS X mandates that the GUI event loop run on very first thread of
329
* an application. This requires that we re-call Java's main() on a new
330
* thread, reserving the 'main' thread for Cocoa.
331
*/
332
static void MacOSXStartup(int argc, char *argv[]) {
333
// Thread already started?
334
static jboolean started = false;
335
if (started) {
336
return;
337
}
338
started = true;
339
340
// Hand off arguments
341
struct NSAppArgs args;
342
args.argc = argc;
343
args.argv = argv;
344
345
// Fire up the main thread
346
pthread_t main_thr;
347
if (pthread_create(&main_thr, NULL, &apple_main, &args) != 0) {
348
JLI_ReportErrorMessageSys("Could not create main thread: %s\n", strerror(errno));
349
exit(1);
350
}
351
if (pthread_detach(main_thr)) {
352
JLI_ReportErrorMessageSys("pthread_detach() failed: %s\n", strerror(errno));
353
exit(1);
354
}
355
356
ParkEventLoop();
357
}
358
359
void
360
CreateExecutionEnvironment(int *pargc, char ***pargv,
361
char jrepath[], jint so_jrepath,
362
char jvmpath[], jint so_jvmpath,
363
char jvmcfg[], jint so_jvmcfg) {
364
jboolean jvmpathExists;
365
366
/* Compute/set the name of the executable */
367
SetExecname(*pargv);
368
369
char * jvmtype = NULL;
370
int argc = *pargc;
371
char **argv = *pargv;
372
373
/* Find out where the JRE is that we will be using. */
374
if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
375
JLI_ReportErrorMessage(JRE_ERROR1);
376
exit(2);
377
}
378
JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
379
jrepath, FILESEP, FILESEP);
380
/* Find the specified JVM type */
381
if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
382
JLI_ReportErrorMessage(CFG_ERROR7);
383
exit(1);
384
}
385
386
jvmpath[0] = '\0';
387
jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
388
if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
389
JLI_ReportErrorMessage(CFG_ERROR9);
390
exit(4);
391
}
392
393
if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {
394
JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
395
exit(4);
396
}
397
398
/*
399
* Mac OS X requires the Cocoa event loop to be run on the "main"
400
* thread. Spawn off a new thread to run main() and pass
401
* this thread off to the Cocoa event loop.
402
*/
403
MacOSXStartup(argc, argv);
404
405
/*
406
* we seem to have everything we need
407
*/
408
return;
409
}
410
411
/*
412
* VM choosing is done by the launcher (java.c).
413
*/
414
static jboolean
415
GetJVMPath(const char *jrepath, const char *jvmtype,
416
char *jvmpath, jint jvmpathsize)
417
{
418
struct stat s;
419
420
if (JLI_StrChr(jvmtype, '/')) {
421
JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
422
} else {
423
/*
424
* macosx client library is built thin, i386 only.
425
* 64 bit client requests must load server library
426
*/
427
JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
428
}
429
430
JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
431
432
#ifdef STATIC_BUILD
433
return JNI_TRUE;
434
#else
435
if (stat(jvmpath, &s) == 0) {
436
JLI_TraceLauncher("yes.\n");
437
return JNI_TRUE;
438
} else {
439
JLI_TraceLauncher("no.\n");
440
return JNI_FALSE;
441
}
442
#endif
443
}
444
445
/*
446
* Find path to JRE based on .exe's location or registry settings.
447
*/
448
static jboolean
449
GetJREPath(char *path, jint pathsize, jboolean speculative)
450
{
451
char libjava[MAXPATHLEN];
452
453
if (GetApplicationHome(path, pathsize)) {
454
/* Is JRE co-located with the application? */
455
#ifdef STATIC_BUILD
456
char jvm_cfg[MAXPATHLEN];
457
JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path);
458
if (access(jvm_cfg, F_OK) == 0) {
459
return JNI_TRUE;
460
}
461
#else
462
JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
463
if (access(libjava, F_OK) == 0) {
464
return JNI_TRUE;
465
}
466
#endif
467
/* ensure storage for path + /jre + NULL */
468
if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
469
JLI_TraceLauncher("Insufficient space to store JRE path\n");
470
return JNI_FALSE;
471
}
472
/* Does the app ship a private JRE in <apphome>/jre directory? */
473
JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
474
if (access(libjava, F_OK) == 0) {
475
JLI_StrCat(path, "/jre");
476
JLI_TraceLauncher("JRE path is %s\n", path);
477
return JNI_TRUE;
478
}
479
}
480
481
/* try to find ourselves instead */
482
Dl_info selfInfo;
483
dladdr(&GetJREPath, &selfInfo);
484
485
#ifdef STATIC_BUILD
486
char jvm_cfg[MAXPATHLEN];
487
char *p = NULL;
488
strncpy(jvm_cfg, selfInfo.dli_fname, MAXPATHLEN);
489
p = strrchr(jvm_cfg, '/'); *p = '\0';
490
p = strrchr(jvm_cfg, '/');
491
if (strcmp(p, "/.") == 0) {
492
*p = '\0';
493
p = strrchr(jvm_cfg, '/'); *p = '\0';
494
}
495
else *p = '\0';
496
strncpy(path, jvm_cfg, pathsize);
497
strncat(jvm_cfg, "/lib/jvm.cfg", MAXPATHLEN);
498
if (access(jvm_cfg, F_OK) == 0) {
499
return JNI_TRUE;
500
}
501
#endif
502
503
char *realPathToSelf = realpath(selfInfo.dli_fname, path);
504
if (realPathToSelf != path) {
505
return JNI_FALSE;
506
}
507
508
size_t pathLen = strlen(realPathToSelf);
509
if (pathLen == 0) {
510
return JNI_FALSE;
511
}
512
513
const char lastPathComponent[] = "/lib/libjli.dylib";
514
size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;
515
if (pathLen < sizeOfLastPathComponent) {
516
return JNI_FALSE;
517
}
518
519
size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;
520
if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent)) {
521
realPathToSelf[indexOfLastPathComponent + 1] = '\0';
522
return JNI_TRUE;
523
}
524
525
// If libjli.dylib is loaded from a macos bundle MacOS dir, find the JRE dir
526
// in ../Home.
527
const char altLastPathComponent[] = "/MacOS/libjli.dylib";
528
size_t sizeOfAltLastPathComponent = sizeof(altLastPathComponent) - 1;
529
if (pathLen < sizeOfLastPathComponent) {
530
return JNI_FALSE;
531
}
532
533
size_t indexOfAltLastPathComponent = pathLen - sizeOfAltLastPathComponent;
534
if (0 == strncmp(realPathToSelf + indexOfAltLastPathComponent, altLastPathComponent, sizeOfAltLastPathComponent)) {
535
JLI_Snprintf(realPathToSelf + indexOfAltLastPathComponent, sizeOfAltLastPathComponent, "%s", "/Home");
536
if (access(realPathToSelf, F_OK) == 0) {
537
return JNI_TRUE;
538
}
539
}
540
541
if (!speculative)
542
JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
543
return JNI_FALSE;
544
}
545
546
jboolean
547
LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
548
{
549
Dl_info dlinfo;
550
void *libjvm;
551
552
JLI_TraceLauncher("JVM path is %s\n", jvmpath);
553
554
#ifndef STATIC_BUILD
555
libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
556
#else
557
libjvm = dlopen(NULL, RTLD_FIRST);
558
#endif
559
if (libjvm == NULL) {
560
JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
561
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
562
return JNI_FALSE;
563
}
564
565
ifn->CreateJavaVM = (CreateJavaVM_t)
566
dlsym(libjvm, "JNI_CreateJavaVM");
567
if (ifn->CreateJavaVM == NULL) {
568
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
569
return JNI_FALSE;
570
}
571
572
ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
573
dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
574
if (ifn->GetDefaultJavaVMInitArgs == NULL) {
575
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
576
return JNI_FALSE;
577
}
578
579
ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
580
dlsym(libjvm, "JNI_GetCreatedJavaVMs");
581
if (ifn->GetCreatedJavaVMs == NULL) {
582
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
583
return JNI_FALSE;
584
}
585
586
return JNI_TRUE;
587
}
588
589
/*
590
* Compute the name of the executable
591
*
592
* In order to re-exec securely we need the absolute path of the
593
* executable. On Solaris getexecname(3c) may not return an absolute
594
* path so we use dladdr to get the filename of the executable and
595
* then use realpath to derive an absolute path. From Solaris 9
596
* onwards the filename returned in DL_info structure from dladdr is
597
* an absolute pathname so technically realpath isn't required.
598
* On Linux we read the executable name from /proc/self/exe.
599
* As a fallback, and for platforms other than Solaris and Linux,
600
* we use FindExecName to compute the executable name.
601
*/
602
const char*
603
SetExecname(char **argv)
604
{
605
char* exec_path = NULL;
606
{
607
Dl_info dlinfo;
608
609
#ifdef STATIC_BUILD
610
void *fptr;
611
fptr = (void *)&SetExecname;
612
#else
613
int (*fptr)();
614
fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
615
#endif
616
if (fptr == NULL) {
617
JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
618
return JNI_FALSE;
619
}
620
621
if (dladdr((void*)fptr, &dlinfo)) {
622
char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
623
if (resolved != NULL) {
624
exec_path = realpath(dlinfo.dli_fname, resolved);
625
if (exec_path == NULL) {
626
JLI_MemFree(resolved);
627
}
628
}
629
}
630
}
631
if (exec_path == NULL) {
632
exec_path = FindExecName(argv[0]);
633
}
634
execname = exec_path;
635
return exec_path;
636
}
637
638
/* --- Splash Screen shared library support --- */
639
640
static JavaVM* SetJavaVMValue()
641
{
642
JavaVM * jvm = NULL;
643
644
// The handle is good for both the launcher and the libosxapp.dylib
645
void * handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
646
if (handle) {
647
typedef JavaVM* (*JLI_GetJavaVMInstance_t)();
648
649
JLI_GetJavaVMInstance_t JLI_GetJavaVMInstance =
650
(JLI_GetJavaVMInstance_t)dlsym(handle,
651
"JLI_GetJavaVMInstance");
652
if (JLI_GetJavaVMInstance) {
653
jvm = JLI_GetJavaVMInstance();
654
}
655
656
if (jvm) {
657
typedef void (*OSXAPP_SetJavaVM_t)(JavaVM*);
658
659
OSXAPP_SetJavaVM_t OSXAPP_SetJavaVM =
660
(OSXAPP_SetJavaVM_t)dlsym(handle, "OSXAPP_SetJavaVM");
661
if (OSXAPP_SetJavaVM) {
662
OSXAPP_SetJavaVM(jvm);
663
} else {
664
jvm = NULL;
665
}
666
}
667
668
dlclose(handle);
669
}
670
671
return jvm;
672
}
673
674
static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
675
676
static void* hSplashLib = NULL;
677
678
void* SplashProcAddress(const char* name) {
679
if (!hSplashLib) {
680
char jrePath[PATH_MAX];
681
if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
682
JLI_ReportErrorMessage(JRE_ERROR1);
683
return NULL;
684
}
685
686
char splashPath[PATH_MAX];
687
const int ret = JLI_Snprintf(splashPath, sizeof(splashPath),
688
"%s/lib/%s", jrePath, SPLASHSCREEN_SO);
689
if (ret >= (int)sizeof(splashPath)) {
690
JLI_ReportErrorMessage(JRE_ERROR11);
691
return NULL;
692
}
693
if (ret < 0) {
694
JLI_ReportErrorMessage(JRE_ERROR13);
695
return NULL;
696
}
697
698
hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
699
// It's OK if dlopen() fails. The splash screen library binary file
700
// might have been stripped out from the JRE image to reduce its size
701
// (e.g. on embedded platforms).
702
703
if (hSplashLib) {
704
if (!SetJavaVMValue()) {
705
dlclose(hSplashLib);
706
hSplashLib = NULL;
707
}
708
}
709
}
710
if (hSplashLib) {
711
void* sym = dlsym(hSplashLib, name);
712
return sym;
713
} else {
714
return NULL;
715
}
716
}
717
718
/*
719
* Signature adapter for pthread_create().
720
*/
721
static void* ThreadJavaMain(void* args) {
722
return (void*)(intptr_t)JavaMain(args);
723
}
724
725
/*
726
* Block current thread and continue execution in a new thread.
727
*/
728
int
729
CallJavaMainInNewThread(jlong stack_size, void* args) {
730
int rslt;
731
pthread_t tid;
732
pthread_attr_t attr;
733
pthread_attr_init(&attr);
734
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
735
736
if (stack_size > 0) {
737
pthread_attr_setstacksize(&attr, stack_size);
738
}
739
pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads
740
741
if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) {
742
void* tmp;
743
pthread_join(tid, &tmp);
744
rslt = (int)(intptr_t)tmp;
745
} else {
746
/*
747
* Continue execution in current thread if for some reason (e.g. out of
748
* memory/LWP) a new thread can't be created. This will likely fail
749
* later in JavaMain as JNI_CreateJavaVM needs to create quite a
750
* few new threads, anyway, just give it a try..
751
*/
752
rslt = JavaMain(args);
753
}
754
755
pthread_attr_destroy(&attr);
756
return rslt;
757
}
758
759
static JavaVM* jvmInstance = NULL;
760
static jboolean sameThread = JNI_FALSE; /* start VM in current thread */
761
762
/*
763
* Note there is a callback on this function from the splashscreen logic,
764
* this as well SetJavaVMValue() needs to be simplified.
765
*/
766
JNIEXPORT JavaVM* JNICALL
767
JLI_GetJavaVMInstance()
768
{
769
return jvmInstance;
770
}
771
772
void
773
RegisterThread()
774
{
775
// stubbed out for windows and *nixes.
776
}
777
778
static void
779
SetXDockArgForAWT(const char *arg)
780
{
781
char envVar[80];
782
if (strstr(arg, "-Xdock:name=") == arg) {
783
/*
784
* The APP_NAME_<pid> environment variable is used to pass
785
* an application name as specified with the -Xdock:name command
786
* line option from Java launcher code to the AWT code in order
787
* to assign this name to the app's dock tile on the Mac.
788
* The _<pid> part is added to avoid collisions with child processes.
789
*
790
* WARNING: This environment variable is an implementation detail and
791
* isn't meant for use outside of the core platform. The mechanism for
792
* passing this information from Java launcher to other modules may
793
* change drastically between update release, and it may even be
794
* removed or replaced with another mechanism.
795
*
796
* NOTE: It is used by SWT, and JavaFX.
797
*/
798
snprintf(envVar, sizeof(envVar), "APP_NAME_%d", getpid());
799
setenv(envVar, (arg + 12), 1);
800
}
801
802
if (strstr(arg, "-Xdock:icon=") == arg) {
803
/*
804
* The APP_ICON_<pid> environment variable is used to pass
805
* an application icon as specified with the -Xdock:icon command
806
* line option from Java launcher code to the AWT code in order
807
* to assign this icon to the app's dock tile on the Mac.
808
* The _<pid> part is added to avoid collisions with child processes.
809
*
810
* WARNING: This environment variable is an implementation detail and
811
* isn't meant for use outside of the core platform. The mechanism for
812
* passing this information from Java launcher to other modules may
813
* change drastically between update release, and it may even be
814
* removed or replaced with another mechanism.
815
*
816
* NOTE: It is used by SWT, and JavaFX.
817
*/
818
snprintf(envVar, sizeof(envVar), "APP_ICON_%d", getpid());
819
setenv(envVar, (arg + 12), 1);
820
}
821
}
822
823
static void
824
SetMainClassForAWT(JNIEnv *env, jclass mainClass) {
825
jclass classClass = NULL;
826
NULL_CHECK(classClass = FindBootStrapClass(env, "java/lang/Class"));
827
828
jmethodID getCanonicalNameMID = NULL;
829
NULL_CHECK(getCanonicalNameMID = (*env)->GetMethodID(env, classClass, "getCanonicalName", "()Ljava/lang/String;"));
830
831
jstring mainClassString = (*env)->CallObjectMethod(env, mainClass, getCanonicalNameMID);
832
if ((*env)->ExceptionCheck(env) || NULL == mainClassString) {
833
/*
834
* Clears all errors caused by getCanonicalName() on the mainclass and
835
* leaves the JAVA_MAIN_CLASS__<pid> empty.
836
*/
837
(*env)->ExceptionClear(env);
838
return;
839
}
840
841
const char *mainClassName = NULL;
842
NULL_CHECK(mainClassName = (*env)->GetStringUTFChars(env, mainClassString, NULL));
843
844
char envVar[80];
845
/*
846
* The JAVA_MAIN_CLASS_<pid> environment variable is used to pass
847
* the name of a Java class whose main() method is invoked by
848
* the Java launcher code to start the application, to the AWT code
849
* in order to assign the name to the Apple menu bar when the app
850
* is active on the Mac.
851
* The _<pid> part is added to avoid collisions with child processes.
852
*
853
* WARNING: This environment variable is an implementation detail and
854
* isn't meant for use outside of the core platform. The mechanism for
855
* passing this information from Java launcher to other modules may
856
* change drastically between update release, and it may even be
857
* removed or replaced with another mechanism.
858
*
859
* NOTE: It is used by SWT, and JavaFX.
860
*/
861
snprintf(envVar, sizeof(envVar), "JAVA_MAIN_CLASS_%d", getpid());
862
setenv(envVar, mainClassName, 1);
863
864
(*env)->ReleaseStringUTFChars(env, mainClassString, mainClassName);
865
}
866
867
void
868
SetXStartOnFirstThreadArg()
869
{
870
// XXX: BEGIN HACK
871
// short circuit hack for <https://bugs.eclipse.org/bugs/show_bug.cgi?id=211625>
872
// need a way to get AWT/Swing apps launched when spawned from Eclipse,
873
// which currently has no UI to not pass the -XstartOnFirstThread option
874
if (getenv("HACK_IGNORE_START_ON_FIRST_THREAD") != NULL) return;
875
// XXX: END HACK
876
877
sameThread = JNI_TRUE;
878
// Set a variable that tells us we started on the main thread.
879
// This is used by the AWT during startup. (See LWCToolkit.m)
880
char envVar[80];
881
snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());
882
setenv(envVar, "1", 1);
883
}
884
885
// MacOSX we may continue in the same thread
886
int
887
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
888
int argc, char **argv,
889
int mode, char *what, int ret) {
890
if (sameThread) {
891
JLI_TraceLauncher("In same thread\n");
892
// need to block this thread against the main thread
893
// so signals get caught correctly
894
__block int rslt = 0;
895
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
896
{
897
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock: ^{
898
JavaMainArgs args;
899
args.argc = argc;
900
args.argv = argv;
901
args.mode = mode;
902
args.what = what;
903
args.ifn = *ifn;
904
rslt = JavaMain(&args);
905
}];
906
907
/*
908
* We cannot use dispatch_sync here, because it blocks the main dispatch queue.
909
* Using the main NSRunLoop allows the dispatch queue to run properly once
910
* SWT (or whatever toolkit this is needed for) kicks off it's own NSRunLoop
911
* and starts running.
912
*/
913
[op performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES];
914
}
915
[pool drain];
916
return rslt;
917
} else {
918
return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
919
}
920
}
921
922
/*
923
* Note the jvmInstance must be initialized first before entering into
924
* ShowSplashScreen, as there is a callback into the JLI_GetJavaVMInstance.
925
*/
926
void PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm) {
927
jvmInstance = vm;
928
SetMainClassForAWT(env, mainClass);
929
CHECK_EXCEPTION_RETURN();
930
ShowSplashScreen();
931
}
932
933
jboolean
934
ProcessPlatformOption(const char* arg)
935
{
936
if (JLI_StrCmp(arg, "-XstartOnFirstThread") == 0) {
937
SetXStartOnFirstThreadArg();
938
return JNI_TRUE;
939
} else if (JLI_StrCCmp(arg, "-Xdock:") == 0) {
940
SetXDockArgForAWT(arg);
941
return JNI_TRUE;
942
}
943
// arguments we know not
944
return JNI_FALSE;
945
}
946
947