/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "java.h"
#include "jvm_md.h"
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "manifest_info.h"
#include "version_comp.h"
/* Support Cocoa event loop on the main thread */
#include <objc/objc-runtime.h>
#include <objc/objc-auto.h>
#include <errno.h>
#include <spawn.h>
struct NSAppArgs {
int argc;
char **argv;
};
/* FALLBACK avoids naming conflicts with system libraries
* (eg, ImageIO's libJPEG.dylib) */
/*
* If a processor / os combination has the ability to run binaries of
* models is supported, then DUAL_MODE is defined. MacOSX is a hybrid
* system in that, the universal library can contain all types of libraries
* appropriate library as requested.
*
* Notes:
* 1. VM. DUAL_MODE is disabled, and not supported, however, it is left here in
* for experimentation and perhaps enable it in the future.
* 2. At the time of this writing, the universal library contains only
* a server 64-bit server JVM.
* 3. "-client" command line option is supported merely as a command line flag,
* for, compatibility reasons, however, a server VM will be launched.
*/
/*
* Flowchart of launcher execs and options processing on unix
*
* The selection of the proper vm shared library to open depends on
* several classes of command line options, including vm "flavor"
* options (-client, -server) and the data model options, -d32 and
* -d64, as well as a version specification which may have come from
* the command line or from the manifest of an executable jar file.
* The vm selection options are not passed to the running
* virtual machine; they must be screened out by the launcher.
*
* The version specification (if any) is processed first by the
* platform independent routine SelectVersion. This may result in
* the exec of the specified launcher version.
*
* Now, in most cases,the launcher will dlopen the target libjvm.so. All
* required libraries are loaded by the runtime linker, using the known paths
* baked into the shared libraries at compile time. Therefore,
* in most cases, the launcher will only exec, if the data models are
* mismatched, and will not set any environment variables, regardless of the
* data models.
*
*
*
* Main
* (incoming argv)
* |
* \|/
* SelectVersion
* (selects the JRE version, note: not data model)
* |
* \|/
* CreateExecutionEnvironment
* (determines desired data model)
* |
* |
* \|/
* Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error)
* | |
* | |
* | \|/
* | YES
* | |
* | |
* | \|/
* | CheckJvmType
* | (removes -client, -server etc.)
* | |
* | |
* \|/ \|/
* YES Find the desired executable/library
* | |
* | |
* \|/ \|/
* CheckJvmType POINT A
* (removes -client, -server, etc.)
* |
* |
* \|/
* TranslateDashJArgs...
* (Prepare to pass args to vm)
* |
* |
* \|/
* ParseArguments
* (removes -d32 and -d64 if any,
* processes version options,
* creates argument list for vm,
* etc.)
* |
* |
* \|/
* POINT A
* |
* |
* \|/
* Path is desired JRE ? YES --> Have Desired Model ? NO --> Re-exec --> Main
* NO YES --> Continue
* |
* |
* \|/
* Paths have well known
* jvm paths ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main
* YES YES --> Continue
* |
* |
* \|/
* Does libjvm.so exist
* in any of them ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main
* YES YES --> Continue
* |
* |
* \|/
* Re-exec / Spawn
* |
* |
* \|/
* Main
*/
/* Store the name of the executable once computed */
/*
* execname accessor from other parts of platform dependent logic
*/
const char *
GetExecName() {
return execname;
}
const char *
{
switch(nbits) {
default:
return LIBARCHNAME;
}
}
/*
* Exports the JNI interface from libjli
*
* This allows client code to link against the .jre/.jdk bundles,
* and not worry about trying to pick a HotSpot to link against.
*
* Switching architectures is unsupported, since client code has
* made that choice before the JVM was requested.
*/
if (!gotJREPath) {
JLI_ReportErrorMessage("Failed to GetJREPath()");
return NULL;
}
if (preferredJVM == NULL) {
#if defined(__i386__)
preferredJVM = "client";
#elif defined(__x86_64__)
preferredJVM = "server";
#else
#error "Unknown architecture - needs definition"
#endif
}
jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
if (!gotJVMPath) {
JLI_ReportErrorMessage("Failed to GetJVMPath()");
return NULL;
}
if (!vmLoaded) {
JLI_ReportErrorMessage("Failed to LoadJavaVM()");
return NULL;
}
return sExportedJNIFunctions = fxns;
}
}
}
}
/*
*/
if (sPreferredJVMType != NULL) {
}
}
{
}
/*
* Unwrap the arguments and re-run main()
*/
{
JLI_ReportErrorMessageSys("error locating main entrypoint\n");
exit(1);
}
}
}
static void ParkEventLoop() {
// RunLoop needs at least one source, and 1e20 is pretty far into the future
CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
CFRelease(t);
// Park this thread in the main run loop.
do {
} while (result != kCFRunLoopRunFinished);
}
/*
* Mac OS X mandates that the GUI event loop run on very first thread of
* an application. This requires that we re-call Java's main() on a new
* thread, reserving the 'main' thread for Cocoa.
*/
// Thread already started?
if (started) {
return;
}
started = true;
// Hand off arguments
// Fire up the main thread
exit(1);
}
if (pthread_detach(main_thr)) {
exit(1);
}
}
void
/*
* First, determine if we are running the desired data model. If we
* are running the desired data model, all the error messages
* associated with calling GetJREPath, ReadKnownVMs, etc. should be
* output. However, if we are not running the desired data model,
* some of the errors should be suppressed since it is more
* informative to issue an error message based on whether or not the
*/
SetExecname(*pargv);
/* Check data model flags, and exec process, if needed */
{
asked for? Current model is
fine unless another model
is asked for */
int newargc = 0;
/*
* Starting in 1.5, all unix platforms accept the -d32 and -d64
* options. On platforms where only one data-model is supported
* (e.g. ia-64 Linux), using the flag for the other data model is
* an error and will terminate the program.
*/
{ /* open new scope to declare local variables */
int i;
/* scan for data model arguments and remove from argument list;
last occurrence determines desired data model */
for (i=1; i < argc; i++) {
wanted = 64;
continue;
}
wanted = 32;
continue;
}
if (IsJavaArgs()) {
if (argv[i][0] != '-') continue;
} else {
i++;
if (i >= argc) break;
continue;
}
if (argv[i][0] != '-') { i++; break; }
}
}
/* copy rest of args [i .. argc) */
while (i < argc) {
}
/*
* newargv has all proper arguments here
*/
}
/* If the data model is not changing, it is an error if the
jvmpath does not exist */
/* Find out where the JRE is that we will be using. */
exit(2);
}
/* Find the specified JVM type */
exit(1);
}
jvmpath[0] = '\0';
exit(4);
}
exit(4);
}
/*
* Mac OS X requires the Cocoa event loop to be run on the "main"
* thread. Spawn off a new thread to run main() and pass
* this thread off to the Cocoa event loop.
*/
/*
* we seem to have everything we need, so without further ado
* we return back, otherwise proceed to set the environment.
*/
return;
} else { /* do the same speculatively or exit */
#if defined(DUAL_MODE)
/* Find out where the JRE is that we will be using. */
/* give up and let other code report error message */
exit(1);
}
/*
* Read in jvm.cfg for target data model and process vm
* selection options.
*/
/* give up and let other code report error message */
exit(1);
}
jvmpath[0] = '\0';
exit(4);
}
/* exec child can do error checking on the existence of the path */
}
#else /* ! DUAL_MODE */
exit(1);
#endif /* DUAL_MODE */
}
{
JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");
/*
* Use posix_spawn() instead of execv() on Mac OS X.
* This allows us to choose which architecture the child process
* should run as.
*/
{
#if defined(__i386__) || defined(__x86_64__)
#else
#endif /* __i386 .. */
cpu_type, &unused_size);
}
#if defined(DUAL_MODE)
}
#endif /* DUAL_MODE */
}
exit(1);
}
}
/*
* VM choosing is done by the launcher (java.c).
*/
static jboolean
{
struct stat s;
} else {
/*
* macosx client library is built thin, i386 only.
* 64 bit client requests must load server library
*/
const char *jvmtypeUsed = ((bitsWanted == 64) && (strcmp(jvmtype, "client") == 0)) ? "server" : jvmtype;
}
JLI_TraceLauncher("yes.\n");
return JNI_TRUE;
} else {
JLI_TraceLauncher("no.\n");
return JNI_FALSE;
}
}
/*
* Find path to JRE based on .exe's location or registry settings.
*/
static jboolean
{
/* Is JRE co-located with the application? */
return JNI_TRUE;
}
/* Does the app ship a private JRE in <apphome>/jre directory? */
return JNI_TRUE;
}
}
/* try to find ourselves instead */
if (realPathToSelf != path) {
return JNI_FALSE;
}
if (pathLen == 0) {
return JNI_FALSE;
}
if (pathLen < sizeOfLastPathComponent) {
return JNI_FALSE;
}
if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) {
return JNI_TRUE;
}
if (!speculative)
return JNI_FALSE;
}
{
void *libjvm;
return JNI_FALSE;
}
return JNI_FALSE;
}
return JNI_FALSE;
}
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Compute the name of the executable
*
* In order to re-exec securely we need the absolute path of the
* executable. On Solaris getexecname(3c) may not return an absolute
* path so we use dladdr to get the filename of the executable and
* then use realpath to derive an absolute path. From Solaris 9
* onwards the filename returned in DL_info structure from dladdr is
* an absolute pathname so technically realpath isn't required.
* As a fallback, and for platforms other than Solaris and Linux,
* we use FindExecName to compute the executable name.
*/
const char*
{
{
int (*fptr)();
return JNI_FALSE;
}
}
}
}
}
}
return exec_path;
}
/*
* BSD's implementation of CounterGet()
*/
{
}
/* --- Splash Screen shared library support --- */
{
// The handle is good for both the launcher and the libosxapp.dylib
if (handle) {
"JLI_GetJavaVMInstance");
if (JLI_GetJavaVMInstance) {
jvm = JLI_GetJavaVMInstance();
}
if (jvm) {
if (OSXAPP_SetJavaVM) {
} else {
}
}
}
return jvm;
}
if (!hSplashLib) {
return NULL;
}
if (ret >= (int)sizeof(splashPath)) {
return NULL;
}
if (ret < 0) {
return NULL;
}
// It's OK if dlopen() fails. The splash screen library binary file
// might have been stripped out from the JRE image to reduce its size
// (e.g. on embedded platforms).
if (hSplashLib) {
if (!SetJavaVMValue()) {
hSplashLib = NULL;
}
}
}
if (hSplashLib) {
return sym;
} else {
return NULL;
}
}
void SplashFreeLibrary() {
if (hSplashLib) {
hSplashLib = NULL;
}
}
/*
* Block current thread and continue execution in a new thread
*/
int
int rslt;
if (stack_size > 0) {
}
void * tmp;
} else {
/*
* Continue execution in current thread if for some reason (e.g. out of
* later in continuation as JNI_CreateJavaVM needs to create quite a
* few new threads, anyway, just give it a try..
*/
}
return rslt;
}
void SetJavaLauncherPlatformProps() {
/* Linux only */
}
ServerClassMachine(void) {
return JNI_TRUE;
}
/*
* Note there is a callback on this function from the splashscreen logic,
* this as well SetJavaVMValue() needs to be simplified.
*/
{
return jvmInstance;
}
void
{
}
static void
{
/*
* The APP_NAME_<pid> environment variable is used to pass
* an application name as specified with the -Xdock:name command
* line option from Java launcher code to the AWT code in order
* to assign this name to the app's dock tile on the Mac.
* The _<pid> part is added to avoid collisions with child processes.
*
* WARNING: This environment variable is an implementation detail and
* isn't meant for use outside of the core platform. The mechanism for
* passing this information from Java launcher to other modules may
* change drastically between update release, and it may even be
* removed or replaced with another mechanism.
*
* NOTE: It is used by SWT, and JavaFX.
*/
}
/*
* The APP_ICON_<pid> environment variable is used to pass
* an application icon as specified with the -Xdock:icon command
* line option from Java launcher code to the AWT code in order
* to assign this icon to the app's dock tile on the Mac.
* The _<pid> part is added to avoid collisions with child processes.
*
* WARNING: This environment variable is an implementation detail and
* isn't meant for use outside of the core platform. The mechanism for
* passing this information from Java launcher to other modules may
* change drastically between update release, and it may even be
* removed or replaced with another mechanism.
*
* NOTE: It is used by SWT, and JavaFX.
*/
}
}
static void
NULL_CHECK(getCanonicalNameMID = (*env)->GetMethodID(env, classClass, "getCanonicalName", "()Ljava/lang/String;"));
/*
* The JAVA_MAIN_CLASS_<pid> environment variable is used to pass
* the name of a Java class whose main() method is invoked by
* the Java launcher code to start the application, to the AWT code
* in order to assign the name to the Apple menu bar when the app
* is active on the Mac.
* The _<pid> part is added to avoid collisions with child processes.
*
* WARNING: This environment variable is an implementation detail and
* isn't meant for use outside of the core platform. The mechanism for
* passing this information from Java launcher to other modules may
* change drastically between update release, and it may even be
* removed or replaced with another mechanism.
*
* NOTE: It is used by SWT, and JavaFX.
*/
}
void
{
// XXX: BEGIN HACK
// short circuit hack for <https://bugs.eclipse.org/bugs/show_bug.cgi?id=211625>
// which currently has no UI to not pass the -XstartOnFirstThread option
// XXX: END HACK
// Set a variable that tells us we started on the main thread.
// This is used by the AWT during startup. (See awt.m)
}
/* This class is made for performSelectorOnMainThread when java main
* should be launched on main thread.
* We cannot use dispatch_sync here, because it blocks the main dispatch queue
* which is used inside Cocoa
*/
int _returnValue;
}
- (int) getReturnValue;
@end
{
}
- (int) getReturnValue
{
return _returnValue;
}
@end
// MacOSX we may continue in the same thread
int
if (sameThread) {
JLI_TraceLauncher("In same thread\n");
// need to block this thread against the main thread
// so signals get caught correctly
int rslt;
{
}
return rslt;
} else {
}
}
/*
* Note the jvmInstance must be initialized first before entering into
* ShowSplashScreen, as there is a callback into the JLI_GetJavaVMInstance.
*/
jvmInstance = vm;
}
{
return JNI_TRUE;
return JNI_TRUE;
}
// arguments we know not
return JNI_FALSE;
}