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