Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/bin/java_md_macosx.c
32285 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#elif defined(__aarch64__)231preferredJVM = "server";232#else233#error "Unknown architecture - needs definition"234#endif235}236237char jvmPath[PATH_MAX];238jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);239if (!gotJVMPath) {240JLI_ReportErrorMessage("Failed to GetJVMPath()");241return NULL;242}243244InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));245jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);246if (!vmLoaded) {247JLI_ReportErrorMessage("Failed to LoadJavaVM()");248return NULL;249}250251return sExportedJNIFunctions = fxns;252}253254JNIEXPORT jint JNICALL255JNI_GetDefaultJavaVMInitArgs(void *args) {256InvocationFunctions *ifn = GetExportedJNIFunctions();257if (ifn == NULL) return JNI_ERR;258return ifn->GetDefaultJavaVMInitArgs(args);259}260261JNIEXPORT jint JNICALL262JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {263InvocationFunctions *ifn = GetExportedJNIFunctions();264if (ifn == NULL) return JNI_ERR;265return ifn->CreateJavaVM(pvm, penv, args);266}267268JNIEXPORT jint JNICALL269JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {270InvocationFunctions *ifn = GetExportedJNIFunctions();271if (ifn == NULL) return JNI_ERR;272return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);273}274275/*276* Allow JLI-aware launchers to specify a client/server preference277*/278JNIEXPORT void JNICALL279JLI_SetPreferredJVM(const char *prefJVM) {280if (sPreferredJVMType != NULL) {281free(sPreferredJVMType);282sPreferredJVMType = NULL;283}284285if (prefJVM == NULL) return;286sPreferredJVMType = strdup(prefJVM);287}288289static BOOL awtLoaded = NO;290static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;291static pthread_cond_t awtLoaded_cv = PTHREAD_COND_INITIALIZER;292293JNIEXPORT void JNICALL294JLI_NotifyAWTLoaded()295{296pthread_mutex_lock(&awtLoaded_mutex);297awtLoaded = YES;298pthread_cond_signal(&awtLoaded_cv);299pthread_mutex_unlock(&awtLoaded_mutex);300}301302static int (*main_fptr)(int argc, char **argv) = NULL;303304/*305* Unwrap the arguments and re-run main()306*/307static void *apple_main (void *arg)308{309objc_registerThreadWithCollector();310311if (main_fptr == NULL) {312main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");313if (main_fptr == NULL) {314JLI_ReportErrorMessageSys("error locating main entrypoint\n");315exit(1);316}317}318319struct NSAppArgs *args = (struct NSAppArgs *) arg;320exit(main_fptr(args->argc, args->argv));321}322323static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}324325static void ParkEventLoop() {326// RunLoop needs at least one source, and 1e20 is pretty far into the future327CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);328CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);329CFRelease(t);330331// Park this thread in the main run loop.332int32_t result;333do {334result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e20, false);335} while (result != kCFRunLoopRunFinished);336}337338/*339* Mac OS X mandates that the GUI event loop run on very first thread of340* an application. This requires that we re-call Java's main() on a new341* thread, reserving the 'main' thread for Cocoa.342*/343static void MacOSXStartup(int argc, char *argv[]) {344// Thread already started?345static jboolean started = false;346if (started) {347return;348}349started = true;350351// Hand off arguments352struct NSAppArgs args;353args.argc = argc;354args.argv = argv;355356// Fire up the main thread357pthread_t main_thr;358if (pthread_create(&main_thr, NULL, &apple_main, &args) != 0) {359JLI_ReportErrorMessageSys("Could not create main thread: %s\n", strerror(errno));360exit(1);361}362if (pthread_detach(main_thr)) {363JLI_ReportErrorMessageSys("pthread_detach() failed: %s\n", strerror(errno));364exit(1);365}366367ParkEventLoop();368}369370void371CreateExecutionEnvironment(int *pargc, char ***pargv,372char jrepath[], jint so_jrepath,373char jvmpath[], jint so_jvmpath,374char jvmcfg[], jint so_jvmcfg) {375/*376* First, determine if we are running the desired data model. If we377* are running the desired data model, all the error messages378* associated with calling GetJREPath, ReadKnownVMs, etc. should be379* output. However, if we are not running the desired data model,380* some of the errors should be suppressed since it is more381* informative to issue an error message based on whether or not the382* os/processor combination has dual mode capabilities.383*/384jboolean jvmpathExists;385386/* Compute/set the name of the executable */387SetExecname(*pargv);388389/* Check data model flags, and exec process, if needed */390{391char *arch = (char *)GetArch(); /* like sparc or sparcv9 */392char * jvmtype = NULL;393int argc = *pargc;394char **argv = *pargv;395int running = CURRENT_DATA_MODEL;396397int wanted = running; /* What data mode is being398asked for? Current model is399fine unless another model400is asked for */401402char** newargv = NULL;403int newargc = 0;404405/*406* Starting in 1.5, all unix platforms accept the -d32 and -d64407* options. On platforms where only one data-model is supported408* (e.g. ia-64 Linux), using the flag for the other data model is409* an error and will terminate the program.410*/411412{ /* open new scope to declare local variables */413int i;414415newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*));416newargv[newargc++] = argv[0];417418/* scan for data model arguments and remove from argument list;419last occurrence determines desired data model */420for (i=1; i < argc; i++) {421422if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) {423wanted = 64;424continue;425}426if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) {427wanted = 32;428continue;429}430newargv[newargc++] = argv[i];431432if (IsJavaArgs()) {433if (argv[i][0] != '-') continue;434} else {435if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) {436i++;437if (i >= argc) break;438newargv[newargc++] = argv[i];439continue;440}441if (argv[i][0] != '-') { i++; break; }442}443}444445/* copy rest of args [i .. argc) */446while (i < argc) {447newargv[newargc++] = argv[i++];448}449newargv[newargc] = NULL;450451/*452* newargv has all proper arguments here453*/454455argc = newargc;456argv = newargv;457}458459/* If the data model is not changing, it is an error if the460jvmpath does not exist */461if (wanted == running) {462/* Find out where the JRE is that we will be using. */463if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {464JLI_ReportErrorMessage(JRE_ERROR1);465exit(2);466}467JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",468jrepath, FILESEP, FILESEP, "", "");469/* Find the specified JVM type */470if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {471JLI_ReportErrorMessage(CFG_ERROR7);472exit(1);473}474475jvmpath[0] = '\0';476jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);477if (JLI_StrCmp(jvmtype, "ERROR") == 0) {478JLI_ReportErrorMessage(CFG_ERROR9);479exit(4);480}481482if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, wanted)) {483JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);484exit(4);485}486487/*488* Mac OS X requires the Cocoa event loop to be run on the "main"489* thread. Spawn off a new thread to run main() and pass490* this thread off to the Cocoa event loop.491*/492MacOSXStartup(argc, argv);493494/*495* we seem to have everything we need, so without further ado496* we return back, otherwise proceed to set the environment.497*/498return;499} else { /* do the same speculatively or exit */500#if defined(DUAL_MODE)501if (running != wanted) {502/* Find out where the JRE is that we will be using. */503if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) {504/* give up and let other code report error message */505JLI_ReportErrorMessage(JRE_ERROR2, wanted);506exit(1);507}508JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",509jrepath, FILESEP, FILESEP, "", "");510/*511* Read in jvm.cfg for target data model and process vm512* selection options.513*/514if (ReadKnownVMs(jvmcfg, JNI_TRUE) < 1) {515/* give up and let other code report error message */516JLI_ReportErrorMessage(JRE_ERROR2, wanted);517exit(1);518}519jvmpath[0] = '\0';520jvmtype = CheckJvmType(pargc, pargv, JNI_TRUE);521if (JLI_StrCmp(jvmtype, "ERROR") == 0) {522JLI_ReportErrorMessage(CFG_ERROR9);523exit(4);524}525526/* exec child can do error checking on the existence of the path */527jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), wanted);528}529#else /* ! DUAL_MODE */530JLI_ReportErrorMessage(JRE_ERROR2, wanted);531exit(1);532#endif /* DUAL_MODE */533}534{535char *newexec = execname;536JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");537(void) fflush(stdout);538(void) fflush(stderr);539/*540* Use posix_spawn() instead of execv() on Mac OS X.541* This allows us to choose which architecture the child process542* should run as.543*/544{545posix_spawnattr_t attr;546size_t unused_size;547pid_t unused_pid;548549#if defined(__i386__) || defined(__x86_64__)550cpu_type_t cpu_type[] = { (wanted == 64) ? CPU_TYPE_X86_64 : CPU_TYPE_X86,551(running== 64) ? CPU_TYPE_X86_64 : CPU_TYPE_X86 };552#else553cpu_type_t cpu_type[] = { CPU_TYPE_ANY };554#endif /* __i386 .. */555556posix_spawnattr_init(&attr);557posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);558posix_spawnattr_setbinpref_np(&attr, sizeof(cpu_type) / sizeof(cpu_type_t),559cpu_type, &unused_size);560561posix_spawn(&unused_pid, newexec, NULL, &attr, argv, environ);562}563JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);564565#if defined(DUAL_MODE)566if (running != wanted) {567JLI_ReportErrorMessage(JRE_ERROR5, wanted, running);568}569#endif /* DUAL_MODE */570}571exit(1);572}573}574575/*576* VM choosing is done by the launcher (java.c).577*/578static jboolean579GetJVMPath(const char *jrepath, const char *jvmtype,580char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)581{582struct stat s;583584if (JLI_StrChr(jvmtype, '/')) {585JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);586} else {587/*588* macosx client library is built thin, i386 only.589* 64 bit client requests must load server library590*/591const char *jvmtypeUsed = ((bitsWanted == 64) && (strcmp(jvmtype, "client") == 0)) ? "server" : jvmtype;592JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtypeUsed);593}594595JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);596597if (stat(jvmpath, &s) == 0) {598JLI_TraceLauncher("yes.\n");599return JNI_TRUE;600} else {601JLI_TraceLauncher("no.\n");602return JNI_FALSE;603}604}605606/*607* Find path to JRE based on .exe's location or registry settings.608*/609static jboolean610GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)611{612char libjava[MAXPATHLEN];613614if (GetApplicationHome(path, pathsize)) {615/* Is JRE co-located with the application? */616JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);617if (access(libjava, F_OK) == 0) {618return JNI_TRUE;619}620/* ensure storage for path + /jre + NULL */621if ((JLI_StrLen(path) + 4 + 1) > pathsize) {622JLI_TraceLauncher("Insufficient space to store JRE path\n");623return JNI_FALSE;624}625/* Does the app ship a private JRE in <apphome>/jre directory? */626JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);627if (access(libjava, F_OK) == 0) {628JLI_StrCat(path, "/jre");629JLI_TraceLauncher("JRE path is %s\n", path);630return JNI_TRUE;631}632}633634/* try to find ourselves instead */635Dl_info selfInfo;636dladdr(&GetJREPath, &selfInfo);637638char *realPathToSelf = realpath(selfInfo.dli_fname, path);639if (realPathToSelf != path) {640return JNI_FALSE;641}642643size_t pathLen = strlen(realPathToSelf);644if (pathLen == 0) {645return JNI_FALSE;646}647648const char lastPathComponent[] = "/lib/jli/libjli.dylib";649size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;650if (pathLen < sizeOfLastPathComponent) {651return JNI_FALSE;652}653654size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;655if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent)) {656realPathToSelf[indexOfLastPathComponent + 1] = '\0';657return JNI_TRUE;658}659660// If libjli.dylib is loaded from a macos bundle MacOS dir, find the JRE dir661// in ../Home.662const char altLastPathComponent[] = "/MacOS/libjli.dylib";663size_t sizeOfAltLastPathComponent = sizeof(altLastPathComponent) - 1;664if (pathLen < sizeOfLastPathComponent) {665return JNI_FALSE;666}667668size_t indexOfAltLastPathComponent = pathLen - sizeOfAltLastPathComponent;669if (0 == strncmp(realPathToSelf + indexOfAltLastPathComponent, altLastPathComponent, sizeOfAltLastPathComponent)) {670JLI_Snprintf(realPathToSelf + indexOfAltLastPathComponent, sizeOfAltLastPathComponent, "%s", "/Home/jre");671if (access(realPathToSelf, F_OK) == 0) {672return JNI_TRUE;673}674JLI_Snprintf(realPathToSelf + indexOfAltLastPathComponent, sizeOfAltLastPathComponent, "%s", "/Home");675if (access(realPathToSelf, F_OK) == 0) {676return JNI_TRUE;677}678}679680if (!speculative)681JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);682return JNI_FALSE;683}684685jboolean686LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)687{688Dl_info dlinfo;689void *libjvm;690691JLI_TraceLauncher("JVM path is %s\n", jvmpath);692693libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);694if (libjvm == NULL) {695JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);696JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());697return JNI_FALSE;698}699700ifn->CreateJavaVM = (CreateJavaVM_t)701dlsym(libjvm, "JNI_CreateJavaVM");702if (ifn->CreateJavaVM == NULL) {703JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());704return JNI_FALSE;705}706707ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)708dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");709if (ifn->GetDefaultJavaVMInitArgs == NULL) {710JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());711return JNI_FALSE;712}713714ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)715dlsym(libjvm, "JNI_GetCreatedJavaVMs");716if (ifn->GetCreatedJavaVMs == NULL) {717JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());718return JNI_FALSE;719}720721return JNI_TRUE;722}723724/*725* Compute the name of the executable726*727* In order to re-exec securely we need the absolute path of the728* executable. On Solaris getexecname(3c) may not return an absolute729* path so we use dladdr to get the filename of the executable and730* then use realpath to derive an absolute path. From Solaris 9731* onwards the filename returned in DL_info structure from dladdr is732* an absolute pathname so technically realpath isn't required.733* On Linux we read the executable name from /proc/self/exe.734* As a fallback, and for platforms other than Solaris and Linux,735* we use FindExecName to compute the executable name.736*/737const char*738SetExecname(char **argv)739{740char* exec_path = NULL;741{742Dl_info dlinfo;743int (*fptr)();744745fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");746if (fptr == NULL) {747JLI_ReportErrorMessage(DLL_ERROR3, dlerror());748return JNI_FALSE;749}750751if (dladdr((void*)fptr, &dlinfo)) {752char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);753if (resolved != NULL) {754exec_path = realpath(dlinfo.dli_fname, resolved);755if (exec_path == NULL) {756JLI_MemFree(resolved);757}758}759}760}761if (exec_path == NULL) {762exec_path = FindExecName(argv[0]);763}764execname = exec_path;765return exec_path;766}767768/*769* BSD's implementation of CounterGet()770*/771int64_t772CounterGet()773{774struct timeval tv;775gettimeofday(&tv, NULL);776return (tv.tv_sec * 1000000) + tv.tv_usec;777}778779780/* --- Splash Screen shared library support --- */781782static JavaVM* SetJavaVMValue()783{784JavaVM * jvm = NULL;785786// The handle is good for both the launcher and the libosxapp.dylib787void * handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);788if (handle) {789typedef JavaVM* (*JLI_GetJavaVMInstance_t)();790791JLI_GetJavaVMInstance_t JLI_GetJavaVMInstance =792(JLI_GetJavaVMInstance_t)dlsym(handle,793"JLI_GetJavaVMInstance");794if (JLI_GetJavaVMInstance) {795jvm = JLI_GetJavaVMInstance();796}797798if (jvm) {799typedef void (*OSXAPP_SetJavaVM_t)(JavaVM*);800801OSXAPP_SetJavaVM_t OSXAPP_SetJavaVM =802(OSXAPP_SetJavaVM_t)dlsym(handle, "OSXAPP_SetJavaVM");803if (OSXAPP_SetJavaVM) {804OSXAPP_SetJavaVM(jvm);805} else {806jvm = NULL;807}808}809810dlclose(handle);811}812813return jvm;814}815816static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");817818static void* hSplashLib = NULL;819820void* SplashProcAddress(const char* name) {821if (!hSplashLib) {822char jrePath[PATH_MAX];823if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) {824JLI_ReportErrorMessage(JRE_ERROR1);825return NULL;826}827828char splashPath[PATH_MAX];829const int ret = JLI_Snprintf(splashPath, sizeof(splashPath),830"%s/lib/%s", jrePath, SPLASHSCREEN_SO);831if (ret >= (int)sizeof(splashPath)) {832JLI_ReportErrorMessage(JRE_ERROR11);833return NULL;834}835if (ret < 0) {836JLI_ReportErrorMessage(JRE_ERROR13);837return NULL;838}839840hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);841// It's OK if dlopen() fails. The splash screen library binary file842// might have been stripped out from the JRE image to reduce its size843// (e.g. on embedded platforms).844845if (hSplashLib) {846if (!SetJavaVMValue()) {847dlclose(hSplashLib);848hSplashLib = NULL;849}850}851}852if (hSplashLib) {853void* sym = dlsym(hSplashLib, name);854return sym;855} else {856return NULL;857}858}859860void SplashFreeLibrary() {861if (hSplashLib) {862dlclose(hSplashLib);863hSplashLib = NULL;864}865}866867/*868* Block current thread and continue execution in a new thread869*/870int871ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {872int rslt;873pthread_t tid;874pthread_attr_t attr;875pthread_attr_init(&attr);876pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);877878if (stack_size > 0) {879pthread_attr_setstacksize(&attr, stack_size);880}881882if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {883void * tmp;884pthread_join(tid, &tmp);885rslt = (int)tmp;886} else {887/*888* Continue execution in current thread if for some reason (e.g. out of889* memory/LWP) a new thread can't be created. This will likely fail890* later in continuation as JNI_CreateJavaVM needs to create quite a891* few new threads, anyway, just give it a try..892*/893rslt = continuation(args);894}895896pthread_attr_destroy(&attr);897return rslt;898}899900void SetJavaLauncherPlatformProps() {901/* Linux only */902}903904jboolean905ServerClassMachine(void) {906return JNI_TRUE;907}908909static JavaVM* jvmInstance = NULL;910static jboolean sameThread = JNI_FALSE; /* start VM in current thread */911912/*913* Note there is a callback on this function from the splashscreen logic,914* this as well SetJavaVMValue() needs to be simplified.915*/916JavaVM*917JLI_GetJavaVMInstance()918{919return jvmInstance;920}921922void923RegisterThread()924{925objc_registerThreadWithCollector();926}927928static void929SetXDockArgForAWT(const char *arg)930{931char envVar[80];932if (strstr(arg, "-Xdock:name=") == arg) {933/*934* The APP_NAME_<pid> environment variable is used to pass935* an application name as specified with the -Xdock:name command936* line option from Java launcher code to the AWT code in order937* to assign this name to the app's dock tile on the Mac.938* The _<pid> part is added to avoid collisions with child processes.939*940* WARNING: This environment variable is an implementation detail and941* isn't meant for use outside of the core platform. The mechanism for942* passing this information from Java launcher to other modules may943* change drastically between update release, and it may even be944* removed or replaced with another mechanism.945*946* NOTE: It is used by SWT, and JavaFX.947*/948snprintf(envVar, sizeof(envVar), "APP_NAME_%d", getpid());949setenv(envVar, (arg + 12), 1);950}951952if (strstr(arg, "-Xdock:icon=") == arg) {953/*954* The APP_ICON_<pid> environment variable is used to pass955* an application icon as specified with the -Xdock:icon command956* line option from Java launcher code to the AWT code in order957* to assign this icon to the app's dock tile on the Mac.958* The _<pid> part is added to avoid collisions with child processes.959*960* WARNING: This environment variable is an implementation detail and961* isn't meant for use outside of the core platform. The mechanism for962* passing this information from Java launcher to other modules may963* change drastically between update release, and it may even be964* removed or replaced with another mechanism.965*966* NOTE: It is used by SWT, and JavaFX.967*/968snprintf(envVar, sizeof(envVar), "APP_ICON_%d", getpid());969setenv(envVar, (arg + 12), 1);970}971}972973static void974SetMainClassForAWT(JNIEnv *env, jclass mainClass) {975jclass classClass = NULL;976NULL_CHECK(classClass = FindBootStrapClass(env, "java/lang/Class"));977978jmethodID getCanonicalNameMID = NULL;979NULL_CHECK(getCanonicalNameMID = (*env)->GetMethodID(env, classClass, "getCanonicalName", "()Ljava/lang/String;"));980981jstring mainClassString = NULL;982NULL_CHECK(mainClassString = (*env)->CallObjectMethod(env, mainClass, getCanonicalNameMID));983984const char *mainClassName = NULL;985NULL_CHECK(mainClassName = (*env)->GetStringUTFChars(env, mainClassString, NULL));986987char envVar[80];988/*989* The JAVA_MAIN_CLASS_<pid> environment variable is used to pass990* the name of a Java class whose main() method is invoked by991* the Java launcher code to start the application, to the AWT code992* in order to assign the name to the Apple menu bar when the app993* is active on the Mac.994* The _<pid> part is added to avoid collisions with child processes.995*996* WARNING: This environment variable is an implementation detail and997* isn't meant for use outside of the core platform. The mechanism for998* passing this information from Java launcher to other modules may999* change drastically between update release, and it may even be1000* removed or replaced with another mechanism.1001*1002* NOTE: It is used by SWT, and JavaFX.1003*/1004snprintf(envVar, sizeof(envVar), "JAVA_MAIN_CLASS_%d", getpid());1005setenv(envVar, mainClassName, 1);10061007(*env)->ReleaseStringUTFChars(env, mainClassString, mainClassName);1008}10091010void1011SetXStartOnFirstThreadArg()1012{1013// XXX: BEGIN HACK1014// short circuit hack for <https://bugs.eclipse.org/bugs/show_bug.cgi?id=211625>1015// need a way to get AWT/Swing apps launched when spawned from Eclipse,1016// which currently has no UI to not pass the -XstartOnFirstThread option1017if (getenv("HACK_IGNORE_START_ON_FIRST_THREAD") != NULL) return;1018// XXX: END HACK10191020sameThread = JNI_TRUE;1021// Set a variable that tells us we started on the main thread.1022// This is used by the AWT during startup. (See awt.m)1023char envVar[80];1024snprintf(envVar, sizeof(envVar), "JAVA_STARTED_ON_FIRST_THREAD_%d", getpid());1025setenv(envVar, "1", 1);1026}10271028// MacOSX we may continue in the same thread1029int1030JVMInit(InvocationFunctions* ifn, jlong threadStackSize,1031int argc, char **argv,1032int mode, char *what, int ret) {1033if (sameThread) {1034JLI_TraceLauncher("In same thread\n");1035// need to block this thread against the main thread1036// so signals get caught correctly1037__block int rslt = 0;1038NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];1039{1040NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock: ^{1041JavaMainArgs args;1042args.argc = argc;1043args.argv = argv;1044args.mode = mode;1045args.what = what;1046args.ifn = *ifn;1047rslt = JavaMain(&args);1048}];10491050/*1051* We cannot use dispatch_sync here, because it blocks the main dispatch queue.1052* Using the main NSRunLoop allows the dispatch queue to run properly once1053* SWT (or whatever toolkit this is needed for) kicks off it's own NSRunLoop1054* and starts running.1055*/1056[op performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES];1057}1058[pool drain];1059return rslt;1060} else {1061return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);1062}1063}10641065/*1066* Note the jvmInstance must be initialized first before entering into1067* ShowSplashScreen, as there is a callback into the JLI_GetJavaVMInstance.1068*/1069void PostJVMInit(JNIEnv *env, jstring mainClass, JavaVM *vm) {1070jvmInstance = vm;1071SetMainClassForAWT(env, mainClass);1072CHECK_EXCEPTION_RETURN();1073ShowSplashScreen();1074}10751076jboolean1077ProcessPlatformOption(const char* arg)1078{1079if (JLI_StrCmp(arg, "-XstartOnFirstThread") == 0) {1080SetXStartOnFirstThreadArg();1081return JNI_TRUE;1082} else if (JLI_StrCCmp(arg, "-Xdock:") == 0) {1083SetXDockArgForAWT(arg);1084return JNI_TRUE;1085}1086// arguments we know not1087return JNI_FALSE;1088}108910901091