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 "Platform.h" 27 #include "PlatformString.h" 28 #include "FilePath.h" 29 #include "PropertyFile.h" 30 #include "JavaVirtualMachine.h" 31 #include "Package.h" 32 #include "Macros.h" 33 #include "Messages.h" 34 35 #include <stdio.h> 36 #include <signal.h> 37 #include <stdlib.h> 38 39 /* 40 This is the app launcher program for application packaging on Windows, Mac, 41 and Linux. 42 43 Basic approach: 44 - Launcher (jpackageapplauncher) is executable that loads 45 applauncher.dll/libapplauncher.dylib/libapplauncher.so 46 and calls start_launcher below. 47 - Reads app/package.cfg or Info.plist or app/<appname>.cfg for application 48 launch configuration (package.cfg is property file). 49 - Load JVM with requested JVM settings (bundled client JVM if availble, 50 server or installed JVM otherwise). 51 - Wait for JVM to exit and then exit from Main 52 - To debug application by passing command line argument. 53 - Application folder is added to the library path (so LoadLibrary()) works. 54 55 Limitations and future work: 56 - Running Java code in primordial thread may cause problems 57 (example: can not use custom stack size). 58 Solution used by java launcher is to create a new thread to invoke JVM. 59 See CR 6316197 for more information. 60 */ 61 62 extern "C" { 63 64 JNIEXPORT bool start_launcher(int argc, TCHAR* argv[]) { 65 bool result = false; 66 bool parentProcess = true; 67 68 // Platform must be initialize first. 69 Platform& platform = Platform::GetInstance(); 70 71 try { 72 for (int index = 0; index < argc; index++) { 73 TString argument = argv[index]; 74 75 if (argument == _T("-Xappcds:generatecache")) { 76 platform.SetAppCDSState(cdsGenCache); 77 } 78 else if (argument == _T("-Xappcds:off")) { 79 platform.SetAppCDSState(cdsDisabled); 80 } 81 else if (argument == _T("-Xapp:child")) { 82 parentProcess = false; 83 } 84 #ifdef DEBUG 85 // There is a compiler bug on Mac when overloading 86 // ShowResponseMessage. 87 else if (argument == _T("-nativedebug")) { 88 if (platform.ShowResponseMessage(_T("Test"), 89 TString(_T("Would you like to debug?\n\nProcessID: ")) 90 + PlatformString(platform.GetProcessID()).toString()) 91 == mrOK) { 92 while (platform.IsNativeDebuggerPresent() == false) { 93 } 94 } 95 } 96 #endif //DEBUG 97 } 98 99 // Package must be initialized after Platform is fully initialized. 100 Package& package = Package::GetInstance(); 101 Macros::Initialize(); 102 package.SetCommandLineArguments(argc, argv); 103 platform.SetCurrentDirectory(package.GetPackageAppDirectory()); 104 105 switch (platform.GetAppCDSState()) { 106 case cdsDisabled: 107 case cdsUninitialized: 108 case cdsEnabled: { 109 break; 110 } 111 112 case cdsGenCache: { 113 TString cacheDirectory = package.GetAppCDSCacheDirectory(); 114 115 if (FilePath::DirectoryExists(cacheDirectory) == false) { 116 FilePath::CreateDirectory(cacheDirectory, true); 117 } else { 118 TString cacheFileName = 119 package.GetAppCDSCacheFileName(); 120 if (FilePath::FileExists(cacheFileName) == true) { 121 FilePath::DeleteFile(cacheFileName); 122 } 123 } 124 125 break; 126 } 127 128 case cdsAuto: { 129 TString cacheFileName = package.GetAppCDSCacheFileName(); 130 131 if (parentProcess == true && 132 FilePath::FileExists(cacheFileName) == false) { 133 AutoFreePtr<Process> process = platform.CreateProcess(); 134 std::vector<TString> args; 135 args.push_back(_T("-Xappcds:generatecache")); 136 args.push_back(_T("-Xapp:child")); 137 process->Execute( 138 platform.GetModuleFileName(), args, true); 139 140 if (FilePath::FileExists(cacheFileName) == false) { 141 // Cache does not exist after trying to generate it, 142 // so run without cache. 143 platform.SetAppCDSState(cdsDisabled); 144 package.Clear(); 145 package.Initialize(); 146 } 147 } 148 149 break; 150 } 151 } 152 153 // Validation 154 switch (platform.GetAppCDSState()) { 155 case cdsDisabled: 156 case cdsGenCache: { 157 // Do nothing. 158 break; 159 } 160 161 case cdsEnabled: 162 case cdsAuto: { 163 TString cacheFileName = 164 package.GetAppCDSCacheFileName(); 165 166 if (FilePath::FileExists(cacheFileName) == false) { 167 Messages& messages = Messages::GetInstance(); 168 TString message = PlatformString::Format( 169 messages.GetMessage( 170 APPCDS_CACHE_FILE_NOT_FOUND), 171 cacheFileName.data()); 172 throw Exception(message); 173 } 174 break; 175 } 176 177 case cdsUninitialized: { 178 platform.ShowMessage(_T("Internal Error")); 179 break; 180 } 181 } 182 183 // Run App 184 result = RunVM(); 185 } catch (Exception &e) { 186 platform.ShowMessage(e.GetMessage()); 187 } 188 189 return result; 190 } 191 192 JNIEXPORT void stop_launcher() { 193 } 194 }