--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javaruntimes/starterutils/src.linux/jvmstarterjni.cpp Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,447 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: This class is meant for starting the Linux JVM.
+*
+*/
+
+#include <string>
+#include <algorithm>
+
+#include "jvmstarterjni.h"
+
+#include "jvmargsmodifier.h"
+
+#include "runtimeexception.h"
+#include "logger.h"
+#include "javaoslayer.h"
+#include "dynamiclibloader.h"
+#include "javacommonutils.h"
+
+using namespace java::runtime;
+using namespace java::util;
+
+extern const wchar_t CLASS_PATH_SEPARATOR = L':';
+extern const char PATH_SEPARATOR_FROM = '\\';
+extern const char PATH_SEPARATOR_TO = '/';
+
+JvmStarter*
+JvmStarter::getJvmStarterInstance(const Configuration configuration,
+ const std::wstring& indetifier)
+{
+ JELOG2(EJavaRuntime);
+ return new JvmStarterJni(configuration, indetifier);
+}
+
+JvmStarter*
+JvmStarter::getJvmStarterInstance()
+{
+ JELOG2(EJavaRuntime);
+ return new JvmStarterJni();
+}
+
+JvmStarterJni::JvmStarterJni()
+{
+ JELOG2(EJavaRuntime);
+}
+
+JvmStarterJni::JvmStarterJni(const Configuration configuration,
+ const std::wstring& indetifier)
+{
+ JELOG2(EJavaRuntime);
+ mConfiguration = configuration;
+ mIdentifier = indetifier;
+
+ // In Linux the binary root varies depending on the user.
+ std::string rootStr;
+ JavaOsLayer::getResRoot(rootStr, false);
+ rootStr += "jsr/classes/common/";
+ mExtensionPath.assign(rootStr.begin(), rootStr.end());
+}
+
+
+JvmStarterJni::~JvmStarterJni()
+{
+ JELOG2(EJavaRuntime);
+}
+
+void JvmStarterJni::overrideOldHeapSize(int /*heapSize*/)
+{
+ // Not supported by the JVM
+ JELOG2(EJavaRuntime);
+}
+
+void JvmStarterJni::overrideNewHeapSize(int /*heapSize*/)
+{
+ // Not supported by the JVM
+ JELOG2(EJavaRuntime);
+}
+
+void JvmStarterJni::overrideNativeStackSize(int /*stackSize*/)
+{
+ // Not supported by the JVM
+ JELOG2(EJavaRuntime);
+}
+
+void JvmStarterJni::overrideJavaStackSize(int stackSize)
+{
+ JELOG2(EJavaRuntime);
+ std::wstring stackSizeStr = L"-Xss";
+ stackSizeStr += JavaCommonUtils::intToWstring(stackSize);
+ stackSizeStr += L"K";
+ mJvmArgs.push_back(stackSizeStr);
+}
+
+int JvmStarterJni::startJvm()
+{
+ JELOG2(EJavaRuntime);
+
+ // Set mJvmArgs container to contain all the JVM args and set mAppAndArgs
+ // to contain the main class and the arguments.
+ completeArgumentContainers();
+
+ // Give arguments to modifyJvmArguments for modification. Args
+ // are modified if the default empty implementation has been overridden
+ // by eclipsing the modifyJvmArguments dll.
+ modifyJvmArguments(mIdentifier, mJvmArgs, mAppAndArgs);
+
+ // Allocate space for the raw JVM args.
+ int rawJvmArgumentCount = mJvmArgs.size();
+ ScopedCharPointerArray rawJvmArgs(rawJvmArgumentCount);
+
+ // Adding the JVM args. Main class and applcation arguments are handled
+ // later.
+ int ind = 0;
+ for (JvmArgs_t::iterator jvmArgsIter = mJvmArgs.begin();
+ jvmArgsIter!= mJvmArgs.end();
+ ++jvmArgsIter)
+ {
+ // Do character conversion while adding the arguments.
+ rawJvmArgs.get()[ind++] = JavaCommonUtils::wstringToUtf8(*jvmArgsIter);
+ }
+ return startJvmInSeparateThread(rawJvmArgumentCount, rawJvmArgs.get());
+}
+
+int JvmStarterJni::startJvm(int argc, char** argv)
+{
+ JELOG2(EJavaRuntime);
+ // Allocate space for the raw JVM args. This will contain only
+ // JVM arguments. Main class and application arguments are handled
+ // differently.
+ ScopedCharPointerArray rawJvmArgs(argc);
+
+ // Assuming that in the beginning of the list there are JVM arguments and
+ // they start with '-'.
+ bool handlingArguments = true;
+
+ int argCount = 0;
+ for (int i = 0; i < argc; i++)
+ {
+ if (argv[i][0] != '-') // codescanner::accessArrayElementWithoutCheck2
+ {
+ // First non JVM argument was found.
+ handlingArguments = false;
+ }
+ if (handlingArguments)
+ {
+ if ((strcmp(argv[i], "-cp") == 0 || // codescanner::accessArrayElementWithoutCheck2
+ strcmp(argv[i], "-classpath") == 0) && // codescanner::accessArrayElementWithoutCheck2
+ (i + 1) < argc)
+ {
+ // There is class path available.
+ std::string cp("-Djava.class.path=");
+ cp += argv[i+1];
+ i++;
+ rawJvmArgs.get()[argCount] = strdup(cp.c_str());
+ }
+ else
+ {
+ // Normal JVM argument.
+ rawJvmArgs.get()[argCount] = strdup(argv[i]); // codescanner::accessArrayElementWithoutCheck2
+ }
+ argCount++;
+ }
+ else
+ {
+ // The first non JVM argument can be considered as main class.
+ // The rest of the arguments are arguments for the Java app.
+ mAppAndArgs.push_back(JavaCommonUtils::utf8ToWstring(argv[i])); // codescanner::accessArrayElementWithoutCheck2
+ }
+ }
+ return startJvmInSeparateThread(argCount, rawJvmArgs.get());
+}
+
+
+void* JvmStarterJni::javaThreadMain(void* arg)
+{
+ JELOG2(EJavaRuntime);
+ int result = -1;
+ JvmStarterJni* jniStarter = (reinterpret_cast<JvmStarterJni*>(arg));
+ try
+ {
+ result = jniStarter->startJvmImpl();
+ }
+ catch (RuntimeException& e)
+ {
+ ELOG1(EJavaRuntime, "JvmStarterJni::javaThreadMain() RuntimeException "
+ "catched in VM thread. %s", e.toString().c_str());
+ }
+ catch (java::util::ExceptionBase& e)
+ {
+ ELOG1(EJavaRuntime, "JvmStarterJni::javaThreadMain() ExceptionBase "
+ "catched in VM thread. %s", e.toString().c_str());
+ }
+ catch (std::exception& e)
+ {
+ ELOG1(EJavaRuntime, "JvmStarterJni::javaThreadMain() std::Exception "
+ "catched in VM thread. %s", e.what());
+ }
+ return reinterpret_cast<void*>(result);
+}
+
+int JvmStarterJni::startJvmInSeparateThread(int argc, char** argv)
+{
+ JELOG2(EJavaRuntime);
+
+ // Store the argc and argv into member variables in order be avaliable
+ // for the JVM starter thread.
+ mArgCount = argc;
+ mArgs = argv;
+ // return startJvmImpl(); This could be used to start the JVM into same
+ // thread.
+ pthread_t threadId;
+ void* result;
+
+ // Create the JVM thread.
+ pthread_create(&threadId, 0, javaThreadMain, this);
+
+ // Wait until the thread has died.
+ pthread_join(threadId, &result);
+ return reinterpret_cast<int>(result);
+}
+
+
+int JvmStarterJni::startJvmImpl()
+{
+ JELOG2(EJavaRuntime);
+
+ JavaVM* jvm; // Denotes a Java VM.
+ JNIEnv* env; // Pointer to native method interface.
+ JavaVMInitArgs vmArgs; // VM initialization arguments.
+ JavaVMOption vmOption;
+ vmOption.extraInfo = 0;
+
+ LOG(EJavaRuntime, EInfo, "VM args:");
+ JvmOptionArgs_t jvmOptions;
+ for (int i = 0; i < mArgCount; i++)
+ {
+ vmOption.optionString = mArgs[i];
+ jvmOptions.push_back(vmOption);
+ LOG1(EJavaRuntime, EInfo, " %s",mArgs[i]); // codescanner::accessArrayElementWithoutCheck2
+ }
+ vmArgs.version = JNI_VERSION_1_4;
+
+ // Initializing JavaVMInitArgs.
+ // Contiguity for std::vector<T> is mandated by the standard as long
+ // as T is not bool. [See 23.2.4./1].
+ vmArgs.options = &((jvmOptions)[0]); // codescanner::accessArrayElementWithoutCheck2
+ vmArgs.nOptions = jvmOptions.size();
+ vmArgs.ignoreUnrecognized = JNI_FALSE;
+
+ JavaOsLayer::startUpTrace("Starting VM()", -1, -1);
+
+ // Creating the JVM.
+ int res = JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &vmArgs);
+ LOG1(EJavaRuntime, EInfo, "JNI_CreateJavaVM() returned. st = %d", res);
+ if (res == 0)
+ {
+ // Converting the '.' to '/' in the main class
+ // (com.nokia.Foo -> com/nokia/Foo)
+ std::wstring& appMain = mAppAndArgs.front();
+ std::replace(appMain.begin(), appMain.end(), '.', '/');
+
+ // Convert the main class to UTF-8.
+ ScopedCharPointer main(JavaCommonUtils::wstringToUtf8(appMain));
+
+ // Find the main class.
+ jclass mainClass = env->FindClass(main.get());
+ LOG2(EJavaRuntime, EInfo, " mainClass (%s): %p", main.get(), mainClass);
+ if (mainClass != 0)
+ {
+ // Find method static void main(String[] args) from the main class.
+ jmethodID mainMethod = env->GetStaticMethodID(mainClass, "main",
+ "([Ljava/lang/String;)V");
+ LOG1(EJavaRuntime, EInfo, " mainMethod: %p", mainMethod);
+ if (mainMethod != 0)
+ {
+ // Call the method static void main().
+ env->CallStaticVoidMethod(mainClass, mainMethod,
+ getApplicationArguments(env));
+ LOG(EJavaRuntime, EInfo, " CallStaticVoidMethod returned");
+ }
+ else
+ {
+ std::string errorStr("Not able to find main() method.");
+ throw RuntimeException(errorStr,
+ __FILE__, __FUNCTION__, __LINE__);
+ }
+ }
+ else
+ {
+ std::string errorStr("Main class was not found.");
+ throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
+ }
+ jvm->DestroyJavaVM();
+ }
+ else
+ {
+ std::string errorStr("JNI_CreateJavaVM failed. Reason = .");
+ errorStr += JavaCommonUtils::intToString(res);
+ throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
+ }
+ return res;
+}
+
+
+void JvmStarterJni::completeArgumentContainers()
+{
+ JELOG2(EJavaRuntime);
+
+ // Set the used porting layer.
+ mJvmArgs.push_back(L"-Dcom.nokia.jvm.port=sun.JvmPortJ2se");
+
+ // Disable JIT, if requested.
+ if (mJitDisabled)
+ {
+ mJvmArgs.push_back(L"-Xint");
+ }
+
+ // Add the classpath.
+ if (mClassPath.length() > 0)
+ {
+ mClassPath.insert(0, L"-Djava.class.path=");
+ mJvmArgs.push_front(mClassPath);
+ LOG1(EJavaRuntime, EInfo, " mClassPath = %S", mClassPath.c_str());
+ }
+
+ // Add the extension classpath.
+ if (mExtensionPath.length() > 0)
+ {
+ mExtensionPath.insert(0, L"-Djava.ext.dirs=");
+ mJvmArgs.push_front(mExtensionPath);
+ LOG1(EJavaRuntime, EInfo, " mExtensionPath = %S",
+ mExtensionPath.c_str());
+ }
+
+ // Add the prepending boot classpath if set.
+ if (mBootClassPathPrepend.length() > 0)
+ {
+ std::wstring bcpp(L"-Xbootclasspath/p:");
+ bcpp += mBootClassPathPrepend;
+ mJvmArgs.push_front(bcpp);
+ LOG1(EJavaRuntime, EInfo, " bcpp = %S", bcpp.c_str());
+ }
+
+ // Add the appending boot classpath if set.
+ if (mBootClassPathAppend.length() > 0)
+ {
+ std::wstring bcpa(L"-Xbootclasspath/a:");
+ bcpa += mBootClassPathAppend;
+ mJvmArgs.push_front(bcpa);
+ LOG1(EJavaRuntime, EInfo, " bcpa = %S", bcpa.c_str());
+ }
+
+ std::wstring javaBinRoot;
+ std::string binRoot;
+ JavaOsLayer::getBinRoot(binRoot, false);
+ javaBinRoot.assign(binRoot.begin(), binRoot.end());
+
+ // Setting the java.library.path.
+ std::wstring jlp(L"-Djava.library.path=");
+ jlp += javaBinRoot;
+ jlp += L"lib";
+ mJvmArgs.push_front(jlp);
+ LOG1(EJavaRuntime, EInfo, " jlp = %S", jlp.c_str());
+
+ // Setting the java.home.
+ std::wstring jh = L"-Djava.home=";
+ const char* javaHome = getenv("JAVA_VM_HOME");
+ if (javaHome == 0)
+ {
+ throw RuntimeException("JAVA_VM_HOME not defined",
+ __FILE__, __FUNCTION__, __LINE__);
+ }
+ std::string jhs(javaHome);
+ jh.append(jhs.begin(), jhs.end());
+ mJvmArgs.push_front(jh);
+ LOG1(EJavaRuntime, EInfo, " jh = %S", jh.c_str());
+
+ // Define emma.properties to point to emma.properties file
+ // which is used when Java code coverage is measured.
+ std::wstring emma(L"-Demma.properties=");
+ emma += javaBinRoot;
+ emma += L"emma.properties";
+ mJvmArgs.push_front(emma);
+ LOG1(EJavaRuntime, EInfo, " emma = %S", emma.c_str());
+
+ // Add the main class.
+ mAppAndArgs.push_front(mMainClass);
+ LOG1(EJavaRuntime, EInfo, " mMainClass = %S", mMainClass.c_str());
+}
+
+jobjectArray JvmStarterJni::getApplicationArguments(JNIEnv* env)
+{
+ JELOG2(EJavaRuntime);
+ // When using JNI_CreateJavaVM to start the JVM the arguments for the
+ // Java application must be handled so that a jobjectArray is created
+ // to contain Java Strings created using jni APIs.
+
+ if (env == 0)
+ {
+ throw RuntimeException("JNIEnv was null",
+ __FILE__, __FUNCTION__, __LINE__);
+ }
+
+ // Create the jobjectArray. mAppAndArgs container contains the main
+ // class which must be taken into account.
+ jobjectArray array =
+ (jobjectArray)env->NewObjectArray(mAppAndArgs.size() - 1,
+ env->FindClass("java/lang/String"),
+ env->NewStringUTF(""));
+ LOG(EJavaRuntime, EInfo, " Application arguments:");
+ if (array != 0)
+ {
+ JvmArgs_t::iterator appAndArgsIter = mAppAndArgs.begin();
+ // Skip the main class.
+ ++appAndArgsIter;
+
+ int i = 0;
+
+ // Fill the object array with application arguments.
+ for (; appAndArgsIter!= mAppAndArgs.end(); ++appAndArgsIter)
+ {
+ ScopedCharPointer appArg(JavaCommonUtils::wstringToUtf8(*appAndArgsIter));
+ LOG1(EJavaRuntime, EInfo, " %s", appArg.get());
+ env->SetObjectArrayElement(array, i++,
+ env->NewStringUTF(appArg.get()));
+ }
+ }
+ else
+ {
+ throw RuntimeException("jobjectArray was null",
+ __FILE__, __FUNCTION__, __LINE__);
+ }
+ return array;
+}
+
+