8340114: Remove outdated SelectVersion() function from the launcher and update the code comments explaining the code flow

Reviewed-by: dholmes, alanb
This commit is contained in:
Jaikiran Pai 2024-09-24 01:47:57 +00:00
parent c8ae848049
commit 40cde003e8
8 changed files with 260 additions and 642 deletions

View file

@ -60,115 +60,79 @@ struct NSAppArgs {
#define LD_LIBRARY_PATH "DYLD_FALLBACK_LIBRARY_PATH"
/*
* If a processor / os combination has the ability to run binaries of
* two data models and cohabitation of jre/jdk bits with both data
* models is supported, then DUAL_MODE is defined. MacOSX is a hybrid
* system in that, the universal library can contain all types of libraries
* 32/64 and client/server, thus the spawn is capable of linking with the
* appropriate library as requested.
* Following is the high level flow of the launcher
* code residing in the common java.c and this
* macosx specific java_md_macosx file:
*
* 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
* - JLI_Launch function, which is the entry point
* to the launcher, calls CreateExecutionEnvironment.
*
* 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.
* - CreateExecutionEnvironment does the following
* (not necessarily in this order):
* - determines the relevant JVM type that needs
* to be ultimately created
* - determines the path and asserts the presence
* of libjava and relevant libjvm library
* - removes any JVM selection options from the
* arguments that were passed to 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.
* - CreateExecutionEnvironment then creates a new
* thread, within the same process, to launch the
* application's main() Java method and parks the
* current thread, on which CreateExecutionEnvironment
* was invoked, in Apple's Cocoa event loop. Before
* doing so, CreateExecutionEnvironment maintains a
* state flag to keep note that a new thread has
* been spawned.
*
* 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.
* - The newly created thread (in which the application's
* main() method will ultimately run) starts right from
* the beginning of the current process' main function,
* which effectively means that JLI_Launch is re-invoked
* on this new thread and the same above sequence of code
* flow repeats again. During this "recursive" call, when
* at the point of creating a new thread in
* CreateExecutionEnvironment, the CreateExecutionEnvironment
* will check for the state flag to see if a new thread
* has already been spawned and upon noticing that it
* has, it will skip spawning any more threads and will
* return back from CreateExecutionEnvironment.
*
* - The control returns back from CreateExecutionEnvironment
* to JLI_Launch, and the thread on which the control
* returns is the thread on which the application's main()
* Java method will be invoked.
*
* - JLI_Launch then invokes LoadJavaVM which dlopen()s the
* JVM library and asserts the presence of JNI Invocation
* Functions "JNI_CreateJavaVM", "JNI_GetDefaultJavaVMInitArgs"
* and "JNI_GetCreatedJavaVMs" in that library. It then sets
* internal function pointers in the launcher to point to
* those functions.
*
* Main
* (incoming argv)
* |
* \|/
* 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
* (processes version options,
* creates argument list for vm,
* etc.)
* |
* |
* \|/
* POINT A
* |
* |
* \|/
* Path is desired JRE ? YES --> Continue
* NO
* |
* |
* \|/
* Paths have well known
* jvm paths ? --> NO --> Continue
* YES
* |
* |
* \|/
* Does libjvm.so exist
* in any of them ? --> NO --> Continue
* YES
* |
* |
* \|/
* Re-exec / Spawn
* |
* |
* \|/
* Main
* - JLI_Launch then translates any -J options by invoking
* TranslateApplicationArgs.
*
* - JLI_Launch then invokes ParseArguments to parse/process
* the launcher arguments.
*
* - JLI_Launch then ultimately calls JVMInit.
*
* - JVMInit then invokes JavaMain.
*
* - JavaMain, before launching the application, invokes
* PostJVMInit.
*
* - PostJVMInit invokes ShowSplashScreen which displays
* a splash screen for the application, if applicable.
*
* - Control then returns back from PostJVMInit into
* JavaMain, which then loads the application's main
* class and invokes the relevant main() Java method.
*
* - JavaMain then returns back an integer result which
* then gets propagated as a return value all the way
* out of the JLI_Launch function.
*/
/* Store the name of the executable once computed */

View file

@ -103,9 +103,6 @@
#define JRE_ERROR12 "Error: Exec of %s failed"
#define JRE_ERROR13 "Error: String processing operation failed"
#define SPC_ERROR1 "Error: Specifying an alternate JDK/JRE version is no longer supported.\n The use of the flag '-version:' is no longer valid.\n Please download and execute the appropriate version."
#define SPC_ERROR2 "Error: Specifying an alternate JDK/JRE is no longer supported.\n The related flags -jre-restrict-search | -jre-no-restrict-search are also no longer valid."
#define DLL_ERROR1 "Error: dl failure on line %d"
#define DLL_ERROR2 "Error: failed %s, because %s"
#define DLL_ERROR3 "Error: could not find executable %s"

View file

@ -36,18 +36,13 @@
* One job of the launcher is to remove command line options which the
* vm does not understand and will not process. These options include
* options which select which style of vm is run (e.g. -client and
* -server) as well as options which select the data model to use.
* -server).
* Additionally, for tools which invoke an underlying vm "-J-foo"
* options are turned into "-foo" options to the vm. This option
* filtering is handled in a number of places in the launcher, some of
* it in machine-dependent code. In this file, the function
* CheckJvmType removes vm style options and TranslateApplicationArgs
* removes "-J" prefixes. The CreateExecutionEnvironment function processes
* and removes -d<n> options. On unix, there is a possibility that the running
* data model may not match to the desired data model, in this case an exec is
* required to start the desired model. If the data models match, then
* ParseArguments will remove the -d<n> flags. If the data models do not match
* the CreateExecutionEnviroment will remove the -d<n> flags.
* removes "-J" prefixes.
*/
@ -55,11 +50,12 @@
#include "java.h"
#include "jni.h"
#include "stdbool.h"
/*
* A NOTE TO DEVELOPERS: For performance reasons it is important that
* the program image remain relatively small until after SelectVersion
* CreateExecutionEnvironment have finished their possibly recursive
* the program image remain relatively small until after
* CreateExecutionEnvironment has finished its possibly recursive
* processing. Watch everything, but resist all temptations to use Java
* interfaces.
*/
@ -88,10 +84,10 @@ static jboolean _wc_enabled = JNI_FALSE;
static jboolean dumpSharedSpaces = JNI_FALSE; /* -Xshare:dump */
/*
* Entries for splash screen environment variables.
* putenv is performed in SelectVersion. We need
* them in memory until UnsetEnv, so they are made static
* global instead of auto local.
* Values that will be stored into splash screen environment variables.
* putenv is performed to set _JAVA_SPLASH_FILE and _JAVA_SPLASH_JAR
* with these values. We need them in memory until UnsetEnv in
* ShowSplashScreen, so they are made static global instead of auto local.
*/
static char* splash_file_entry = NULL;
static char* splash_jar_entry = NULL;
@ -110,14 +106,14 @@ static jboolean IsJavaArgs();
static void SetJavaLauncherProp();
static void SetClassPath(const char *s);
static void SetMainModule(const char *s);
static void SelectVersion(int argc, char **argv, char **main_class);
static jboolean ParseArguments(int *pargc, char ***pargv,
int *pmode, char **pwhat,
int *pret, const char *jrepath);
int *pret);
static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv,
InvocationFunctions *ifn);
static jstring NewPlatformString(JNIEnv *env, char *s);
static jclass LoadMainClass(JNIEnv *env, int mode, char *name);
static void SetupSplashScreenEnvVars(const char *splash_file_path, char *jar_path);
static jclass GetApplicationClass(JNIEnv *env);
static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv);
@ -240,7 +236,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */
{
int mode = LM_UNKNOWN;
char *what = NULL;
char *main_class = NULL;
int ret;
InvocationFunctions ifn;
jlong start = 0, end = 0;
@ -257,6 +252,10 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */
InitLauncher(javaw);
DumpState();
if (JLI_IsTraceLauncher()) {
char *env_in;
if ((env_in = getenv(MAIN_CLASS_ENV_ENTRY)) != NULL) {
printf("Launched through Multiple JRE (mJRE) support\n");
}
int i;
printf("Java args:\n");
for (i = 0; i < jargc ; i++) {
@ -269,18 +268,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */
AddOption("-Dsun.java.launcher.diag=true", NULL);
}
/*
* SelectVersion() has several responsibilities:
*
* 1) Disallow specification of another JRE. With 1.9, another
* version of the JRE cannot be invoked.
* 2) Allow for a JRE version to invoke JDK 1.9 or later. Since
* all mJRE directives have been stripped from the request but
* the pre 1.9 JRE [ 1.6 thru 1.8 ], it is as if 1.9+ has been
* invoked from the command line.
*/
SelectVersion(argc, argv, &main_class);
CreateExecutionEnvironment(&argc, &argv,
jrepath, sizeof(jrepath),
jvmpath, sizeof(jvmpath),
@ -323,7 +310,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */
/* Parse command line options; if the return value of
* ParseArguments is false, the program should exit.
*/
if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath)) {
if (!ParseArguments(&argc, &argv, &mode, &what, &ret)) {
return(ret);
}
@ -1078,167 +1065,6 @@ SetMainModule(const char *s)
AddOption(def, NULL);
}
/*
* The SelectVersion() routine ensures that an appropriate version of
* the JRE is running. The specification for the appropriate version
* is obtained from either the manifest of a jar file (preferred) or
* from command line options.
* The routine also parses splash screen command line options and
* passes on their values in private environment variables.
*/
static void
SelectVersion(int argc, char **argv, char **main_class)
{
char *arg;
char *operand;
int jarflag = 0;
int headlessflag = 0;
manifest_info info;
char *splash_file_name = NULL;
char *splash_jar_name = NULL;
char *env_in;
int res;
jboolean has_arg;
/*
* If the version has already been selected, set *main_class
* with the value passed through the environment (if any) and
* simply return.
*/
/*
* This environmental variable can be set by mJRE capable JREs
* [ 1.5 thru 1.8 ]. All other aspects of mJRE processing have been
* stripped by those JREs. This environmental variable allows 1.9+
* JREs to be started by these mJRE capable JREs.
* Note that mJRE directives in the jar manifest file would have been
* ignored for a JRE started by another JRE...
* .. skipped for JRE 1.5 and beyond.
* .. not even checked for pre 1.5.
*/
if ((env_in = getenv(ENV_ENTRY)) != NULL) {
if (*env_in != '\0')
*main_class = JLI_StringDup(env_in);
return;
}
/*
* Scan through the arguments for options relevant to multiple JRE
* support. Multiple JRE support existed in JRE versions 1.5 thru 1.8.
*
* This capability is no longer available with JRE versions 1.9 and later.
* These command line options are reported as errors.
*/
argc--;
argv++;
while (argc > 0 && *(arg = *argv) == '-') {
has_arg = IsOptionWithArgument(argc, argv);
if (JLI_StrCCmp(arg, "-version:") == 0) {
JLI_ReportErrorMessage(SPC_ERROR1);
} else if (JLI_StrCmp(arg, "-jre-restrict-search") == 0) {
JLI_ReportErrorMessage(SPC_ERROR2);
} else if (JLI_StrCmp(arg, "-jre-no-restrict-search") == 0) {
JLI_ReportErrorMessage(SPC_ERROR2);
} else {
if (JLI_StrCmp(arg, "-jar") == 0)
jarflag = 1;
if (IsWhiteSpaceOption(arg)) {
if (has_arg) {
argc--;
argv++;
arg = *argv;
}
}
/*
* Checking for headless toolkit option in the some way as AWT does:
* "true" means true and any other value means false
*/
if (JLI_StrCmp(arg, "-Djava.awt.headless=true") == 0) {
headlessflag = 1;
} else if (JLI_StrCCmp(arg, "-Djava.awt.headless=") == 0) {
headlessflag = 0;
} else if (JLI_StrCCmp(arg, "-splash:") == 0) {
splash_file_name = arg+8;
}
}
argc--;
argv++;
}
if (argc <= 0) { /* No operand? Possibly legit with -[full]version */
operand = NULL;
} else {
argc--;
operand = *argv++;
}
/*
* If there is a jar file, read the manifest. If the jarfile can't be
* read, the manifest can't be read from the jar file, or the manifest
* is corrupt, issue the appropriate error messages and exit.
*
* Even if there isn't a jar file, construct a manifest_info structure
* containing the command line information. It's a convenient way to carry
* this data around.
*/
if (jarflag && operand) {
if ((res = JLI_ParseManifest(operand, &info)) != 0) {
if (res == -1)
JLI_ReportErrorMessage(JAR_ERROR2, operand);
else
JLI_ReportErrorMessage(JAR_ERROR3, operand);
exit(1);
}
/*
* Command line splash screen option should have precedence
* over the manifest, so the manifest data is used only if
* splash_file_name has not been initialized above during command
* line parsing
*/
if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) {
splash_file_name = info.splashscreen_image_file_name;
splash_jar_name = operand;
}
} else {
info.manifest_version = NULL;
info.main_class = NULL;
info.jre_version = NULL;
info.jre_restrict_search = 0;
}
/*
* Passing on splash screen info in environment variables
*/
if (splash_file_name && !headlessflag) {
splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=")+JLI_StrLen(splash_file_name)+1);
JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "=");
JLI_StrCat(splash_file_entry, splash_file_name);
putenv(splash_file_entry);
}
if (splash_jar_name && !headlessflag) {
splash_jar_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY "=")+JLI_StrLen(splash_jar_name)+1);
JLI_StrCpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "=");
JLI_StrCat(splash_jar_entry, splash_jar_name);
putenv(splash_jar_entry);
}
/*
* "Valid" returns (other than unrecoverable errors) follow. Set
* main_class as a side-effect of this routine.
*/
if (info.main_class != NULL)
*main_class = JLI_StringDup(info.main_class);
if (info.jre_version == NULL) {
JLI_FreeManifest();
return;
}
}
/*
* Test if the current argv is an option, i.e. with a leading `-`
* and followed with an argument without a leading `-`.
@ -1325,12 +1151,14 @@ GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) {
static jboolean
ParseArguments(int *pargc, char ***pargv,
int *pmode, char **pwhat,
int *pret, const char *jrepath)
int *pret)
{
int argc = *pargc;
char **argv = *pargv;
int mode = LM_UNKNOWN;
char *arg = NULL;
bool headless = false;
char *splash_file_path = NULL; // value of "-splash:" option
*pret = 0;
@ -1492,7 +1320,7 @@ ParseArguments(int *pargc, char ***pargv,
snprintf(tmp, tmpSize, "-X%s", arg + 1); /* skip '-' */
AddOption(tmp, NULL);
} else if (JLI_StrCCmp(arg, "-splash:") == 0) {
; /* Ignore machine independent options already handled */
splash_file_path = arg + 8;
} else if (JLI_StrCmp(arg, "--disable-@files") == 0) {
; /* Ignore --disable-@files option already handled */
} else if (ProcessPlatformOption(arg)) {
@ -1501,6 +1329,14 @@ ParseArguments(int *pargc, char ***pargv,
/* java.class.path set on the command line */
if (JLI_StrCCmp(arg, "-Djava.class.path=") == 0) {
_have_classpath = JNI_TRUE;
} else if (JLI_StrCmp(arg, "-Djava.awt.headless=true") == 0) {
/*
* Checking for headless toolkit option in the same way as AWT does:
* "true" means true and any other value means false
*/
headless = true;
} else if (JLI_StrCCmp(arg, "-Djava.awt.headless=") == 0) {
headless = false;
}
AddOption(arg, NULL);
}
@ -1551,9 +1387,82 @@ ParseArguments(int *pargc, char ***pargv,
*pmode = mode;
if (!headless) {
char *jar_path = NULL;
if (mode == LM_JAR) {
jar_path = *pwhat;
}
// Not in headless mode. We now set a couple of env variables that
// will be used later by ShowSplashScreen().
SetupSplashScreenEnvVars(splash_file_path, jar_path);
}
return JNI_TRUE;
}
/*
* Sets the relevant environment variables that are subsequently used by
* the ShowSplashScreen() function. The splash_file_path and jar_path parameters
* are used to determine which environment variables to set.
* The splash_file_path is the value that was provided to the "-splash:" option
* when launching java. It may be null, which implies the "-splash:" option wasn't used.
* The jar_path is the value that was provided to the "-jar" option when launching java.
* It too may be null, which implies the "-jar" option wasn't used.
*/
static void
SetupSplashScreenEnvVars(const char *splash_file_path, char *jar_path) {
// Command line specified "-splash:" takes priority over manifest one.
if (splash_file_path) {
// We set up the splash file name as a env variable which then gets
// used when showing the splash screen in ShowSplashScreen().
// create the string of the form _JAVA_SPLASH_FILE=<val>
splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=")
+ JLI_StrLen(splash_file_path) + 1);
JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "=");
JLI_StrCat(splash_file_entry, splash_file_path);
putenv(splash_file_entry);
return;
}
if (!jar_path) {
// no jar to look into for "SplashScreen-Image" manifest attribute
return;
}
// parse the jar's manifest to find any "SplashScreen-Image"
int res = 0;
manifest_info info;
if ((res = JLI_ParseManifest(jar_path, &info)) != 0) {
JLI_FreeManifest(); // cleanup any manifest structure
if (res == -1) {
JLI_ReportErrorMessage(JAR_ERROR2, jar_path);
} else {
JLI_ReportErrorMessage(JAR_ERROR3, jar_path);
}
exit(1);
}
if (!info.splashscreen_image_file_name) {
JLI_FreeManifest(); // cleanup the manifest structure
// no "SplashScreen-Image" in jar's manifest
return;
}
// The jar's manifest had a "Splashscreen-Image" specified. We set up the jar entry name
// and the jar file name as env variables which then get used when showing the splash screen
// in ShowSplashScreen().
// create the string of the form _JAVA_SPLASH_FILE=<val>
splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=")
+ JLI_StrLen(info.splashscreen_image_file_name) + 1);
JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "=");
JLI_StrCat(splash_file_entry, info.splashscreen_image_file_name);
putenv(splash_file_entry);
// create the string of the form _JAVA_SPLASH_JAR=<val>
splash_jar_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY "=") + JLI_StrLen(jar_path) + 1);
JLI_StrCpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "=");
JLI_StrCat(splash_jar_entry, jar_path);
putenv(splash_jar_entry);
JLI_FreeManifest(); // cleanup the manifest structure
}
/*
* Initializes the Java Virtual Machine. Also frees options array when
* finished.
@ -2340,7 +2249,7 @@ ShowSplashScreen()
* Done with all command line processing and potential re-execs so
* clean up the environment.
*/
(void)UnsetEnv(ENV_ENTRY);
(void)UnsetEnv(MAIN_CLASS_ENV_ENTRY);
(void)UnsetEnv(SPLASH_FILE_ENV_ENTRY);
(void)UnsetEnv(SPLASH_JAR_ENV_ENTRY);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -51,23 +51,19 @@
#define CURRENT_DATA_MODEL (CHAR_BIT * sizeof(void*))
/*
* The following environment variable is used to influence the behavior
* of the jre exec'd through the SelectVersion routine. The command line
* options which specify the version are not passed to the exec'd version,
* because that jre may be an older version which wouldn't recognize them.
* This environment variable is known to this (and later) version and serves
* to suppress the version selection code. This is not only for efficiency,
* but also for correctness, since any command line options have been
* removed which would cause any value found in the manifest to be used.
* This would be incorrect because the command line options are defined
* to take precedence.
*
* The value associated with this environment variable is the MainClass
* name from within the executable jar file (if any). This is strictly a
* performance enhancement to avoid re-reading the jar file manifest.
*
* Older versions of java launcher used to support JRE version selection - specifically,
* the java launcher in JDK 1.8 can be used to launch a java application using a different
* java runtime (older, newer or same version JRE installed at a different location) than
* the one the launcher belongs to.
* That support was discontinued starting JDK 9. However, the JDK 8 launcher can still
* be started with JRE version selection options to launch Java runtimes greater than JDK 8.
* In such cases, the JDK 8 launcher when exec()ing the JDK N launcher, will set and propagate
* the _JAVA_VERSION_SET environment variable. The value of this environment variable is the
* Main-Class name from within the executable jar file (if any).
* The java launcher in the current version of the JDK doesn't use this environment variable
* in any way other than merely using it in debug logging.
*/
#define ENV_ENTRY "_JAVA_VERSION_SET"
#define MAIN_CLASS_ENV_ENTRY "_JAVA_VERSION_SET"
#define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE"
#define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR"

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -167,10 +167,6 @@ typedef struct zentry { /* Zip file entry */
* Java launcher).
*/
typedef struct manifest_info { /* Interesting fields from the Manifest */
char *manifest_version; /* Manifest-Version string */
char *main_class; /* Main-Class entry */
char *jre_version; /* Appropriate J2SE release spec */
char jre_restrict_search; /* Restricted JRE search */
char *splashscreen_image_file_name; /* splashscreen image file */
} manifest_info;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -594,10 +594,6 @@ JLI_ParseManifest(char *jarfile, manifest_info *info)
)) == -1) {
return (-1);
}
info->manifest_version = NULL;
info->main_class = NULL;
info->jre_version = NULL;
info->jre_restrict_search = 0;
info->splashscreen_image_file_name = NULL;
if ((rc = find_file(fd, &entry, manifest_name)) != 0) {
close(fd);
@ -610,17 +606,7 @@ JLI_ParseManifest(char *jarfile, manifest_info *info)
}
lp = manifest;
while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) {
if (JLI_StrCaseCmp(name, "Manifest-Version") == 0) {
info->manifest_version = value;
} else if (JLI_StrCaseCmp(name, "Main-Class") == 0) {
info->main_class = value;
} else if (JLI_StrCaseCmp(name, "JRE-Version") == 0) {
/*
* Manifest specification overridden by command line option
* so we will silently override there with no specification.
*/
info->jre_version = 0;
} else if (JLI_StrCaseCmp(name, "Splashscreen-Image") == 0) {
if (JLI_StrCaseCmp(name, "Splashscreen-Image") == 0) {
info->splashscreen_image_file_name = value;
}
}

View file

@ -52,102 +52,86 @@
#endif
/*
* Flowchart of launcher execs and options processing on unix
* Following is the high level flow of the launcher
* code residing in the common java.c and this
* unix specific java_md file:
*
* The selection of the proper vm shared library to open depends on
* several classes of command line options, including vm "flavor"
* options (-client, -server).
* The vm selection options are not passed to the running
* virtual machine; they must be screened out by the launcher.
* - JLI_Launch function, which is the entry point
* to the launcher, calls CreateExecutionEnvironment.
*
* 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.
* - CreateExecutionEnvironment does the following
* (not necessarily in this order):
* - determines the relevant JVM type that
* needs to be ultimately created
* - determines the path and asserts the presence
* of libjava and relevant libjvm library
* - removes any JVM selection options from the
* arguments that were passed to the launcher
*
* Previously the launcher modified the LD_LIBRARY_PATH appropriately for the
* desired data model path, regardless if data models matched or not. The
* launcher subsequently exec'ed the desired executable, in order to make the
* LD_LIBRARY_PATH path available, for the runtime linker.
* - CreateExecutionEnvironment then determines (by calling
* RequiresSetenv function) if LD_LIBRARY_PATH environment
* variable needs to be set/updated.
* - If LD_LIBRARY_PATH needs to be set/updated,
* then CreateExecutionEnvironment exec()s
* the current process with the appropriate value
* for LD_LIBRARY_PATH.
* - Else if LD_LIBRARY_PATH need not be set or
* updated, then CreateExecutionEnvironment
* returns back.
*
* Now, in most cases,the launcher will dlopen the target libjvm.so. All
* required libraries are loaded by the runtime linker, using the
* $RPATH/$ORIGIN 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.
* - If CreateExecutionEnvironment exec()ed the process
* in the previous step, then the code control for the
* process will again start from the process' entry
* point and JLI_Launch is thus re-invoked and the
* same above sequence of code flow repeats again.
* During this "recursive" call into CreateExecutionEnvironment,
* the implementation of the check for LD_LIBRARY_PATH
* will realize that no further exec() is required and
* the control will return back from CreateExecutionEnvironment.
*
* However, if the environment contains a LD_LIBRARY_PATH, this will cause the
* launcher to inspect the LD_LIBRARY_PATH. The launcher will check
* a. if the LD_LIBRARY_PATH's first component is the path to the desired
* libjvm.so
* b. if any other libjvm.so is found in any of the paths.
* If case b is true, then the launcher will set the LD_LIBRARY_PATH to the
* desired JRE and reexec, in order to propagate the environment.
* - The control returns back from CreateExecutionEnvironment
* to JLI_Launch.
*
* Main
* (incoming argv)
* |
* \|/
* CreateExecutionEnvironment
* (determines desired data model)
* |
* |
* \|/
* Have Desired Model ? --> NO --> Exit(with error)
* |
* |
* \|/
* YES
* |
* |
* \|/
* CheckJvmType
* (removes -client, -server, etc.)
* |
* |
* \|/
* TranslateDashJArgs...
* (Prepare to pass args to vm)
* |
* |
* \|/
* ParseArguments
* |
* |
* \|/
* RequiresSetenv
* Is LD_LIBRARY_PATH
* and friends set ? --> NO --> Continue
* YES
* |
* |
* \|/
* Path is desired JRE ? YES --> Continue
* NO
* |
* |
* \|/
* Paths have well known
* jvm paths ? --> NO --> Error/Exit
* YES
* |
* |
* \|/
* Does libjvm.so exist
* in any of them ? --> NO --> Continue
* YES
* |
* |
* \|/
* Set the LD_LIBRARY_PATH
* |
* |
* \|/
* Re-exec
* |
* |
* \|/
* Main
* - JLI_Launch then invokes LoadJavaVM which dlopen()s
* the JVM library and asserts the presence of
* JNI Invocation Functions "JNI_CreateJavaVM",
* "JNI_GetDefaultJavaVMInitArgs" and
* "JNI_GetCreatedJavaVMs" in that library. It then
* sets internal function pointers in the launcher to
* point to those functions.
*
* - JLI_Launch then translates any -J options by
* invoking TranslateApplicationArgs.
*
* - JLI_Launch then invokes ParseArguments to
* parse/process the launcher arguments.
*
* - JLI_Launch then ultimately calls JVMInit.
*
* - JVMInit invokes ShowSplashScreen which displays
* a splash screen for the application, if applicable.
*
* - JVMInit then creates a new thread (T2), in the
* current process, and invokes JavaMain function
* in that new thread. The current thread (T1) then
* waits for the newly launched thread (T2) to complete.
*
* - JavaMain function, in thread T2, before launching
* the application, invokes PostJVMInit.
*
* - PostJVMInit is a no-op and returns back.
*
* - Control then returns back from PostJVMInit into JavaMain,
* which then loads the application's main class and invokes
* the relevant main() Java method.
*
* - JavaMain, in thread T2, then returns back an integer
* result and thread T2 execution ends here.
*
* - The thread T1 in JVMInit, which is waiting on T2 to
* complete, receives the integer result and then propagates
* it as a return value all the way out of the
* JLI_Launch function.
*/
/* Store the name of the executable once computed */
@ -221,7 +205,7 @@ ContainsLibJVM(const char *env) {
}
/*
* Test whether the environment variable needs to be set, see flowchart.
* Test whether the LD_LIBRARY_PATH environment variable needs to be set.
*/
static jboolean
RequiresSetenv(const char *jvmpath) {

View file

@ -1,214 +0,0 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* 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.
*/
/**
* @test
* @bug 8067437
* @summary Verify Multiple JRE version support has been removed.
* @modules jdk.compiler
* jdk.zipfs
* @build TestHelper
* @run main MultipleJRERemoved
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
public class MultipleJRERemoved extends TestHelper {
public static final String VERSION_JAR = "version.jar";
public static final String PRINT_VERSION_CLASS = "PrintVersion";
private final File javaFile = new File(PRINT_VERSION_CLASS + ".java");
private final File clsFile = new File(PRINT_VERSION_CLASS + ".class");
private MultipleJRERemoved() {
}
/**
* @param args the command line arguments
* @throws java.io.FileNotFoundException
*/
public static void main(String[] args) throws Exception {
MultipleJRERemoved a = new MultipleJRERemoved();
a.run(args);
}
/**
* Check all combinations of flags: "-version:", "-jre-restrict-search", "-jre-no-restrict-search". Test expects to see errors.
*/
@Test
public void allFlagCombinations() throws IOException {
final Pattern newLine = Pattern.compile("\n");
createJar(Collections.emptyMap());
for (Flag flag1 : Flag.values()) {
for (Flag flag2 : Flag.values()) {
for (Flag flag3 : Flag.values()) {
List<Flag> flags = Stream.of(flag1, flag2, flag3)
.filter(f -> !Flag.EMPTY.equals(f))
.collect(Collectors.toList());
if (flags.size() == 0) continue;
List<String> flagValues = flags.stream()
.map(Flag::value)
.collect(Collectors.toList());
List<String> errorMessages = flags.stream()
.map(Flag::errorMessage)
.flatMap(newLine::splitAsStream)
.collect(Collectors.toList());
List<String> jarCmd = new ArrayList<>();
jarCmd.add(javaCmd);
jarCmd.addAll(flagValues);
jarCmd.add("-jar");
jarCmd.add("version.jar");
check(jarCmd, errorMessages);
List<String> cmd = new ArrayList<>();
cmd.add(javaCmd);
cmd.addAll(flagValues);
cmd.add(PRINT_VERSION_CLASS);
check(cmd, errorMessages);
}
}
}
}
private void check(List<String> cmd, List<String> errorMessages) {
TestResult tr = doExec(cmd.toArray(new String[cmd.size()]));
tr.checkNegative();
tr.isNotZeroOutput();
errorMessages.forEach(tr::contains);
if (!tr.testStatus) {
System.out.println(tr);
throw new RuntimeException("test case: failed\n" + cmd);
}
}
/**
* Verifies that java -help output doesn't contain information about "mJRE" flags.
*/
@Test
public void javaHelp() {
TestResult tr = doExec(javaCmd, "-help");
tr.checkPositive();
tr.isNotZeroOutput();
tr.notContains("-version:<value>");
tr.notContains("-jre-restrict-search");
tr.notContains("-jre-no-restrict-search");
tr.notContains("-no-jre-restrict-search"); //it's not a typo in flag name.
if (!tr.testStatus) {
System.out.println(tr);
throw new RuntimeException("Failed. java -help output contains obsolete flags.\n");
}
}
/**
* Verifies that java -jar version.jar output ignores "mJRE" manifest directives.
*/
@Test
public void manifestDirectives() throws IOException {
Map<String, String> manifest = new TreeMap<>();
manifest.put("JRE-Version", "1.8");
manifest.put("JRE-Restrict-Search", "1.8");
createJar(manifest);
TestResult tr = doExec(javaCmd, "-jar", VERSION_JAR);
tr.checkPositive();
tr.contains(System.getProperty("java.version"));
if (!tr.testStatus) {
System.out.println(tr);
throw new RuntimeException("Failed.\n");
}
}
private void emitFile() throws IOException {
List<String> scr = new ArrayList<>();
scr.add("public class PrintVersion {");
scr.add(" public static void main(String... args) {");
scr.add(" System.out.println(System.getProperty(\"java.version\"));");
scr.add(" }");
scr.add("}");
createFile(javaFile, scr);
compile(javaFile.getName());
}
private void createJar(Map<String, String> manifestAttributes) throws IOException {
emitFile();
Manifest manifest = new Manifest();
final Attributes mainAttributes = manifest.getMainAttributes();
mainAttributes.putValue("Manifest-Version", "1.0");
mainAttributes.putValue("Main-Class", PRINT_VERSION_CLASS);
manifestAttributes.forEach(mainAttributes::putValue);
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(VERSION_JAR), manifest)) {
jar.putNextEntry(new ZipEntry(PRINT_VERSION_CLASS + ".class"));
jar.write(Files.readAllBytes(clsFile.toPath()));
jar.closeEntry();
} finally {
javaFile.delete();
}
}
private enum Flag {
EMPTY("", ""),
VERSION("-version:1.9", "Error: Specifying an alternate JDK/JRE version is no longer supported.\n" +
"The use of the flag '-version:' is no longer valid.\n" +
"Please download and execute the appropriate version."),
JRE_RESTRICT_SEARCH("-jre-restrict-search", "Error: Specifying an alternate JDK/JRE is no longer supported.\n" +
"The related flags -jre-restrict-search | -jre-no-restrict-search are also no longer valid."),
JRE_NO_RESTRICT_SEARCH("-jre-no-restrict-search", "Error: Specifying an alternate JDK/JRE is no longer supported.\n" +
"The related flags -jre-restrict-search | -jre-no-restrict-search are also no longer valid.");
private final String flag;
private final String errorMessage;
Flag(String flag, String errorMessage) {
this.flag = flag;
this.errorMessage = errorMessage;
}
String value() {
return flag;
}
String errorMessage() {
return errorMessage;
}
}
}