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 std::vector<TString> orderedKeys = Values.GetKeys(); 88 89 for (std::vector<TString>::const_iterator iterator = orderedKeys.begin(); 90 iterator != orderedKeys.end(); iterator++) { 91 TString name = *iterator; 92 TString value; 93 94 if (Values.GetValue(name, value) == true) { 95 AppendValue(name, value); 96 } 97 } 98 } 99 100 void JavaOptions::ReplaceValue(const TString Key, TString Value) { 101 for (std::list<JavaOptionItem>::iterator iterator = FItems.begin(); 102 iterator != FItems.end(); iterator++) { 103 104 TString lkey = iterator->name; 105 106 if (lkey == Key) { 107 JavaOptionItem item = *iterator; 108 item.value = Value; 109 iterator = FItems.erase(iterator); 110 FItems.insert(iterator, item); 111 break; 112 } 113 } 114 } 115 116 std::list<TString> JavaOptions::ToList() { 117 std::list<TString> result; 118 Macros& macros = Macros::GetInstance(); 119 120 for (std::list<JavaOptionItem>::const_iterator iterator = FItems.begin(); 121 iterator != FItems.end(); iterator++) { 122 TString key = iterator->name; 123 TString value = iterator->value; 124 TString option = Helpers::NameValueToString(key, value); 125 option = macros.ExpandMacros(option); 126 result.push_back(option); 127 } 128 129 return result; 130 } 131 132 size_t JavaOptions::GetCount() { 133 return FItems.size(); 134 } 135 136 //---------------------------------------------------------------------------- 137 138 JavaVirtualMachine::JavaVirtualMachine() { 139 } 140 141 JavaVirtualMachine::~JavaVirtualMachine(void) { 142 } 143 144 bool JavaVirtualMachine::StartJVM() { 145 Platform& platform = Platform::GetInstance(); 146 Package& package = Package::GetInstance(); 147 148 TString classpath = package.GetClassPath(); 149 TString modulepath = package.GetModulePath(); 150 JavaOptions options; 151 152 if (modulepath.empty() == false) { 153 options.AppendValue(_T("-Djava.module.path"), modulepath); 154 } 155 156 options.AppendValue(_T("-Djava.library.path"), 157 package.GetPackageAppDirectory() + FilePath::PathSeparator() 158 + package.GetPackageLauncherDirectory()); 159 options.AppendValue( 160 _T("-Djava.launcher.path"), package.GetPackageLauncherDirectory()); 161 options.AppendValue(_T("-Dapp.preferences.id"), package.GetAppID()); 162 options.AppendValues(package.GetJavaOptions()); 163 164 #ifdef DEBUG 165 if (package.Debugging() == dsJava) { 166 options.AppendValue(_T("-Xdebug"), _T("")); 167 options.AppendValue( 168 _T("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=localhost:5005"), 169 _T("")); 170 platform.ShowMessage(_T("localhost:5005")); 171 } 172 #endif // DEBUG 173 174 TString maxHeapSizeOption; 175 TString minHeapSizeOption; 176 177 178 if (package.GetMemoryState() == PackageBootFields::msAuto) { 179 TPlatformNumber memorySize = package.GetMemorySize(); 180 TString memory = 181 PlatformString((size_t)memorySize).toString() + _T("m"); 182 maxHeapSizeOption = TString(_T("-Xmx")) + memory; 183 options.AppendValue(maxHeapSizeOption, _T("")); 184 185 if (memorySize > 256) 186 minHeapSizeOption = _T("-Xms256m"); 187 else 188 minHeapSizeOption = _T("-Xms") + memory; 189 190 options.AppendValue(minHeapSizeOption, _T("")); 191 } 192 193 TString mainClassName = package.GetMainClassName(); 194 TString mainModule = package.GetMainModule(); 195 196 if (mainClassName.empty() == true && mainModule.empty() == true) { 197 Messages& messages = Messages::GetInstance(); 198 platform.ShowMessage(messages.GetMessage(NO_MAIN_CLASS_SPECIFIED)); 199 return false; 200 } 201 202 configureLibrary(); 203 204 // Initialize the arguments to JLI_Launch() 205 // 206 // On Mac OS X JLI_Launch spawns a new thread that actually starts the JVM. 207 // This new thread simply re-runs main(argc, argv). Therefore we do not 208 // want to add new args if we are still in the original main thread so we 209 // will treat them as command line args provided by the user ... 210 // Only propagate original set of args first time. 211 212 options.AppendValue(_T("-classpath")); 213 options.AppendValue(classpath); 214 215 std::list<TString> vmargs; 216 vmargs.push_back(package.GetCommandName()); 217 218 if (package.HasSplashScreen() == true) { 219 options.AppendValue(TString(_T("-splash:")) 220 + package.GetSplashScreenFileName(), _T("")); 221 } 222 223 if (mainModule.empty() == true) { 224 options.AppendValue(Helpers::ConvertJavaPathToId(mainClassName), 225 _T("")); 226 } else { 227 options.AppendValue(_T("-m")); 228 options.AppendValue(mainModule); 229 } 230 231 return launchVM(options, vmargs); 232 } 233 234 void JavaVirtualMachine::configureLibrary() { 235 Platform& platform = Platform::GetInstance(); 236 Package& package = Package::GetInstance(); 237 TString libName = package.GetJavaLibraryFileName(); 238 platform.addPlatformDependencies(&javaLibrary); 239 javaLibrary.Load(libName); 240 } 241 242 bool JavaVirtualMachine::launchVM(JavaOptions& options, 243 std::list<TString>& vmargs) { 244 Platform& platform = Platform::GetInstance(); 245 Package& package = Package::GetInstance(); 246 247 #ifdef MAC 248 // Mac adds a ProcessSerialNumber to args when launched from .app 249 // filter out the psn since they it's not expected in the app 250 if (platform.IsMainThread() == false) { 251 std::list<TString> loptions = options.ToList(); 252 vmargs.splice(vmargs.end(), loptions, 253 loptions.begin(), loptions.end()); 254 } 255 #else 256 std::list<TString> loptions = options.ToList(); 257 vmargs.splice(vmargs.end(), loptions, loptions.begin(), loptions.end()); 258 #endif 259 260 std::list<TString> largs = package.GetArgs(); 261 vmargs.splice(vmargs.end(), largs, largs.begin(), largs.end()); 262 263 size_t argc = vmargs.size(); 264 DynamicBuffer<char*> argv(argc + 1); 265 if (argv.GetData() == NULL) { 266 return false; 267 } 268 269 unsigned int index = 0; 270 for (std::list<TString>::const_iterator iterator = vmargs.begin(); 271 iterator != vmargs.end(); iterator++) { 272 TString item = *iterator; 273 std::string arg = PlatformString(item).toStdString(); 274 #ifdef DEBUG 275 printf("%i %s\n", index, arg.c_str()); 276 #endif // DEBUG 277 argv[index] = PlatformString::duplicate(arg.c_str()); 278 index++; 279 } 280 281 argv[argc] = NULL; 282 283 // On Mac we can only free the boot fields if the calling thread is 284 // not the main thread. 285 #ifdef MAC 286 if (platform.IsMainThread() == false) { 287 package.FreeBootFields(); 288 } 289 #else 290 package.FreeBootFields(); 291 #endif // MAC 292 293 if (javaLibrary.JavaVMCreate(argc, argv.GetData()) == true) { 294 return true; 295 } 296 297 for (index = 0; index < argc; index++) { 298 if (argv[index] != NULL) { 299 delete[] argv[index]; 300 } 301 } 302 303 return false; 304 }