src/jdk.jpackage/share/native/libapplauncher/JavaVirtualMachine.cpp
branchJDK-8200758-branch
changeset 58994 b09ba68c6a19
parent 58993 b5e1baa9d2c3
child 58995 de1413ae214c
equal deleted inserted replaced
58993:b5e1baa9d2c3 58994:b09ba68c6a19
     1 /*
       
     2  * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #include "JavaVirtualMachine.h"
       
    27 #include "Platform.h"
       
    28 #include "PlatformString.h"
       
    29 #include "FilePath.h"
       
    30 #include "Package.h"
       
    31 #include "Helpers.h"
       
    32 #include "Messages.h"
       
    33 #include "Macros.h"
       
    34 
       
    35 #include "jni.h"
       
    36 
       
    37 #include <map>
       
    38 #include <list>
       
    39 #include <sstream>
       
    40 
       
    41 
       
    42 bool RunVM() {
       
    43     JavaVirtualMachine javavm;
       
    44 
       
    45     bool result = javavm.StartJVM();
       
    46 
       
    47     if (!result) {
       
    48         Platform& platform = Platform::GetInstance();
       
    49         platform.ShowMessage(_T("Failed to launch JVM\n"));
       
    50     }
       
    51 
       
    52     return result;
       
    53 }
       
    54 
       
    55 //----------------------------------------------------------------------------
       
    56 
       
    57 JavaOptions::JavaOptions(): FOptions(NULL) {
       
    58 }
       
    59 
       
    60 JavaOptions::~JavaOptions() {
       
    61     if (FOptions != NULL) {
       
    62         for (unsigned int index = 0; index < GetCount(); index++) {
       
    63             delete[] FOptions[index].optionString;
       
    64         }
       
    65 
       
    66         delete[] FOptions;
       
    67     }
       
    68 }
       
    69 
       
    70 void JavaOptions::AppendValue(const TString Key, TString Value, void* Extra) {
       
    71     JavaOptionItem item;
       
    72     item.name = Key;
       
    73     item.value = Value;
       
    74     item.extraInfo = Extra;
       
    75     FItems.push_back(item);
       
    76 }
       
    77 
       
    78 void JavaOptions::AppendValue(const TString Key, TString Value) {
       
    79     AppendValue(Key, Value, NULL);
       
    80 }
       
    81 
       
    82 void JavaOptions::AppendValue(const TString Key) {
       
    83     AppendValue(Key, _T(""), NULL);
       
    84 }
       
    85 
       
    86 void JavaOptions::AppendValues(OrderedMap<TString, TString> Values) {
       
    87     if (Values.GetAllowDuplicates()) {
       
    88         for (int i = 0; i < (int)Values.Count(); i++) {
       
    89             TString name, value;
       
    90 
       
    91             bool bResult = Values.GetKey(i, name);
       
    92             bResult &= Values.GetValue(i, value);
       
    93 
       
    94             if (bResult) {
       
    95                 AppendValue(name, value);
       
    96             }
       
    97         }
       
    98     } else { // In case we asked to add values from OrderedMap with allow
       
    99         // duplicates set to false. Not used now, but should avoid possible
       
   100         // bugs.
       
   101         std::vector<TString> orderedKeys = Values.GetKeys();
       
   102 
       
   103         for (std::vector<TString>::const_iterator iterator = orderedKeys.begin();
       
   104             iterator != orderedKeys.end(); iterator++) {
       
   105             TString name = *iterator;
       
   106             TString value;
       
   107 
       
   108             if (Values.GetValue(name, value) == true) {
       
   109                 AppendValue(name, value);
       
   110             }
       
   111         }
       
   112     }
       
   113 }
       
   114 
       
   115 void JavaOptions::ReplaceValue(const TString Key, TString Value) {
       
   116     for (std::list<JavaOptionItem>::iterator iterator = FItems.begin();
       
   117         iterator != FItems.end(); iterator++) {
       
   118 
       
   119         TString lkey = iterator->name;
       
   120 
       
   121         if (lkey == Key) {
       
   122             JavaOptionItem item = *iterator;
       
   123             item.value = Value;
       
   124             iterator = FItems.erase(iterator);
       
   125             FItems.insert(iterator, item);
       
   126             break;
       
   127         }
       
   128     }
       
   129 }
       
   130 
       
   131 std::list<TString> JavaOptions::ToList() {
       
   132     std::list<TString> result;
       
   133     Macros& macros = Macros::GetInstance();
       
   134 
       
   135     for (std::list<JavaOptionItem>::const_iterator iterator = FItems.begin();
       
   136         iterator != FItems.end(); iterator++) {
       
   137         TString key = iterator->name;
       
   138         TString value = iterator->value;
       
   139         TString option = Helpers::NameValueToString(key, value);
       
   140         option = macros.ExpandMacros(option);
       
   141         result.push_back(option);
       
   142     }
       
   143 
       
   144     return result;
       
   145 }
       
   146 
       
   147 size_t JavaOptions::GetCount() {
       
   148     return FItems.size();
       
   149 }
       
   150 
       
   151 //----------------------------------------------------------------------------
       
   152 
       
   153 JavaVirtualMachine::JavaVirtualMachine() {
       
   154 }
       
   155 
       
   156 JavaVirtualMachine::~JavaVirtualMachine(void) {
       
   157 }
       
   158 
       
   159 bool JavaVirtualMachine::StartJVM() {
       
   160     Platform& platform = Platform::GetInstance();
       
   161     Package& package = Package::GetInstance();
       
   162 
       
   163     TString classpath = package.GetClassPath();
       
   164     TString modulepath = package.GetModulePath();
       
   165     JavaOptions options;
       
   166 
       
   167     if (modulepath.empty() == false) {
       
   168         options.AppendValue(_T("-Djava.module.path"), modulepath);
       
   169     }
       
   170 
       
   171     options.AppendValue(_T("-Djava.library.path"),
       
   172             package.GetPackageAppDirectory() + FilePath::PathSeparator()
       
   173             + package.GetPackageLauncherDirectory());
       
   174     options.AppendValue(
       
   175             _T("-Djava.launcher.path"), package.GetPackageLauncherDirectory());
       
   176     options.AppendValues(package.GetJavaOptions());
       
   177 
       
   178 #ifdef DEBUG
       
   179     if (package.Debugging() == dsJava) {
       
   180         options.AppendValue(_T("-Xdebug"), _T(""));
       
   181         options.AppendValue(
       
   182                 _T("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:5005"),
       
   183                 _T(""));
       
   184         platform.ShowMessage(_T("localhost:5005"));
       
   185     }
       
   186 #endif // DEBUG
       
   187 
       
   188     TString maxHeapSizeOption;
       
   189     TString minHeapSizeOption;
       
   190 
       
   191 
       
   192     if (package.GetMemoryState() == PackageBootFields::msAuto) {
       
   193         TPlatformNumber memorySize = package.GetMemorySize();
       
   194         TString memory =
       
   195                 PlatformString((size_t)memorySize).toString() + _T("m");
       
   196         maxHeapSizeOption = TString(_T("-Xmx")) + memory;
       
   197         options.AppendValue(maxHeapSizeOption, _T(""));
       
   198 
       
   199         if (memorySize > 256)
       
   200             minHeapSizeOption = _T("-Xms256m");
       
   201         else
       
   202             minHeapSizeOption = _T("-Xms") + memory;
       
   203 
       
   204         options.AppendValue(minHeapSizeOption, _T(""));
       
   205     }
       
   206 
       
   207     TString mainClassName = package.GetMainClassName();
       
   208     TString mainModule = package.GetMainModule();
       
   209 
       
   210     if (mainClassName.empty() == true && mainModule.empty() == true) {
       
   211         Messages& messages = Messages::GetInstance();
       
   212         platform.ShowMessage(messages.GetMessage(NO_MAIN_CLASS_SPECIFIED));
       
   213         return false;
       
   214     }
       
   215 
       
   216     configureLibrary();
       
   217 
       
   218     // Initialize the arguments to JLI_Launch()
       
   219     //
       
   220     // On Mac OS X JLI_Launch spawns a new thread that actually starts the JVM.
       
   221     // This new thread simply re-runs main(argc, argv). Therefore we do not
       
   222     // want to add new args if we are still in the original main thread so we
       
   223     // will treat them as command line args provided by the user ...
       
   224     // Only propagate original set of args first time.
       
   225 
       
   226     options.AppendValue(_T("-classpath"));
       
   227     options.AppendValue(classpath);
       
   228 
       
   229     std::list<TString> vmargs;
       
   230     vmargs.push_back(package.GetCommandName());
       
   231 
       
   232     if (package.HasSplashScreen() == true) {
       
   233         options.AppendValue(TString(_T("-splash:"))
       
   234                 + package.GetSplashScreenFileName(), _T(""));
       
   235     }
       
   236 
       
   237     if (mainModule.empty() == true) {
       
   238         options.AppendValue(Helpers::ConvertJavaPathToId(mainClassName),
       
   239                 _T(""));
       
   240     } else {
       
   241         options.AppendValue(_T("-m"));
       
   242         options.AppendValue(mainModule);
       
   243     }
       
   244 
       
   245     return launchVM(options, vmargs);
       
   246 }
       
   247 
       
   248 void JavaVirtualMachine::configureLibrary() {
       
   249     Platform& platform = Platform::GetInstance();
       
   250     Package& package = Package::GetInstance();
       
   251     TString libName = package.GetJavaLibraryFileName();
       
   252     platform.addPlatformDependencies(&javaLibrary);
       
   253     javaLibrary.Load(libName);
       
   254 }
       
   255 
       
   256 bool JavaVirtualMachine::launchVM(JavaOptions& options,
       
   257         std::list<TString>& vmargs) {
       
   258     Platform& platform = Platform::GetInstance();
       
   259     Package& package = Package::GetInstance();
       
   260 
       
   261 #ifdef MAC
       
   262     // Mac adds a ProcessSerialNumber to args when launched from .app
       
   263     // filter out the psn since they it's not expected in the app
       
   264     if (platform.IsMainThread() == false) {
       
   265         std::list<TString> loptions = options.ToList();
       
   266         vmargs.splice(vmargs.end(), loptions,
       
   267                 loptions.begin(), loptions.end());
       
   268     }
       
   269 #else
       
   270     std::list<TString> loptions = options.ToList();
       
   271     vmargs.splice(vmargs.end(), loptions, loptions.begin(), loptions.end());
       
   272 #endif
       
   273 
       
   274     std::list<TString> largs = package.GetArgs();
       
   275     vmargs.splice(vmargs.end(), largs, largs.begin(), largs.end());
       
   276 
       
   277     size_t argc = vmargs.size();
       
   278     DynamicBuffer<char*> argv(argc + 1);
       
   279     if (argv.GetData() == NULL) {
       
   280         return false;
       
   281     }
       
   282 
       
   283     unsigned int index = 0;
       
   284     for (std::list<TString>::const_iterator iterator = vmargs.begin();
       
   285         iterator != vmargs.end(); iterator++) {
       
   286         TString item = *iterator;
       
   287         std::string arg = PlatformString(item).toStdString();
       
   288 #ifdef DEBUG
       
   289         printf("%i %s\n", index, arg.c_str());
       
   290 #endif // DEBUG
       
   291         argv[index] = PlatformString::duplicate(arg.c_str());
       
   292         index++;
       
   293     }
       
   294 
       
   295     argv[argc] = NULL;
       
   296 
       
   297 // On Mac we can only free the boot fields if the calling thread is
       
   298 // not the main thread.
       
   299 #ifdef MAC
       
   300     if (platform.IsMainThread() == false) {
       
   301         package.FreeBootFields();
       
   302     }
       
   303 #else
       
   304     package.FreeBootFields();
       
   305 #endif // MAC
       
   306 
       
   307     if (javaLibrary.JavaVMCreate(argc, argv.GetData()) == true) {
       
   308         return true;
       
   309     }
       
   310 
       
   311     for (index = 0; index < argc; index++) {
       
   312         if (argv[index] != NULL) {
       
   313             delete[] argv[index];
       
   314         }
       
   315     }
       
   316 
       
   317     return false;
       
   318 }