javaruntimes/starterutils/src.linux/jvmstarterjni.cpp
branchRCL_3
changeset 18 9ac0a0a7da70
parent 17 0fd27995241b
child 19 71c436fe3ce0
equal deleted inserted replaced
17:0fd27995241b 18:9ac0a0a7da70
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  This class is meant for starting the Linux JVM.
       
    15 *
       
    16 */
       
    17 
       
    18 #include <string>
       
    19 #include <algorithm>
       
    20 
       
    21 #include "jvmstarterjni.h"
       
    22 
       
    23 #include "jvmargsmodifier.h"
       
    24 
       
    25 #include "runtimeexception.h"
       
    26 #include "logger.h"
       
    27 #include "javaoslayer.h"
       
    28 #include "dynamiclibloader.h"
       
    29 #include "javacommonutils.h"
       
    30 
       
    31 using namespace java::runtime;
       
    32 using namespace java::util;
       
    33 
       
    34 extern const wchar_t CLASS_PATH_SEPARATOR = L':';
       
    35 extern const char PATH_SEPARATOR_FROM  = '\\';
       
    36 extern const char PATH_SEPARATOR_TO    = '/';
       
    37 
       
    38 JvmStarter*
       
    39 JvmStarter::getJvmStarterInstance(const Configuration configuration,
       
    40                                   const std::wstring& indetifier)
       
    41 {
       
    42     JELOG2(EJavaRuntime);
       
    43     return  new JvmStarterJni(configuration, indetifier);
       
    44 }
       
    45 
       
    46 JvmStarter*
       
    47 JvmStarter::getJvmStarterInstance()
       
    48 {
       
    49     JELOG2(EJavaRuntime);
       
    50     return new JvmStarterJni();
       
    51 }
       
    52 
       
    53 JvmStarterJni::JvmStarterJni()
       
    54 {
       
    55     JELOG2(EJavaRuntime);
       
    56 }
       
    57 
       
    58 JvmStarterJni::JvmStarterJni(const Configuration configuration,
       
    59                              const std::wstring& indetifier)
       
    60 {
       
    61     JELOG2(EJavaRuntime);
       
    62     mConfiguration = configuration;
       
    63     mIdentifier = indetifier;
       
    64 
       
    65     // In Linux the binary root varies depending on the user.
       
    66     std::string rootStr;
       
    67     JavaOsLayer::getResRoot(rootStr, false);
       
    68     rootStr += "jsr/classes/common/";
       
    69     mExtensionPath.assign(rootStr.begin(), rootStr.end());
       
    70 }
       
    71 
       
    72 
       
    73 JvmStarterJni::~JvmStarterJni()
       
    74 {
       
    75     JELOG2(EJavaRuntime);
       
    76 }
       
    77 
       
    78 void JvmStarterJni::overrideOldHeapSize(int /*heapSize*/)
       
    79 {
       
    80     // Not supported by the JVM
       
    81     JELOG2(EJavaRuntime);
       
    82 }
       
    83 
       
    84 void JvmStarterJni::overrideNewHeapSize(int /*heapSize*/)
       
    85 {
       
    86     // Not supported by the JVM
       
    87     JELOG2(EJavaRuntime);
       
    88 }
       
    89 
       
    90 void JvmStarterJni::overrideNativeStackSize(int /*stackSize*/)
       
    91 {
       
    92     // Not supported by the JVM
       
    93     JELOG2(EJavaRuntime);
       
    94 }
       
    95 
       
    96 void JvmStarterJni::overrideJavaStackSize(int stackSize)
       
    97 {
       
    98     JELOG2(EJavaRuntime);
       
    99     std::wstring stackSizeStr = L"-Xss";
       
   100     stackSizeStr += JavaCommonUtils::intToWstring(stackSize);
       
   101     stackSizeStr += L"K";
       
   102     mJvmArgs.push_back(stackSizeStr);
       
   103 }
       
   104 
       
   105 int JvmStarterJni::startJvm()
       
   106 {
       
   107     JELOG2(EJavaRuntime);
       
   108 
       
   109     // Set mJvmArgs container to contain all the JVM args and set mAppAndArgs
       
   110     // to contain the main class and the arguments.
       
   111     completeArgumentContainers();
       
   112 
       
   113     // Give arguments to modifyJvmArguments for modification. Args
       
   114     // are modified if the default empty implementation has been overridden
       
   115     // by eclipsing the modifyJvmArguments dll.
       
   116     modifyJvmArguments(mIdentifier, mJvmArgs, mAppAndArgs);
       
   117 
       
   118     // Allocate space for the raw JVM args.
       
   119     int rawJvmArgumentCount = mJvmArgs.size();
       
   120     ScopedCharPointerArray rawJvmArgs(rawJvmArgumentCount);
       
   121 
       
   122     // Adding the JVM args. Main class and applcation arguments are handled
       
   123     // later.
       
   124     int ind = 0;
       
   125     for (JvmArgs_t::iterator jvmArgsIter = mJvmArgs.begin();
       
   126             jvmArgsIter!= mJvmArgs.end();
       
   127             ++jvmArgsIter)
       
   128     {
       
   129         // Do character conversion while adding the arguments.
       
   130         rawJvmArgs.get()[ind++] = JavaCommonUtils::wstringToUtf8(*jvmArgsIter);
       
   131     }
       
   132     return startJvmInSeparateThread(rawJvmArgumentCount, rawJvmArgs.get());
       
   133 }
       
   134 
       
   135 int JvmStarterJni::startJvm(int argc, char** argv)
       
   136 {
       
   137     JELOG2(EJavaRuntime);
       
   138     // Allocate space for the raw JVM args. This will contain only
       
   139     // JVM arguments. Main class and application arguments are handled
       
   140     // differently.
       
   141     ScopedCharPointerArray rawJvmArgs(argc);
       
   142 
       
   143     // Assuming that in the beginning of the list there are JVM arguments and
       
   144     // they start with '-'.
       
   145     bool handlingArguments = true;
       
   146 
       
   147     int argCount = 0;
       
   148     for (int i = 0; i < argc; i++)
       
   149     {
       
   150         if (argv[i][0] != '-') // codescanner::accessArrayElementWithoutCheck2
       
   151         {
       
   152             // First non JVM argument was found.
       
   153             handlingArguments = false;
       
   154         }
       
   155         if (handlingArguments)
       
   156         {
       
   157             if ((strcmp(argv[i], "-cp") == 0 || // codescanner::accessArrayElementWithoutCheck2
       
   158                     strcmp(argv[i], "-classpath") == 0) && // codescanner::accessArrayElementWithoutCheck2
       
   159                     (i + 1) < argc)
       
   160             {
       
   161                 // There is class path available.
       
   162                 std::string cp("-Djava.class.path=");
       
   163                 cp += argv[i+1];
       
   164                 i++;
       
   165                 rawJvmArgs.get()[argCount] = strdup(cp.c_str());
       
   166             }
       
   167             else
       
   168             {
       
   169                 // Normal JVM argument.
       
   170                 rawJvmArgs.get()[argCount] = strdup(argv[i]); // codescanner::accessArrayElementWithoutCheck2
       
   171             }
       
   172             argCount++;
       
   173         }
       
   174         else
       
   175         {
       
   176             // The first non JVM argument can be considered as main class.
       
   177             // The rest of the arguments are arguments for the Java app.
       
   178             mAppAndArgs.push_back(JavaCommonUtils::utf8ToWstring(argv[i])); // codescanner::accessArrayElementWithoutCheck2
       
   179         }
       
   180     }
       
   181     return startJvmInSeparateThread(argCount, rawJvmArgs.get());
       
   182 }
       
   183 
       
   184 
       
   185 void* JvmStarterJni::javaThreadMain(void* arg)
       
   186 {
       
   187     JELOG2(EJavaRuntime);
       
   188     int result = -1;
       
   189     JvmStarterJni* jniStarter = (reinterpret_cast<JvmStarterJni*>(arg));
       
   190     try
       
   191     {
       
   192         result = jniStarter->startJvmImpl();
       
   193     }
       
   194     catch (RuntimeException& e)
       
   195     {
       
   196         ELOG1(EJavaRuntime, "JvmStarterJni::javaThreadMain() RuntimeException "
       
   197               "catched in VM thread. %s", e.toString().c_str());
       
   198     }
       
   199     catch (java::util::ExceptionBase& e)
       
   200     {
       
   201         ELOG1(EJavaRuntime, "JvmStarterJni::javaThreadMain() ExceptionBase "
       
   202               "catched in VM thread. %s", e.toString().c_str());
       
   203     }
       
   204     catch (std::exception& e)
       
   205     {
       
   206         ELOG1(EJavaRuntime, "JvmStarterJni::javaThreadMain() std::Exception "
       
   207               "catched in VM thread. %s", e.what());
       
   208     }
       
   209     return reinterpret_cast<void*>(result);
       
   210 }
       
   211 
       
   212 int JvmStarterJni::startJvmInSeparateThread(int argc, char** argv)
       
   213 {
       
   214     JELOG2(EJavaRuntime);
       
   215 
       
   216     // Store the argc and argv into member variables in order be avaliable
       
   217     // for the JVM starter thread.
       
   218     mArgCount = argc;
       
   219     mArgs = argv;
       
   220     // return startJvmImpl(); This could be used to start the JVM into same
       
   221     // thread.
       
   222     pthread_t threadId;
       
   223     void*     result;
       
   224 
       
   225     // Create the JVM thread.
       
   226     pthread_create(&threadId, 0, javaThreadMain, this);
       
   227 
       
   228     // Wait until the thread has died.
       
   229     pthread_join(threadId, &result);
       
   230     return reinterpret_cast<int>(result);
       
   231 }
       
   232 
       
   233 
       
   234 int JvmStarterJni::startJvmImpl()
       
   235 {
       
   236     JELOG2(EJavaRuntime);
       
   237 
       
   238     JavaVM* jvm;            // Denotes a Java VM.
       
   239     JNIEnv* env;            // Pointer to native method interface.
       
   240     JavaVMInitArgs vmArgs;  // VM initialization arguments.
       
   241     JavaVMOption vmOption;
       
   242     vmOption.extraInfo = 0;
       
   243 
       
   244     LOG(EJavaRuntime, EInfo, "VM args:");
       
   245     JvmOptionArgs_t jvmOptions;
       
   246     for (int i = 0; i < mArgCount; i++)
       
   247     {
       
   248         vmOption.optionString = mArgs[i];
       
   249         jvmOptions.push_back(vmOption);
       
   250         LOG1(EJavaRuntime, EInfo, " %s",mArgs[i]); // codescanner::accessArrayElementWithoutCheck2
       
   251     }
       
   252     vmArgs.version = JNI_VERSION_1_4;
       
   253 
       
   254     // Initializing JavaVMInitArgs.
       
   255     // Contiguity for std::vector<T> is mandated by the standard as long
       
   256     // as T is not bool. [See 23.2.4./1].
       
   257     vmArgs.options = &((jvmOptions)[0]); // codescanner::accessArrayElementWithoutCheck2
       
   258     vmArgs.nOptions = jvmOptions.size();
       
   259     vmArgs.ignoreUnrecognized = JNI_FALSE;
       
   260 
       
   261     JavaOsLayer::startUpTrace("Starting VM()", -1, -1);
       
   262 
       
   263     // Creating the JVM.
       
   264     int res = JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &vmArgs);
       
   265     LOG1(EJavaRuntime, EInfo, "JNI_CreateJavaVM() returned. st = %d", res);
       
   266     if (res == 0)
       
   267     {
       
   268         // Converting the '.' to '/' in the main class
       
   269         // (com.nokia.Foo -> com/nokia/Foo)
       
   270         std::wstring& appMain = mAppAndArgs.front();
       
   271         std::replace(appMain.begin(), appMain.end(), '.', '/');
       
   272 
       
   273         // Convert the main class to UTF-8.
       
   274         ScopedCharPointer main(JavaCommonUtils::wstringToUtf8(appMain));
       
   275 
       
   276         // Find the main class.
       
   277         jclass mainClass = env->FindClass(main.get());
       
   278         LOG2(EJavaRuntime, EInfo, " mainClass (%s): %p", main.get(), mainClass);
       
   279         if (mainClass != 0)
       
   280         {
       
   281             // Find method static void main(String[] args) from the main class.
       
   282             jmethodID mainMethod = env->GetStaticMethodID(mainClass, "main",
       
   283                                    "([Ljava/lang/String;)V");
       
   284             LOG1(EJavaRuntime, EInfo, " mainMethod: %p", mainMethod);
       
   285             if (mainMethod != 0)
       
   286             {
       
   287                 // Call the method static void main().
       
   288                 env->CallStaticVoidMethod(mainClass, mainMethod,
       
   289                                           getApplicationArguments(env));
       
   290                 LOG(EJavaRuntime, EInfo, " CallStaticVoidMethod returned");
       
   291             }
       
   292             else
       
   293             {
       
   294                 std::string errorStr("Not able to find main() method.");
       
   295                 throw RuntimeException(errorStr,
       
   296                                        __FILE__, __FUNCTION__, __LINE__);
       
   297             }
       
   298         }
       
   299         else
       
   300         {
       
   301             std::string errorStr("Main class was not found.");
       
   302             throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   303         }
       
   304         jvm->DestroyJavaVM();
       
   305     }
       
   306     else
       
   307     {
       
   308         std::string errorStr("JNI_CreateJavaVM failed. Reason = .");
       
   309         errorStr += JavaCommonUtils::intToString(res);
       
   310         throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   311     }
       
   312     return res;
       
   313 }
       
   314 
       
   315 
       
   316 void JvmStarterJni::completeArgumentContainers()
       
   317 {
       
   318     JELOG2(EJavaRuntime);
       
   319 
       
   320     // Set the used porting layer.
       
   321     mJvmArgs.push_back(L"-Dcom.nokia.jvm.port=sun.JvmPortJ2se");
       
   322 
       
   323     // Disable JIT, if requested.
       
   324     if (mJitDisabled)
       
   325     {
       
   326         mJvmArgs.push_back(L"-Xint");
       
   327     }
       
   328 
       
   329     // Add the classpath.
       
   330     if (mClassPath.length() > 0)
       
   331     {
       
   332         mClassPath.insert(0, L"-Djava.class.path=");
       
   333         mJvmArgs.push_front(mClassPath);
       
   334         LOG1(EJavaRuntime, EInfo, " mClassPath = %S", mClassPath.c_str());
       
   335     }
       
   336 
       
   337     // Add the extension classpath.
       
   338     if (mExtensionPath.length() > 0)
       
   339     {
       
   340         mExtensionPath.insert(0, L"-Djava.ext.dirs=");
       
   341         mJvmArgs.push_front(mExtensionPath);
       
   342         LOG1(EJavaRuntime, EInfo, " mExtensionPath = %S",
       
   343              mExtensionPath.c_str());
       
   344     }
       
   345 
       
   346     // Add the prepending boot classpath if set.
       
   347     if (mBootClassPathPrepend.length() > 0)
       
   348     {
       
   349         std::wstring bcpp(L"-Xbootclasspath/p:");
       
   350         bcpp += mBootClassPathPrepend;
       
   351         mJvmArgs.push_front(bcpp);
       
   352         LOG1(EJavaRuntime, EInfo, " bcpp = %S", bcpp.c_str());
       
   353     }
       
   354 
       
   355     // Add the appending boot classpath if set.
       
   356     if (mBootClassPathAppend.length() > 0)
       
   357     {
       
   358         std::wstring bcpa(L"-Xbootclasspath/a:");
       
   359         bcpa += mBootClassPathAppend;
       
   360         mJvmArgs.push_front(bcpa);
       
   361         LOG1(EJavaRuntime, EInfo, " bcpa = %S", bcpa.c_str());
       
   362     }
       
   363 
       
   364     std::wstring javaBinRoot;
       
   365     std::string binRoot;
       
   366     JavaOsLayer::getBinRoot(binRoot, false);
       
   367     javaBinRoot.assign(binRoot.begin(), binRoot.end());
       
   368 
       
   369     // Setting the java.library.path.
       
   370     std::wstring jlp(L"-Djava.library.path=");
       
   371     jlp += javaBinRoot;
       
   372     jlp +=  L"lib";
       
   373     mJvmArgs.push_front(jlp);
       
   374     LOG1(EJavaRuntime, EInfo, " jlp = %S", jlp.c_str());
       
   375 
       
   376     // Setting the java.home.
       
   377     std::wstring jh = L"-Djava.home=";
       
   378     const char* javaHome = getenv("JAVA_VM_HOME");
       
   379     if (javaHome == 0)
       
   380     {
       
   381         throw RuntimeException("JAVA_VM_HOME not defined",
       
   382                                __FILE__, __FUNCTION__, __LINE__);
       
   383     }
       
   384     std::string jhs(javaHome);
       
   385     jh.append(jhs.begin(), jhs.end());
       
   386     mJvmArgs.push_front(jh);
       
   387     LOG1(EJavaRuntime, EInfo, " jh = %S", jh.c_str());
       
   388 
       
   389     // Define emma.properties to point to emma.properties file
       
   390     // which is used when Java code coverage is measured.
       
   391     std::wstring emma(L"-Demma.properties=");
       
   392     emma += javaBinRoot;
       
   393     emma +=  L"emma.properties";
       
   394     mJvmArgs.push_front(emma);
       
   395     LOG1(EJavaRuntime, EInfo, " emma = %S", emma.c_str());
       
   396 
       
   397     // Add the main class.
       
   398     mAppAndArgs.push_front(mMainClass);
       
   399     LOG1(EJavaRuntime, EInfo, " mMainClass = %S", mMainClass.c_str());
       
   400 }
       
   401 
       
   402 jobjectArray JvmStarterJni::getApplicationArguments(JNIEnv* env)
       
   403 {
       
   404     JELOG2(EJavaRuntime);
       
   405     // When using JNI_CreateJavaVM to start the JVM the arguments for the
       
   406     // Java application must be handled so that a jobjectArray is created
       
   407     // to contain Java Strings created using jni APIs.
       
   408 
       
   409     if (env == 0)
       
   410     {
       
   411         throw RuntimeException("JNIEnv was null",
       
   412                                __FILE__, __FUNCTION__, __LINE__);
       
   413     }
       
   414 
       
   415     // Create the jobjectArray. mAppAndArgs container contains the main
       
   416     // class which must be taken into account.
       
   417     jobjectArray array =
       
   418         (jobjectArray)env->NewObjectArray(mAppAndArgs.size() - 1,
       
   419                                           env->FindClass("java/lang/String"),
       
   420                                           env->NewStringUTF(""));
       
   421     LOG(EJavaRuntime, EInfo, "  Application arguments:");
       
   422     if (array != 0)
       
   423     {
       
   424         JvmArgs_t::iterator appAndArgsIter = mAppAndArgs.begin();
       
   425         // Skip the main class.
       
   426         ++appAndArgsIter;
       
   427 
       
   428         int i = 0;
       
   429 
       
   430         // Fill the object array with application arguments.
       
   431         for (; appAndArgsIter!= mAppAndArgs.end(); ++appAndArgsIter)
       
   432         {
       
   433             ScopedCharPointer appArg(JavaCommonUtils::wstringToUtf8(*appAndArgsIter));
       
   434             LOG1(EJavaRuntime, EInfo, "   %s", appArg.get());
       
   435             env->SetObjectArrayElement(array, i++,
       
   436                                        env->NewStringUTF(appArg.get()));
       
   437         }
       
   438     }
       
   439     else
       
   440     {
       
   441         throw RuntimeException("jobjectArray was null",
       
   442                                __FILE__, __FUNCTION__, __LINE__);
       
   443     }
       
   444     return array;
       
   445 }
       
   446 
       
   447