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