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 "Package.h" 27 #include "Lock.h" 28 #include "Helpers.h" 29 #include "Macros.h" 30 #include "IniFile.h" 31 32 #include <assert.h> 33 34 35 Package::Package(void) { 36 FInitialized = false; 37 Initialize(); 38 } 39 40 TPlatformNumber StringToPercentageOfNumber(TString Value, 41 TPlatformNumber Number) { 42 TPlatformNumber result = 0; 43 size_t percentage = atoi(PlatformString(Value.c_str())); 44 45 if (percentage > 0 && Number > 0) { 46 result = Number * percentage / 100; 47 } 48 49 return result; 50 } 51 52 bool Package::CheckForSingleInstance() { 53 Platform& platform = Platform::GetInstance(); 54 #ifdef MAC 55 if (platform.IsMainThread()) { 56 return false; 57 } 58 #endif 59 if (FInitialized == true) { 60 // everything must be initialised at this point 61 return false; 62 } 63 TString appName; 64 TString appVersion; 65 AutoFreePtr<ISectionalPropertyContainer> config = 66 platform.GetConfigFile(platform.GetConfigFileName()); 67 std::map<TString, TString> keys = platform.GetKeys(); 68 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 69 keys[APP_NAME_KEY], appName); 70 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 71 keys[CONFIG_VERSION], appVersion); 72 TString singleInstance; 73 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 74 keys[CONFIG_APPLICATION_INSTANCE], singleInstance); 75 if (singleInstance == _T("single")) { 76 TString uniqueID = appName + FBootFields->FAppID + appVersion; 77 // if another instance is running, later we can try to reactivate it 78 return platform.CheckForSingleInstance(uniqueID); 79 } 80 return false; 81 } 82 83 void Package::Initialize() { 84 if (FInitialized == true) { 85 return; 86 } 87 88 Platform& platform = Platform::GetInstance(); 89 90 FBootFields = new PackageBootFields(); 91 FDebugging = dsNone; 92 93 FBootFields->FPackageRootDirectory = platform.GetPackageRootDirectory(); 94 FBootFields->FPackageAppDirectory = platform.GetPackageAppDirectory(); 95 FBootFields->FPackageLauncherDirectory = 96 platform.GetPackageLauncherDirectory(); 97 FBootFields->FAppDataDirectory = platform.GetAppDataDirectory(); 98 99 std::map<TString, TString> keys = platform.GetKeys(); 100 101 // Read from configure.cfg/Info.plist 102 AutoFreePtr<ISectionalPropertyContainer> config = 103 platform.GetConfigFile(platform.GetConfigFileName()); 104 105 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 106 keys[CONFIG_APP_ID_KEY], FBootFields->FAppID); 107 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 108 keys[JPACKAGER_APP_DATA_DIR], FBootFields->FPackageAppDataDirectory); 109 FBootFields->FPackageAppDataDirectory = 110 FilePath::FixPathForPlatform(FBootFields->FPackageAppDataDirectory); 111 112 // Main JAR. 113 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 114 keys[CONFIG_MAINJAR_KEY], FBootFields->FMainJar); 115 FBootFields->FMainJar = 116 FilePath::IncludeTrailingSeparator(GetPackageAppDirectory()) 117 + FilePath::FixPathForPlatform(FBootFields->FMainJar); 118 119 // Main Module. 120 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 121 keys[CONFIG_MAINMODULE_KEY], FBootFields->FMainModule); 122 123 // Classpath. 124 // 1. If the provided class path contains main jar then only use 125 // provided class path. 126 // 2. If class path provided by config file is empty then add main jar. 127 // 3. If main jar is not in provided class path then add it. 128 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 129 keys[CONFIG_CLASSPATH_KEY], FBootFields->FClassPath); 130 FBootFields->FClassPath = 131 FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath); 132 133 if (FBootFields->FClassPath.empty() == true) { 134 FBootFields->FClassPath = GetMainJar(); 135 } else if (FBootFields->FClassPath.find(GetMainJar()) == TString::npos) { 136 FBootFields->FClassPath = GetMainJar() 137 + FilePath::PathSeparator() + FBootFields->FClassPath; 138 } 139 140 // Modulepath. 141 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 142 keys[CONFIG_MODULEPATH_KEY], FBootFields->FModulePath); 143 FBootFields->FModulePath = 144 FilePath::FixPathSeparatorForPlatform(FBootFields->FModulePath); 145 146 // Main Class. 147 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 148 keys[CONFIG_MAINCLASSNAME_KEY], FBootFields->FMainClassName); 149 150 // Splash Screen. 151 if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], 152 keys[CONFIG_SPLASH_KEY], 153 FBootFields->FSplashScreenFileName) == true) { 154 FBootFields->FSplashScreenFileName = 155 FilePath::IncludeTrailingSeparator(GetPackageAppDirectory()) 156 + FilePath::FixPathForPlatform(FBootFields->FSplashScreenFileName); 157 158 if (FilePath::FileExists(FBootFields->FSplashScreenFileName) == false) { 159 FBootFields->FSplashScreenFileName = _T(""); 160 } 161 } 162 163 // Runtime. 164 config->GetValue(keys[CONFIG_SECTION_APPLICATION], 165 keys[JVM_RUNTIME_KEY], FBootFields->FJVMRuntimeDirectory); 166 167 // Read jvmargs. 168 PromoteAppCDSState(config); 169 ReadJVMArgs(config); 170 171 // Read args if none were passed in. 172 if (FBootFields->FArgs.size() == 0) { 173 OrderedMap<TString, TString> args; 174 175 if (config->GetSection(keys[CONFIG_SECTION_ARGOPTIONS], args) == true) { 176 FBootFields->FArgs = Helpers::MapToNameValueList(args); 177 } 178 } 179 180 // Auto Memory. 181 TString autoMemory; 182 183 if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], 184 keys[CONFIG_APP_MEMORY], autoMemory) == true) { 185 if (autoMemory == _T("auto") || autoMemory == _T("100%")) { 186 FBootFields->FMemoryState = PackageBootFields::msAuto; 187 FBootFields->FMemorySize = platform.GetMemorySize(); 188 } else if (autoMemory.length() == 2 && isdigit(autoMemory[0]) && 189 autoMemory[1] == '%') { 190 FBootFields->FMemoryState = PackageBootFields::msAuto; 191 FBootFields->FMemorySize = 192 StringToPercentageOfNumber(autoMemory.substr(0, 1), 193 platform.GetMemorySize()); 194 } else if (autoMemory.length() == 3 && isdigit(autoMemory[0]) && 195 isdigit(autoMemory[1]) && autoMemory[2] == '%') { 196 FBootFields->FMemoryState = PackageBootFields::msAuto; 197 FBootFields->FMemorySize = 198 StringToPercentageOfNumber(autoMemory.substr(0, 2), 199 platform.GetMemorySize()); 200 } else { 201 FBootFields->FMemoryState = PackageBootFields::msManual; 202 FBootFields->FMemorySize = 0; 203 } 204 } 205 206 // Debug 207 TString debug; 208 if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], 209 keys[CONFIG_APP_DEBUG], debug) == true) { 210 FBootFields->FArgs.push_back(debug); 211 } 212 } 213 214 void Package::Clear() { 215 FreeBootFields(); 216 FInitialized = false; 217 } 218 219 // This is the only location that the AppCDS state should be modified except 220 // by command line arguments provided by the user. 221 // 222 // The state of AppCDS is as follows: 223 // 224 // -> cdsUninitialized 225 // -> cdsGenCache If -Xappcds:generatecache 226 // -> cdsDisabled If -Xappcds:off 227 // -> cdsEnabled If "AppCDSJVMOptions" section is present 228 // -> cdsAuto If "AppCDSJVMOptions" section is present and 229 // app.appcds.cache=auto 230 // -> cdsDisabled Default 231 // 232 void Package::PromoteAppCDSState(ISectionalPropertyContainer* Config) { 233 Platform& platform = Platform::GetInstance(); 234 std::map<TString, TString> keys = platform.GetKeys(); 235 236 // The AppCDS state can change at this point. 237 switch (platform.GetAppCDSState()) { 238 case cdsEnabled: 239 case cdsAuto: 240 case cdsDisabled: 241 case cdsGenCache: { 242 // Do nothing. 243 break; 244 } 245 246 case cdsUninitialized: { 247 if (Config->ContainsSection( 248 keys[CONFIG_SECTION_APPCDSJVMOPTIONS]) == true) { 249 // If the AppCDS section is present then enable AppCDS. 250 TString appCDSCacheValue; 251 252 // If running with AppCDS enabled, and the configuration has 253 // been setup so "auto" is enabled, then 254 // the launcher will attempt to generate the cache file 255 // automatically and run the application. 256 if (Config->GetValue(keys[CONFIG_SECTION_APPLICATION], 257 _T("app.appcds.cache"), appCDSCacheValue) == true && 258 appCDSCacheValue == _T("auto")) { 259 platform.SetAppCDSState(cdsAuto); 260 } 261 else { 262 platform.SetAppCDSState(cdsEnabled); 263 } 264 } else { 265 266 platform.SetAppCDSState(cdsDisabled); 267 } 268 } 269 } 270 } 271 272 void Package::ReadJVMArgs(ISectionalPropertyContainer* Config) { 273 Platform& platform = Platform::GetInstance(); 274 std::map<TString, TString> keys = platform.GetKeys(); 275 276 // Evaluate based on the current AppCDS state. 277 switch (platform.GetAppCDSState()) { 278 case cdsUninitialized: { 279 throw Exception(_T("Internal Error")); 280 } 281 282 case cdsDisabled: { 283 Config->GetSection(keys[CONFIG_SECTION_JVMOPTIONS], 284 FBootFields->FJVMArgs); 285 break; 286 } 287 288 case cdsGenCache: { 289 Config->GetSection(keys[ 290 CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS], 291 FBootFields->FJVMArgs); 292 break; 293 } 294 295 case cdsAuto: 296 case cdsEnabled: { 297 if (Config->GetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], 298 _T( "-XX:SharedArchiveFile"), 299 FBootFields->FAppCDSCacheFileName) == true) { 300 // File names may contain the incorrect path separators. 301 // The cache file name must be corrected at this point. 302 if (FBootFields->FAppCDSCacheFileName.empty() == false) { 303 IniFile* iniConfig = dynamic_cast<IniFile*>(Config); 304 305 if (iniConfig != NULL) { 306 FBootFields->FAppCDSCacheFileName = 307 FilePath::FixPathForPlatform( 308 FBootFields->FAppCDSCacheFileName); 309 iniConfig->SetValue(keys[ 310 CONFIG_SECTION_APPCDSJVMOPTIONS], 311 _T( "-XX:SharedArchiveFile"), 312 FBootFields->FAppCDSCacheFileName); 313 } 314 } 315 316 Config->GetSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], 317 FBootFields->FJVMArgs); 318 } 319 320 break; 321 } 322 } 323 } 324 325 void Package::SetCommandLineArguments(int argc, TCHAR* argv[]) { 326 if (argc > 0) { 327 std::list<TString> args; 328 329 // Prepare app arguments. Skip value at index 0 - 330 // this is path to executable. 331 FBootFields->FCommandName = argv[0]; 332 333 // Path to executable is at 0 index so start at index 1. 334 for (int index = 1; index < argc; index++) { 335 TString arg = argv[index]; 336 337 #ifdef DEBUG 338 if (arg == _T("-debug")) { 339 FDebugging = dsNative; 340 } 341 342 if (arg == _T("-javadebug")) { 343 FDebugging = dsJava; 344 } 345 #endif //DEBUG 346 #ifdef MAC 347 if (arg.find(_T("-psn_"), 0) != TString::npos) { 348 Platform& platform = Platform::GetInstance(); 349 350 if (platform.IsMainThread() == true) { 351 #ifdef DEBUG 352 printf("%s\n", arg.c_str()); 353 #endif //DEBUG 354 continue; 355 } 356 } 357 358 if (arg == _T("-NSDocumentRevisionsDebugMode")) { 359 // Ignore -NSDocumentRevisionsDebugMode and 360 // the following YES/NO 361 index++; 362 continue; 363 } 364 #endif //MAC 365 366 args.push_back(arg); 367 } 368 369 if (args.size() > 0) { 370 FBootFields->FArgs = args; 371 } 372 } 373 } 374 375 Package& Package::GetInstance() { 376 static Package instance; 377 // Guaranteed to be destroyed. Instantiated on first use. 378 return instance; 379 } 380 381 Package::~Package(void) { 382 FreeBootFields(); 383 } 384 385 void Package::FreeBootFields() { 386 if (FBootFields != NULL) { 387 delete FBootFields; 388 FBootFields = NULL; 389 } 390 } 391 392 OrderedMap<TString, TString> Package::GetJVMArgs() { 393 return FBootFields->FJVMArgs; 394 } 395 396 std::vector<TString> GetKeysThatAreNotDuplicates(OrderedMap<TString, 397 TString> &Defaults, OrderedMap<TString, TString> &Overrides) { 398 std::vector<TString> result; 399 std::vector<TString> overrideKeys = Overrides.GetKeys(); 400 401 for (size_t index = 0; index < overrideKeys.size(); index++) { 402 TString overridesKey = overrideKeys[index]; 403 TString overridesValue; 404 TString defaultValue; 405 406 if ((Defaults.ContainsKey(overridesKey) == false) || 407 (Defaults.GetValue(overridesKey, defaultValue) == true && 408 Overrides.GetValue(overridesKey, overridesValue) == true && 409 defaultValue != overridesValue)) { 410 result.push_back(overridesKey); 411 } 412 } 413 414 return result; 415 } 416 417 OrderedMap<TString, TString> CreateOrderedMapFromKeyList(OrderedMap<TString, 418 TString> &Map, std::vector<TString> &Keys) { 419 OrderedMap<TString, TString> result; 420 421 for (size_t index = 0; index < Keys.size(); index++) { 422 TString key = Keys[index]; 423 TString value; 424 425 if (Map.GetValue(key, value) == true) { 426 result.Append(key, value); 427 } 428 } 429 430 return result; 431 } 432 433 std::vector<TString> GetKeysThatAreNotOverridesOfDefaultValues( 434 OrderedMap<TString, TString> &Defaults, OrderedMap<TString, 435 TString> &Overrides) { 436 std::vector<TString> result; 437 std::vector<TString> keys = Overrides.GetKeys(); 438 439 for (unsigned int index = 0; index< keys.size(); index++) { 440 TString key = keys[index]; 441 442 if (Defaults.ContainsKey(key) == true) { 443 try { 444 TString value = Overrides[key]; 445 Defaults[key] = value; 446 } 447 catch (std::out_of_range) { 448 } 449 } 450 else { 451 result.push_back(key); 452 } 453 } 454 455 return result; 456 } 457 458 std::list<TString> Package::GetArgs() { 459 assert(FBootFields != NULL); 460 return FBootFields->FArgs; 461 } 462 463 TString Package::GetPackageRootDirectory() { 464 assert(FBootFields != NULL); 465 return FBootFields->FPackageRootDirectory; 466 } 467 468 TString Package::GetPackageAppDirectory() { 469 assert(FBootFields != NULL); 470 return FBootFields->FPackageAppDirectory; 471 } 472 473 TString Package::GetPackageLauncherDirectory() { 474 assert(FBootFields != NULL); 475 return FBootFields->FPackageLauncherDirectory; 476 } 477 478 TString Package::GetAppDataDirectory() { 479 assert(FBootFields != NULL); 480 return FBootFields->FAppDataDirectory; 481 } 482 483 TString Package::GetAppCDSCacheDirectory() { 484 if (FAppCDSCacheDirectory.empty()) { 485 Platform& platform = Platform::GetInstance(); 486 FAppCDSCacheDirectory = FilePath::IncludeTrailingSeparator( 487 platform.GetAppDataDirectory()) 488 + FilePath::IncludeTrailingSeparator( 489 GetPackageAppDataDirectory()) + _T("cache"); 490 491 Macros& macros = Macros::GetInstance(); 492 FAppCDSCacheDirectory = macros.ExpandMacros(FAppCDSCacheDirectory); 493 FAppCDSCacheDirectory = 494 FilePath::FixPathForPlatform(FAppCDSCacheDirectory); 495 } 496 497 return FAppCDSCacheDirectory; 498 } 499 500 TString Package::GetAppCDSCacheFileName() { 501 assert(FBootFields != NULL); 502 503 if (FBootFields->FAppCDSCacheFileName.empty() == false) { 504 Macros& macros = Macros::GetInstance(); 505 FBootFields->FAppCDSCacheFileName = 506 macros.ExpandMacros(FBootFields->FAppCDSCacheFileName); 507 FBootFields->FAppCDSCacheFileName = 508 FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName); 509 } 510 511 return FBootFields->FAppCDSCacheFileName; 512 } 513 514 TString Package::GetAppID() { 515 assert(FBootFields != NULL); 516 return FBootFields->FAppID; 517 } 518 519 TString Package::GetPackageAppDataDirectory() { 520 assert(FBootFields != NULL); 521 return FBootFields->FPackageAppDataDirectory; 522 } 523 524 TString Package::GetClassPath() { 525 assert(FBootFields != NULL); 526 return FBootFields->FClassPath; 527 } 528 529 TString Package::GetModulePath() { 530 assert(FBootFields != NULL); 531 return FBootFields->FModulePath; 532 } 533 534 TString Package::GetMainJar() { 535 assert(FBootFields != NULL); 536 return FBootFields->FMainJar; 537 } 538 539 TString Package::GetMainModule() { 540 assert(FBootFields != NULL); 541 return FBootFields->FMainModule; 542 } 543 544 TString Package::GetMainClassName() { 545 assert(FBootFields != NULL); 546 return FBootFields->FMainClassName; 547 } 548 549 TString Package::GetJVMLibraryFileName() { 550 assert(FBootFields != NULL); 551 552 if (FBootFields->FJVMLibraryFileName.empty() == true) { 553 Platform& platform = Platform::GetInstance(); 554 Macros& macros = Macros::GetInstance(); 555 TString jvmRuntimePath = macros.ExpandMacros(GetJVMRuntimeDirectory()); 556 FBootFields->FJVMLibraryFileName = 557 platform.GetBundledJVMLibraryFileName(jvmRuntimePath); 558 } 559 560 return FBootFields->FJVMLibraryFileName; 561 } 562 563 TString Package::GetJVMRuntimeDirectory() { 564 assert(FBootFields != NULL); 565 return FBootFields->FJVMRuntimeDirectory; 566 } 567 568 TString Package::GetSplashScreenFileName() { 569 assert(FBootFields != NULL); 570 return FBootFields->FSplashScreenFileName; 571 } 572 573 bool Package::HasSplashScreen() { 574 assert(FBootFields != NULL); 575 return FilePath::FileExists(FBootFields->FSplashScreenFileName); 576 } 577 578 TString Package::GetCommandName() { 579 assert(FBootFields != NULL); 580 return FBootFields->FCommandName; 581 } 582 583 TPlatformNumber Package::GetMemorySize() { 584 assert(FBootFields != NULL); 585 return FBootFields->FMemorySize; 586 } 587 588 PackageBootFields::MemoryState Package::GetMemoryState() { 589 assert(FBootFields != NULL); 590 return FBootFields->FMemoryState; 591 } 592 593 DebugState Package::Debugging() { 594 return FDebugging; 595 }