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