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