Path: blob/jdk8u272-b10-aarch32-20201026/jdk/src/macosx/bin/java_md_macosx.c
83397 views
/*1* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "java.h"26#include "jvm_md.h"27#include <dirent.h>28#include <dlfcn.h>29#include <fcntl.h>30#include <inttypes.h>31#include <stdio.h>32#include <string.h>33#include <stdlib.h>34#include <sys/stat.h>35#include <unistd.h>36#include <sys/types.h>37#include <sys/time.h>3839#include "manifest_info.h"40#include "version_comp.h"4142/* Support Cocoa event loop on the main thread */43#include <Cocoa/Cocoa.h>44#include <objc/objc-runtime.h>45#include <objc/objc-auto.h>4647#include <errno.h>48#include <spawn.h>4950struct NSAppArgs {51int argc;52char **argv;53};5455#define JVM_DLL "libjvm.dylib"56#define JAVA_DLL "libjava.dylib"57/* FALLBACK avoids naming conflicts with system libraries58* (eg, ImageIO's libJPEG.dylib) */59#define LD_LIBRARY_PATH "DYLD_FALLBACK_LIBRARY_PATH"6061/*62* If a processor / os combination has the ability to run binaries of63* two data models and cohabitation of jre/jdk bits with both data64* models is supported, then DUAL_MODE is defined. MacOSX is a hybrid65* system in that, the universal library can contain all types of libraries66* 32/64 and client/server, thus the spawn is capable of linking with the67* appropriate library as requested.68*69* Notes:70* 1. VM. DUAL_MODE is disabled, and not supported, however, it is left here in71* for experimentation and perhaps enable it in the future.72* 2. At the time of this writing, the universal library contains only73* a server 64-bit server JVM.74* 3. "-client" command line option is supported merely as a command line flag,75* for, compatibility reasons, however, a server VM will be launched.76*/7778/*79* Flowchart of launcher execs and options processing on unix80*81* The selection of the proper vm shared library to open depends on82* several classes of command line options, including vm "flavor"83* options (-client, -server) and the data model options, -d32 and84* -d64, as well as a version specification which may have come from85* the command line or from the manifest of an executable jar file.86* The vm selection options are not passed to the running87* virtual machine; they must be screened out by the launcher.88*89* The version specification (if any) is processed first by the90* platform independent routine SelectVersion. This may result in91* the exec of the specified launcher version.92*93* Now, in most cases,the launcher will dlopen the target libjvm.so. All94* required libraries are loaded by the runtime linker, using the known paths95* baked into the shared libraries at compile time. Therefore,96* in most cases, the launcher will only exec, if the data models are97* mismatched, and will not set any environment variables, regardless of the98* data models.99*100*101*102* Main103* (incoming argv)104* |105* \|/106* SelectVersion107* (selects the JRE version, note: not data model)108* |109* \|/110* CreateExecutionEnvironment111* (determines desired data model)112* |113* |114* \|/115* Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error)116* | |117* | |118* | \|/119* | YES120* | |121* | |122* | \|/123* | CheckJvmType124* | (removes -client, -server etc.)125* | |126* | |127* \|/ \|/128* YES Find the desired executable/library129* | |130* | |131* \|/ \|/132* CheckJvmType POINT A133* (removes -client, -server, etc.)134* |135* |136* \|/137* TranslateDashJArgs...138* (Prepare to pass args to vm)139* |140* |141* \|/142* ParseArguments143* (removes -d32 and -d64 if any,144* processes version options,145* creates argument list for vm,146* etc.)147* |148* |149* \|/150* POINT A151* |152* |153* \|/154* Path is desired JRE ? YES --> Have Desired Model ? NO --> Re-exec --> Main155* NO YES --> Continue156* |157* |158* \|/159* Paths have well known160* jvm paths ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main161* YES YES --> Continue162* |163* |164* \|/165* Does libjvm.so exist166* in any of them ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main167* YES YES --> Continue168* |169* |170* \|/171* Re-exec / Spawn172* |173* |174* \|/175* Main176*/177178#define GetArch() GetArchPath(CURRENT_DATA_MODEL)179180/* Store the name of the executable once computed */181static char *execname = NULL;182183/*184* execname accessor from other parts of platform dependent logic185*/186const char *187GetExecName() {188return execname;189}190191const char *192GetArchPath(int nbits)193{194switch(nbits) {195default:196return LIBARCHNAME;197}198}199200201/*202* Exports the JNI interface from libjli203*204* This allows client code to link against the .jre/.jdk bundles,205* and not worry about trying to pick a HotSpot to link against.206*207* Switching architectures is unsupported, since client code has208* made that choice before the JVM was requested.209*/210211static InvocationFunctions *sExportedJNIFunctions = NULL;212static char *sPreferredJVMType = NULL;213214static InvocationFunctions *GetExportedJNIFunctions() {215if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;216217char jrePath[PATH_MAX];218jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE);219if (!gotJREPath) {220JLI_ReportErrorMessage("Failed to GetJREPath()");221return NULL;222}223224char *preferredJVM = sPreferredJVMType;225if (preferredJVM == NULL) {226#if defined(__i386__)227preferredJVM = "client";228#elif defined(__x86_64__)229preferredJVM = "server";230#else231#error "Unknown architecture - needs definition"232#endif233}234235char jvmPath[PATH_MAX];236jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);237if (!gotJVMPath) {238JLI_ReportErrorMessage("Failed to GetJVMPath()");239return NULL;240}241242InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));243jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);244if (!vmLoaded) {245JLI_ReportErrorMessage("Failed to LoadJavaVM()");246return NULL;247}248249return sExportedJNIFunctions = fxns;250}251252JNIEXPORT jint JNICALL253JNI_GetDefaultJavaVMInitArgs(void *args) {254InvocationFunctions *ifn = GetExportedJNIFunctions();255if (ifn == NULL) return JNI_ERR;256return ifn->GetDefaultJavaVMInitArgs(args);257}258259JNIEXPORT jint JNICALL260JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {261InvocationFunctions *ifn = GetExportedJNIFunctions();262if (ifn == NULL) return JNI_ERR;263return ifn->CreateJavaVM(pvm, penv, args);264}265266JNIEXPORT jint JNICALL267JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {268InvocationFunctions *ifn = GetExportedJNIFunctions();269if (ifn == NULL) return JNI_ERR;270return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);271}272273/*274* Allow JLI-aware launchers to specify a client/server preference275*/276JNIEXPORT void JNICALL277JLI_SetPreferredJVM(const char *prefJVM) {278if (sPreferredJVMType != NULL) {279free(sPreferredJVMType);280sPreferredJVMType = NULL;281}282283if (prefJVM == NULL) return;284sPreferredJVMType = strdup(prefJVM);285}286287static BOOL awtLoaded = NO;288static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;289static pthread_cond_t awtLoaded_cv = PTHREAD_COND_INITIALIZER;290291JNIEXPORT void JNICALL292JLI_NotifyAWTLoaded()293{294pthread_mutex_lock(&awtLoaded_mutex);295awtLoaded = YES;296pthread_cond_signal(&awtLoaded_cv);297pthread_mutex_unlock(&awtLoaded_mutex);298}299300static int (*main_fptr)(int argc, char **argv) = NULL;301302/*303* Unwrap the arguments and re-run main()304*/305static void *apple_main (void *arg)306{307objc_registerThreadWithCollector();308309if (main_fptr == NULL) {310main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");311if (main_fptr == NULL) {312JLI_ReportErrorMessageSys("error locating main entrypoint\n");313exit(1);314}315}316317struct NSAppArgs *args = (struct NSAppArgs *) arg;318exit(main_fptr(args->argc, args->argv));319}320321static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}322323static void ParkEventLoop() {324// RunLoop needs at least one source, and 1e20 is pretty far into the future325CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);326CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);327CFRelease(t);328329// Park this thread in the main run loop.330int32_t result;331do {332result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e20, false);333} while (result != kCFRunLoopRunFinished);334}335336/*337* Mac OS X mandates that the GUI event loop run on very first thread of338* an application. This requires that we re-call Java's main() on a new339* thread, reserving the 'main' thread for Cocoa.340*/341static void MacOSXStartup(int argc, char *argv[]) {342// Thread already started?343static jboolean started = false;344if (started) {345return;346}347started = true;348349// Hand off arguments350struct NSAppArgs args;351args.argc = argc;352args.argv = argv;353354// Fire up the main thread355pthread_t main_thr;356if (pthread_create(&main_thr, NULL, &apple_main, &args) != 0) {357JLI_ReportErrorMessageSys("Could not create main thread: %s\n", strerror(errno));358exit(1);359}360if (pthread_detach(main_thr)) {361JLI_ReportErrorMessageSys("pthread_detach() failed: %s\n", strerror(errno));362exit(1);363}364365ParkEventLoop();366}367368void369CreateExecutionEnvironment(int *pargc, char ***pargv,370char jrepath[], jint so_jrepath,371char jvmpath[], jint so_jvmpath,372char jvmcfg[], jint so_jvmcfg) {373/*374* First, determine if we are running the desired data model. If we375* are running the desired data model, all the error messages376* associated with calling GetJREPath, ReadKnownVMs, etc. should be377* output. However, if we are not running the desired data model,378* some of the errors should be suppressed since it is more379* informative to issue an error message based on whether or not the380* os/processor combination has dual mode capabilities.381*/382jboolean jvmpathExists;383384/* Compute/set the name of the executable */385SetExecname(*pargv);386387/* Check data model flags, and exec process, if needed */388{389char *arch = (char *)GetArch(); /* like sparc or sparcv9 */390char * jvmtype = NULL;391int argc = *pargc;392char **argv = *pargv;393int running = CURRENT_DATA_MODEL;394395int wanted = running; /* What data mode is being396asked for? Current model is397fine unless another model398is asked for */399400char** newargv = NULL;401int newargc = 0;402403/*404* Starting in 1.5, all unix platforms accept the -d32 and -d64405* options. On platforms where only one data-model is supported406* (e.g. ia-64 Linux), using the flag for the other data model is407* an error and will terminate the program.408*/409410{ /* open new scope to declare local variables */411int i;412413newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*));414newargv[newargc++] = argv[0];415416/* scan for data model arguments and remove from argument list;417last occurrence determines desired data model */418for (i=1; i < argc; i++) {419420if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) {421wanted = 64;422continue;423}424if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) {425wanted = 32;426continue;427}428newargv[newargc++] = argv[i];429430if (IsJavaArgs()) {431if (argv[i][0] != '-') continue;432} else {433if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) {434i++;435if (i >= argc) break;436newargv[newargc++] = argv[i];437continue;438}439if (argv[i][0] != '-') { i++; break; }440}441}442443/* copy rest of args [i .. argc) */444while (i < argc) {445newargv[newargc++] = argv[i++];446}447newargv[newargc] = NULL;448449/*450* newargv has all proper arguments here451*/452453argc = newargc;454argv = newargv;455}456457/* If the data model is not changing, it is an error if the458jvmpath does not exist */459if (wanted == running) {460/* Find out where the JRE is that we will be using. */461if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {462JLI_ReportErrorMessage(JRE_ERROR1);463exit(2);464}465JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",466jrepath, FILESEP, FILESEP, "", "");467/* Find the specified JVM type */468if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {469JLI_ReportErrorMessage(CFG_ERROR7);470exit(1);471}472473jvmpath[0] = '\0';474jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);475if (JLI_StrCmp(jvmtype, "ERROR") == 0) {476JLI_ReportErrorMessage(CFG_ERROR9);477exit(4);478}479480if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, wanted)) {481JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);482exit(4);483}484485/*486* Mac OS X requires the Cocoa event loop to be run on the "main"487* thread. Spawn off a new thread to run main() and pass488* this thread off to the Cocoa event loop.489*/490MacOSXStartup(argc, argv);491492/*493* we seem to have everything we need, so without further ado494* we return back, otherwise proceed to set the environment.495*/496return;497} else { /* do the same speculatively or exit */498#if defined(DUAL_MODE)499if (running != wanted) {500/* Find out where the JRE is that we will be using. */501if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) {502/* give up and let other code report error message */503JLI_ReportErrorMessage(JRE_ERROR2, wanted);504exit(1);505}506JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",507jrepath, FILESEP, FILESEP, "", "");508/*509* Read in jvm.cfg for target data model and process vm510* selection options.511*/512if (ReadKnownVMs(jvmcfg, JNI_TRUE) < 1) {513/* give up and let other code report error message */514JLI_ReportErrorMessage(JRE_ERROR2, wanted);515exit(1);516}517jvmpath[0] = '\0';518jvmtype = CheckJvmType(pargc, pargv, JNI_TRUE);519if (JLI_StrCmp(jvmtype, "ERROR") == 0) {520JLI_ReportErrorMessage(CFG_ERROR9);521exit(4);522}523524/* exec child can do error checking on the existence of the path */525jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), wanted);526}527#else /* ! DUAL_MODE */528JLI_ReportErrorMessage(JRE_ERROR2, wanted);529exit(1);530#endif /* DUAL_MODE */531}532{533char *newexec = execname;534JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");535(void) fflush(stdout);536(void) fflush(stderr);537/*538* Use posix_spawn() instead of execv() on Mac OS X.539* This allows us to choose which architecture the child process540* should run as.541*/542{543posix_spawnattr_t attr;544size_t unused_size;545pid_t unused_pid;546547#if defined(__i386__) || defined(__x86_64__)548cpu_type_t cpu_type[] = { (wanted == 64) ? CPU_TYPE_X86_64 : CPU_TYPE_X86,549(running== 64) ? CPU_TYPE_X86_64 : CPU_TYPE_X86 };550#else551cpu_type_t cpu_type[] = { CPU_TYPE_ANY };552#endif /* __i386 .. */553554posix_spawnattr_init(&attr);555posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);556posix_spawnattr_setbinpref_np(&attr, sizeof(cpu_type) / sizeof(cpu_type_t),557cpu_type, &unused_size);558559posix_spawn(&unused_pid, newexec, NULL, &attr, argv, environ);560}561JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);562563#if defined(DUAL_MODE)564if (running != wanted) {565JLI_ReportErrorMessage(JRE_ERROR5, wanted, running);566}567#endif /* DUAL_MODE */568}569exit(1);570}571}572573/*574* VM choosing is done by the launcher (java.c).575*/576static jboolean577GetJVMPath(const char *jrepath, const char *jvmtype,578char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)579{580struct stat s;581582if (JLI_StrChr(jvmtype, '/')) {583JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);584} else {585/*586* macosx client library is built thin, i386 only.587* 64 bit client requests must load server library588*/589const char *jvmtypeUsed = ((bitsWanted == 64) && (strcmp(jvmtype, "client") == 0)) ? "server" : jvmtype;590JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtypeUsed);591}592593JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);594595if (stat(jvmpath, &s) == 0) {596JLI_TraceLauncher("yes.\n");597return JNI_TRUE;598} else {599JLI_TraceLauncher("no.\n");600return JNI_FALSE;601}602}603604/*605* Find path to JRE based on .exe's location or registry settings.606*/607static jboolean608GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)609{610char libjava[MAXPATHLEN];611612if (GetApplicationHome(path, pathsize)) {613/* Is JRE co-located with the application? */614JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);615if (access(libjava, F_OK) == 0) {616return JNI_TRUE;617}618/* ensure storage for path + /jre + NULL */619if ((JLI_StrLen(path) + 4 + 1) > pathsize) {620JLI_TraceLauncher("Insufficient space to store JRE path\n");621return JNI_FALSE;622}623/* Does the app ship a private JRE in <apphome>/jre directory? */624JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);625if (access(libjava, F_OK) == 0) {626JLI_StrCat(path, "/jre");627JLI_TraceLauncher("JRE path is %s\n", path);628return JNI_TRUE;629}630}631632/* try to find ourselves instead */633Dl_info selfInfo;634dladdr(&GetJREPath, &selfInfo);635636char *realPathToSelf = realpath(selfInfo.dli_fname, path);637if (realPathToSelf != path) {638return JNI_FALSE;639}640641size_t pathLen = strlen(realPathToSelf);642if (pathLen == 0) {643return JNI_FALSE;644}645646const char lastPathComponent[] = "/lib/jli/libjli.dylib";647size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;648if (pathLen < sizeOfLastPathComponent) {649return JNI_FALSE;650}651652size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;653if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent)) {654realPathToSelf[indexOfLastPathComponent + 1] = '\0';655return JNI_TRUE;656}657658// If libjli.dylib is loaded from a macos bundle MacOS dir, find the JRE dir659// in ../Home.660const char altLastPathComponent[] = "/MacOS/libjli.dylib";661size_t sizeOfAltLastPathComponent = sizeof(altLastPathComponent) - 1;662if (pathLen < sizeOfLastPathComponent) {663return JNI_FALSE;664}665666size_t indexOfAltLastPathComponent = pathLen - sizeOfAltLastPathComponent;667if (0 == strncmp(realPathToSelf + indexOfAltLastPathComponent, altLastPathComponent, sizeOfAltLastPathComponent)) {668JLI_Snprintf(realPathToSelf + indexOfAltLastPathComponent, sizeOfAltLastPathComponent, "%s", "/Home/jre");669if (access(realPathToSelf, F_OK) == 0) {670return JNI_TRUE;671}672JLI_Snprintf(realPathToSelf + indexOfAltLastPathComponent, sizeOfAltLastPathComponent, "%s", "/Home");673if (access(realPathToSelf, F_OK) == 0) {674return JNI_TRUE;675}676}677678if (!speculative)679JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);680return JNI_FALSE;681}682683jboolean684LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)685{686Dl_info dlinfo;687void *libjvm;688689JLI_TraceLauncher("JVM path is %s\n", jvmpath);690691libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);692if (libjvm == NULL) {693JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);694JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());695return JNI_FALSE;696}697698ifn->CreateJavaVM = (CreateJavaVM_t)699dlsym(libjvm, "JNI_CreateJavaVM");700if (ifn->CreateJavaVM == NULL) {701JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());702return JNI_FALSE;703}704705ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)706dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");707if (ifn->GetDefaultJavaVMInitArgs == NULL) {708JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());709return JNI_FALSE;710}711712ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)713dlsym(libjvm, "JNI_GetCreatedJavaVMs");714if (ifn->GetCreatedJavaVMs == NULL) {715JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());716return JNI_FALSE;717}718719return JNI_TRUE;720}721722/*723* Compute the name of the executable724*725* In order to re-exec securely we need the absolute path of the726* executable. On Solaris getexecname(3c) may not return an absolute727* path so we use dladdr to get the filename of the executable and728* then use realpath to derive an absolute path. From Solaris 9729* onwards the filename returned in DL_info structure from dladdr is730* an absolute pathname so technically realpath isn't required.731* On Linux we read the executable name from /proc/self/exe.732* As a fallback, and for platforms other than Solaris and Linux,733* we use FindExecName to compute the executable name.734*/735const char*736SetExecname(char **argv)737{738char* exec_path = NULL;739{740Dl_info dlinfo;741int (*fptr)();742743fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");744if (fptr == NULL) {745JLI_ReportErrorMessage(DLL_ERROR3, dlerror());746return JNI_FALSE;747}748749if (dladdr((void*)fptr, &dlinfo)) {750char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);751if (resolved != NULL) {752exec_path = realpath(dlinfo.dli_fname, resolved);753if (exec_path == NULL) {754JLI_MemFree(resolved);755}756}757}758}759if (exec_path == NULL) {760exec_path = FindExecName(argv[0]);761}762execname = exec_path;763return exec_path;764}765766/*767* BSD's implementation of CounterGet()768*/769int64_t770CounterGet()771{772struct timeval tv;773gettimeofday(&tv, NULL);774return (tv.tv_sec * 1000000) + tv.tv_usec;775}776777778/* --- Splash Screen shared library support --- */779780static JavaVM* SetJavaVMValue()781{782JavaVM * jvm = NULL;783784// The handle is good for both the launcher and the libosxapp.dylib785void * handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);786if (handle) {787typedef JavaVM* (*JLI_GetJavaVMInstance_t)();788789JLI_GetJavaVMInstance_t JLI_GetJavaVMInstance =790(JLI_GetJavaVMInstance_t)dlsym(handle,791"JLI_GetJavaVMInstance");792if (JLI_GetJavaVMInstance) {793jvm = JLI_GetJavaVMInstance();794}795796if (jvm) {797typedef void (*OSXAPP_SetJavaVM_t)(JavaVM*);798799OSXAPP_SetJavaVM_t OSXAPP_SetJavaVM =800(OSXAPP_SetJavaVM_t)dlsym(handle, "OSXAPP_SetJavaVM");801if (OSXAPP_SetJavaVM) {802OSXAPP_SetJavaVM(jvm);803} else {804jvm = NULL;805}806}807808dlclose(handle);809}810811return jvm;812}813814static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");815816static void* hSplashLib = NULL;817818void* SplashProcAddress(const char* name) {819if (!hSplashLib) {820char jrePath[PATH_MAX];821if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) {822JLI_ReportErrorMessage(JRE_ERROR1);823return NULL;824}825826char splashPath[PATH_MAX];827const int ret = JLI_Snprintf(splashPath, sizeof(splashPath),828"%s/lib/%s", jrePath, SPLASHSCREEN_SO);829if (ret >= (int)sizeof(splashPath)) {830JLI_ReportErrorMessage(JRE_ERROR11);831return NULL;832}833if (ret < 0) {834JLI_ReportErrorMessage(JRE_ERROR13);835return NULL;836}837838hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);839// It's OK if dlopen() fails. The splash screen library binary file840// might have been stripped out from the JRE image to reduce its size841// (e.g. on embedded platforms).842843if (hSplashLib) {844if (!SetJavaVMValue()) {845dlclose(hSplashLib);846hSplashLib = NULL;847}848}849}850if (hSplashLib) {851void* sym = dlsym(hSplashLib, name);852return sym;853} else {854return NULL;855}856}857858void SplashFreeLibrary() {859if (hSplashLib) {860dlclose(hSplashLib);861hSplashLib = NULL;862}863}864865/*866* Block current thread and continue execution in a new thread867*/868int869ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {870int rslt;871pthread_t tid;872pthread_attr_t attr;873pthread_attr_init(&attr);874pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);875876if (stack_size > 0) {877pthread_attr_setstacksize(&attr, stack_size);878}879880if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {881void * tmp;882pthread_join(tid, &tmp);883rslt = (int)tmp;884} else {885/*886* Continue execution in current thread if for some reason (e.g. out of887* memory/LWP) a new thread can't be created. This will likely fail888* later in continuation as JNI_CreateJavaVM needs to create quite a889* few new threads, anyway, just give it a try..890*/891rslt = continuation(args);892}893894pthread_attr_destroy(&attr);895return rslt;896}897898void SetJavaLauncherPlatformProps() {899/* Linux only */900}901902jboolean903ServerClassMachine(void) {904return JNI_TRUE;905}906907static JavaVM* jvmInstance = NULL;908static jboolean sameThread = JNI_FALSE; /* start VM in current thread */909910/*911* Note there is a callback on this function from the splashscreen logic,912* this as well SetJavaVMValue() needs to be simplified.913*/914JavaVM*915JLI_GetJavaVMInstance()916{917return jvmInstance;918}919920void921RegisterThread()922{923objc_registerThreadWithCollector();924}925926static void927SetXDockArgForAWT(const char *arg)928{929char envVar[80];930if (strstr(arg, "-Xdock:name=") == arg) {931/*932* The APP_NAME_<pid> environment variable is used to pass933* an application name as specified with the -Xdock:name command934* line option from Java launcher code to the AWT code in order935* to assign this name to the app's dock tile on the Mac.936* The _<pid> part is added to avoid collisions with child processes.937*938* WARNING: This environment variable is an implementation detail and939* isn't meant for use outside of the core platform. The mechanism for940* passing this information from Java launcher to other modules may941* change drastically between update release, and it may even be942* removed or replaced with another mechanism.943*944* NOTE: It is used by SWT, and JavaFX.945*/946snprintf(envVar, sizeof(envVar), "APP_NAME_%d", getpid());947setenv(envVar, (arg + 12), 1);948}949950if (strstr(arg, "-Xdock:icon=") == arg) {951/*952* The APP_ICON_<pid> environment variable is used to pass953* an application icon as specified with the -Xdock:icon command954* line option from Java launcher code to the AWT code in order955* to assign this icon to the app's dock tile on the Mac.956* The _<pid> part is added to avoid collisions with child processes.957*958* WARNING: This environment variable is an implementation detail and959* isn't meant for use outside of the core platform. The mechanism for960* passing this information from Java launcher to other modules may961* change drastically between update release, and it may even be962* removed or replaced with another mechanism.963*964* NOTE: It is used by SWT, and JavaFX.965*/966snprintf(envVar, sizeof(envVar), "APP_ICON_%d", getpid());967setenv(envVar, (arg + 12), 1);968}969}970971static void972SetMainClassForAWT(JNIEnv *env, jclass mainClass) {973jclass classClass = NULL;974NULL_CHECK(classClass = FindBootStrapClass(env, "java/lang/Class"));975976jmethodID getCanonicalNameMID = NULL;977NULL_CHECK(getCanonicalNameMID = (*env)->GetMethodID(env, classClass, "getCanonicalName", "()Ljava/lang/String;"));978979jstring mainClassString = NULL;980NULL_CHECK(mainClassString = (*env)->CallObjectMethod(env, mainClass, getCanonicalNameMID));981982const char *mainClassName = NULL;983NULL_CHECK(mainClassName = (*env)->GetStringUTFChars(env, mainClassString, NULL));984985char envVar[80];986/*987* The JAVA_MAIN_CLASS_<pid> environment variable is used to pass988* the name of a Java class whose main() method is invoked by989* the Java launcher code to start the application, to the AWT code990* in order to assign the name to the Apple menu bar when the app991* is active on the Mac.992* The _<pid> part is added to avoid collisions with child processes.993*994* WARNING: This environment variable is an implementation detail and995* isn't meant for use outside of the core platform. The mechanism for996* passing this information from Java launcher to other modules may997* change drastically between update release, and it may even be998* removed or replaced with another mechanism.999*1000* NOTE: It is used by SWT, and JavaFX.1001*/1002snprintf(envVar, sizeof(envVar), "JAVA_MAIN_CLASS_%d", getpid());1003setenv(envVar, mainClassName, 1);10041005(*env)->ReleaseStringUTFChars(env, mainClassString, mainClassName);1006}10071008void1009SetXStartOnFirstThreadArg()1010{1011// XXX: BEGIN HACK1012// short circuit hack for <https://bugs.eclipse.org/bugs/show_bug.cgi?id=211625>1013// need a way to get AWT/Swing apps launched when spawned from Eclipse,1014// which currently has no UI to not pass the -XstartOnFirstThread option1015if (getenv("HACK_IGNORE_START_ON_FIRST_THREAD") != NULL) return;1016// XXX: END HACK10171018sameThread = JNI_TRUE;1019// Set a variable that tells us we started on the main thread.1020// This is used by the AWT during startup. (See awt.m)1021char envVar[80];1022snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());1023setenv(envVar, "1", 1);1024}10251026// MacOSX we may continue in the same thread1027int1028JVMInit(InvocationFunctions* ifn, jlong threadStackSize,1029int argc, char **argv,1030int mode, char *what, int ret) {1031if (sameThread) {1032JLI_TraceLauncher("In same thread\n");1033// need to block this thread against the main thread1034// so signals get caught correctly1035__block int rslt = 0;1036NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];1037{1038NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock: ^{1039JavaMainArgs args;1040args.argc = argc;1041args.argv = argv;1042args.mode = mode;1043args.what = what;1044args.ifn = *ifn;1045rslt = JavaMain(&args);1046}];10471048/*1049* We cannot use dispatch_sync here, because it blocks the main dispatch queue.1050* Using the main NSRunLoop allows the dispatch queue to run properly once1051* SWT (or whatever toolkit this is needed for) kicks off it's own NSRunLoop1052* and starts running.1053*/1054[op performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES];1055}1056[pool drain];1057return rslt;1058} else {1059return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);1060}1061}10621063/*1064* Note the jvmInstance must be initialized first before entering into1065* ShowSplashScreen, as there is a callback into the JLI_GetJavaVMInstance.1066*/1067void PostJVMInit(JNIEnv *env, jstring mainClass, JavaVM *vm) {1068jvmInstance = vm;1069SetMainClassForAWT(env, mainClass);1070CHECK_EXCEPTION_RETURN();1071ShowSplashScreen();1072}10731074jboolean1075ProcessPlatformOption(const char* arg)1076{1077if (JLI_StrCmp(arg, "-XstartOnFirstThread") == 0) {1078SetXStartOnFirstThreadArg();1079return JNI_TRUE;1080} else if (JLI_StrCCmp(arg, "-Xdock:") == 0) {1081SetXDockArgForAWT(arg);1082return JNI_TRUE;1083}1084// arguments we know not1085return JNI_FALSE;1086}108710881089