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