src/jdk.jpackage/share/native/libapplauncher/JavaVirtualMachine.cpp
branchJDK-8200758-branch
changeset 57064 a7fdadf67a92
child 57099 9a85a7a076ad
equal deleted inserted replaced
57063:1fa5c73d3c5a 57064:a7fdadf67a92
       
     1 /*
       
     2  * Copyright (c) 2014, 2018, 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 "JavaTypes.h"
       
    32 #include "Helpers.h"
       
    33 #include "Messages.h"
       
    34 #include "Macros.h"
       
    35 #include "PlatformThread.h"
       
    36 
       
    37 #include "jni.h"
       
    38 
       
    39 #include <map>
       
    40 #include <list>
       
    41 #include <sstream>
       
    42 
       
    43 
       
    44 bool RunVM(JvmLaunchType type) {
       
    45     bool result = false;
       
    46     JavaVirtualMachine javavm;
       
    47 
       
    48     switch (type){
       
    49         case USER_APP_LAUNCH:
       
    50             result = javavm.StartJVM();
       
    51             break;
       
    52         case SINGLE_INSTANCE_NOTIFICATION_LAUNCH:
       
    53             result = javavm.NotifySingleInstance();
       
    54             break;
       
    55         default:
       
    56             break;
       
    57     }
       
    58 
       
    59     if (!result) {
       
    60         Platform& platform = Platform::GetInstance();
       
    61         platform.ShowMessage(_T("Failed to launch JVM\n"));
       
    62     }
       
    63 
       
    64     return result;
       
    65 }
       
    66 
       
    67 JavaLibrary::JavaLibrary() : Library(), FCreateProc(NULL)  {
       
    68 }
       
    69 
       
    70 bool JavaLibrary::JavaVMCreate(size_t argc, char *argv[]) {
       
    71     if (FCreateProc == NULL) {
       
    72         FCreateProc = (JVM_CREATE)GetProcAddress(LAUNCH_FUNC);
       
    73     }
       
    74 
       
    75     if (FCreateProc == NULL) {
       
    76         Platform& platform = Platform::GetInstance();
       
    77         Messages& messages = Messages::GetInstance();
       
    78         platform.ShowMessage(
       
    79                 messages.GetMessage(FAILED_LOCATING_JVM_ENTRY_POINT));
       
    80         return false;
       
    81     }
       
    82 
       
    83     return FCreateProc((int)argc, argv,
       
    84             0, NULL,
       
    85             0, NULL,
       
    86             "",
       
    87             "",
       
    88             "java",
       
    89             "java",
       
    90             false,
       
    91             false,
       
    92             false,
       
    93             0) == 0;
       
    94 }
       
    95 
       
    96 //----------------------------------------------------------------------------
       
    97 
       
    98 JavaOptions::JavaOptions(): FOptions(NULL) {
       
    99 }
       
   100 
       
   101 JavaOptions::~JavaOptions() {
       
   102     if (FOptions != NULL) {
       
   103         for (unsigned int index = 0; index < GetCount(); index++) {
       
   104             delete[] FOptions[index].optionString;
       
   105         }
       
   106 
       
   107         delete[] FOptions;
       
   108     }
       
   109 }
       
   110 
       
   111 void JavaOptions::AppendValue(const TString Key, TString Value, void* Extra) {
       
   112     JavaOptionItem item;
       
   113     item.name = Key;
       
   114     item.value = Value;
       
   115     item.extraInfo = Extra;
       
   116     FItems.push_back(item);
       
   117 }
       
   118 
       
   119 void JavaOptions::AppendValue(const TString Key, TString Value) {
       
   120     AppendValue(Key, Value, NULL);
       
   121 }
       
   122 
       
   123 void JavaOptions::AppendValue(const TString Key) {
       
   124     AppendValue(Key, _T(""), NULL);
       
   125 }
       
   126 
       
   127 void JavaOptions::AppendValues(OrderedMap<TString, TString> Values) {
       
   128     std::vector<TString> orderedKeys = Values.GetKeys();
       
   129 
       
   130     for (std::vector<TString>::const_iterator iterator = orderedKeys.begin();
       
   131         iterator != orderedKeys.end(); iterator++) {
       
   132         TString name = *iterator;
       
   133         TString value;
       
   134 
       
   135         if (Values.GetValue(name, value) == true) {
       
   136             AppendValue(name, value);
       
   137         }
       
   138     }
       
   139 }
       
   140 
       
   141 void JavaOptions::ReplaceValue(const TString Key, TString Value) {
       
   142     for (std::list<JavaOptionItem>::iterator iterator = FItems.begin();
       
   143         iterator != FItems.end(); iterator++) {
       
   144 
       
   145         TString lkey = iterator->name;
       
   146 
       
   147         if (lkey == Key) {
       
   148             JavaOptionItem item = *iterator;
       
   149             item.value = Value;
       
   150             iterator = FItems.erase(iterator);
       
   151             FItems.insert(iterator, item);
       
   152             break;
       
   153         }
       
   154     }
       
   155 }
       
   156 
       
   157 std::list<TString> JavaOptions::ToList() {
       
   158     std::list<TString> result;
       
   159     Macros& macros = Macros::GetInstance();
       
   160 
       
   161     for (std::list<JavaOptionItem>::const_iterator iterator = FItems.begin();
       
   162         iterator != FItems.end(); iterator++) {
       
   163         TString key = iterator->name;
       
   164         TString value = iterator->value;
       
   165         TString option = Helpers::NameValueToString(key, value);
       
   166         option = macros.ExpandMacros(option);
       
   167         result.push_back(option);
       
   168     }
       
   169 
       
   170     return result;
       
   171 }
       
   172 
       
   173 size_t JavaOptions::GetCount() {
       
   174     return FItems.size();
       
   175 }
       
   176 
       
   177 //----------------------------------------------------------------------------
       
   178 
       
   179 JavaVirtualMachine::JavaVirtualMachine() {
       
   180 }
       
   181 
       
   182 JavaVirtualMachine::~JavaVirtualMachine(void) {
       
   183 }
       
   184 
       
   185 bool JavaVirtualMachine::StartJVM() {
       
   186     Platform& platform = Platform::GetInstance();
       
   187     Package& package = Package::GetInstance();
       
   188 
       
   189     TString classpath = package.GetClassPath();
       
   190     TString modulepath = package.GetModulePath();
       
   191     JavaOptions options;
       
   192 
       
   193     if (modulepath.empty() == false) {
       
   194         options.AppendValue(_T("-Djava.module.path"), modulepath);
       
   195     }
       
   196 
       
   197     options.AppendValue(_T("-Djava.library.path"),
       
   198             package.GetPackageAppDirectory() + FilePath::PathSeparator()
       
   199             + package.GetPackageLauncherDirectory());
       
   200     options.AppendValue(
       
   201             _T("-Djava.launcher.path"), package.GetPackageLauncherDirectory());
       
   202     options.AppendValue(_T("-Dapp.preferences.id"), package.GetAppID());
       
   203     options.AppendValues(package.GetJVMArgs());
       
   204 
       
   205 #ifdef DEBUG
       
   206     if (package.Debugging() == dsJava) {
       
   207         options.AppendValue(_T("-Xdebug"), _T(""));
       
   208         options.AppendValue(
       
   209                 _T("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:5005"),
       
   210                 _T(""));
       
   211         platform.ShowMessage(_T("localhost:5005"));
       
   212     }
       
   213 #endif // DEBUG
       
   214 
       
   215     TString maxHeapSizeOption;
       
   216     TString minHeapSizeOption;
       
   217 
       
   218 
       
   219     if (package.GetMemoryState() == PackageBootFields::msAuto) {
       
   220         TPlatformNumber memorySize = package.GetMemorySize();
       
   221         TString memory =
       
   222                 PlatformString((size_t)memorySize).toString() + _T("m");
       
   223         maxHeapSizeOption = TString(_T("-Xmx")) + memory;
       
   224         options.AppendValue(maxHeapSizeOption, _T(""));
       
   225 
       
   226         if (memorySize > 256)
       
   227             minHeapSizeOption = _T("-Xms256m");
       
   228         else
       
   229             minHeapSizeOption = _T("-Xms") + memory;
       
   230 
       
   231         options.AppendValue(minHeapSizeOption, _T(""));
       
   232     }
       
   233 
       
   234     TString mainClassName = package.GetMainClassName();
       
   235     TString mainModule = package.GetMainModule();
       
   236 
       
   237     if (mainClassName.empty() == true && mainModule.empty() == true) {
       
   238         Messages& messages = Messages::GetInstance();
       
   239         platform.ShowMessage(messages.GetMessage(NO_MAIN_CLASS_SPECIFIED));
       
   240         return false;
       
   241     }
       
   242 
       
   243     configureLibrary();
       
   244 
       
   245     // Initialize the arguments to JLI_Launch()
       
   246     //
       
   247     // On Mac OS X JLI_Launch spawns a new thread that actually starts the JVM.
       
   248     // This new thread simply re-runs main(argc, argv). Therefore we do not
       
   249     // want to add new args if we are still in the original main thread so we
       
   250     // will treat them as command line args provided by the user ...
       
   251     // Only propagate original set of args first time.
       
   252 
       
   253     options.AppendValue(_T("-classpath"));
       
   254     options.AppendValue(classpath);
       
   255 
       
   256     std::list<TString> vmargs;
       
   257     vmargs.push_back(package.GetCommandName());
       
   258 
       
   259     if (package.HasSplashScreen() == true) {
       
   260         options.AppendValue(TString(_T("-splash:"))
       
   261                 + package.GetSplashScreenFileName(), _T(""));
       
   262     }
       
   263 
       
   264     if (mainModule.empty() == true) {
       
   265         options.AppendValue(Helpers::ConvertJavaPathToId(mainClassName),
       
   266                 _T(""));
       
   267     } else {
       
   268         options.AppendValue(_T("-m"));
       
   269         options.AppendValue(mainModule);
       
   270     }
       
   271 
       
   272     return launchVM(options, vmargs, false);
       
   273 }
       
   274 
       
   275 bool JavaVirtualMachine::NotifySingleInstance() {
       
   276     Package& package = Package::GetInstance();
       
   277 
       
   278     std::list<TString> vmargs;
       
   279     vmargs.push_back(package.GetCommandName());
       
   280 
       
   281     JavaOptions options;
       
   282     options.AppendValue(_T("-Djava.library.path"),
       
   283             package.GetPackageAppDirectory() + FilePath::PathSeparator()
       
   284             + package.GetPackageLauncherDirectory());
       
   285     options.AppendValue(_T("-Djava.launcher.path"),
       
   286             package.GetPackageLauncherDirectory());
       
   287     // launch SingleInstanceNewActivation.main() to pass arguments to
       
   288     // another instance
       
   289     options.AppendValue(_T("-m"));
       
   290     options.AppendValue(
       
   291             _T("jdk.jpackage.runtime/jdk.jpackage.runtime.singleton.SingleInstanceNewActivation"));
       
   292 
       
   293     configureLibrary();
       
   294 
       
   295     return launchVM(options, vmargs, true);
       
   296 }
       
   297 
       
   298 void JavaVirtualMachine::configureLibrary() {
       
   299     Platform& platform = Platform::GetInstance();
       
   300     Package& package = Package::GetInstance();
       
   301     // TODO: Clean this up. Because of bug JDK-8131321 the opening of the
       
   302     // PE file ails in WindowsPlatform.cpp on the check to
       
   303     // if (pNTHeader->Signature == IMAGE_NT_SIGNATURE)
       
   304     TString libName = package.GetJVMLibraryFileName();
       
   305 #ifdef _WIN64
       
   306     if (FilePath::FileExists(_T("msvcr100.dll")) == true) {
       
   307         javaLibrary.AddDependency(_T("msvcr100.dll"));
       
   308     }
       
   309 
       
   310     TString runtimeBin = platform.GetPackageRuntimeBinDirectory();
       
   311     SetDllDirectory(runtimeBin.c_str());
       
   312 #else
       
   313     javaLibrary.AddDependencies(
       
   314             platform.FilterOutRuntimeDependenciesForPlatform(
       
   315             platform.GetLibraryImports(libName)));
       
   316 #endif
       
   317     javaLibrary.Load(libName);
       
   318 }
       
   319 
       
   320 bool JavaVirtualMachine::launchVM(JavaOptions& options,
       
   321         std::list<TString>& vmargs, bool addSiProcessId) {
       
   322     Platform& platform = Platform::GetInstance();
       
   323     Package& package = Package::GetInstance();
       
   324 
       
   325 #ifdef MAC
       
   326     // Mac adds a ProcessSerialNumber to args when launched from .app
       
   327     // filter out the psn since they it's not expected in the app
       
   328     if (platform.IsMainThread() == false) {
       
   329         std::list<TString> loptions = options.ToList();
       
   330         vmargs.splice(vmargs.end(), loptions,
       
   331                 loptions.begin(), loptions.end());
       
   332     }
       
   333 #else
       
   334     std::list<TString> loptions = options.ToList();
       
   335     vmargs.splice(vmargs.end(), loptions, loptions.begin(), loptions.end());
       
   336 #endif
       
   337 
       
   338     if (addSiProcessId) {
       
   339         // add single instance process ID as a first argument
       
   340         TProcessID pid = platform.GetSingleInstanceProcessId();
       
   341         std::ostringstream s;
       
   342         s << pid;
       
   343         std::string procIdStr(s.str());
       
   344         vmargs.push_back(TString(procIdStr.begin(), procIdStr.end()));
       
   345     }
       
   346 
       
   347     std::list<TString> largs = package.GetArgs();
       
   348     vmargs.splice(vmargs.end(), largs, largs.begin(), largs.end());
       
   349 
       
   350     size_t argc = vmargs.size();
       
   351     DynamicBuffer<char*> argv(argc + 1);
       
   352     if (argv.GetData() == NULL) {
       
   353         return false;
       
   354     }
       
   355 
       
   356     unsigned int index = 0;
       
   357     for (std::list<TString>::const_iterator iterator = vmargs.begin();
       
   358         iterator != vmargs.end(); iterator++) {
       
   359         TString item = *iterator;
       
   360         std::string arg = PlatformString(item).toStdString();
       
   361 #ifdef DEBUG
       
   362         printf("%i %s\n", index, arg.c_str());
       
   363 #endif // DEBUG
       
   364         argv[index] = PlatformString::duplicate(arg.c_str());
       
   365         index++;
       
   366     }
       
   367 
       
   368     argv[argc] = NULL;
       
   369 
       
   370 // On Mac we can only free the boot fields if the calling thread is
       
   371 // not the main thread.
       
   372 #ifdef MAC
       
   373     if (platform.IsMainThread() == false) {
       
   374         package.FreeBootFields();
       
   375     }
       
   376 #else
       
   377     package.FreeBootFields();
       
   378 #endif // MAC
       
   379 
       
   380     if (javaLibrary.JavaVMCreate(argc, argv.GetData()) == true) {
       
   381         return true;
       
   382     }
       
   383 
       
   384     for (index = 0; index < argc; index++) {
       
   385         if (argv[index] != NULL) {
       
   386             delete[] argv[index];
       
   387         }
       
   388     }
       
   389 
       
   390     return false;
       
   391 }