1 /*
   2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 
  34 #include "Platform.h"
  35 #include "PlatformString.h"
  36 #include "FilePath.h"
  37 #include "PropertyFile.h"
  38 #include "JavaVirtualMachine.h"
  39 #include "Package.h"
  40 #include "PlatformThread.h"
  41 #include "Macros.h"
  42 #include "Messages.h"
  43 
  44 
  45 #ifdef WINDOWS
  46 #include <Shellapi.h>
  47 #endif
  48 
  49 
  50 #include <stdio.h>
  51 #include <signal.h>
  52 #include <stdlib.h>
  53 
  54 /*
  55 This is the launcher program for application packaging on Windows, Mac and Linux.
  56 
  57 Basic approach:
  58   - Launcher executable loads packager.dll/libpackager.dylib/libpackager.so and calls start_launcher below.
  59   - Reads app/package.cfg or Info.plist or app/<appname>.cfg for application launch configuration
  60      (package.cfg is property file).
  61   - Load JVM with requested JVM settings (bundled client JVM if availble, server or installed JVM otherwise).
  62   - Wait for JVM to exit and then exit from Main
  63   - To debug application by passing command line argument.
  64   - Application folder is added to the library path (so LoadLibrary()) works.
  65 
  66 Limitations and future work:
  67   - Running Java code in primordial thread may cause problems
  68     (example: can not use custom stack size).
  69     Solution used by java launcher is to create a new thread to invoke JVM.
  70     See CR 6316197 for more information.
  71 */
  72 
  73 extern "C" {
  74 
  75 #ifdef WINDOWS
  76     BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
  77         return true;
  78     }
  79 
  80     __declspec(dllexport)
  81 #endif //WINDOWS
  82 
  83     bool start_launcher(int argc, TCHAR* argv[]) {
  84         bool result = false;
  85         bool parentProcess = true;
  86 
  87         // Platform must be initialize first.
  88         Platform& platform = Platform::GetInstance();
  89 
  90         try {
  91             for (int index = 0; index < argc; index++) {
  92                 TString argument = argv[index];
  93 
  94                 if (argument == _T("-Xappcds:generatecache")) {
  95                     platform.SetAppCDSState(cdsGenCache);
  96                 }
  97                 else if (argument == _T("-Xappcds:off")) {
  98                     platform.SetAppCDSState(cdsDisabled);
  99                 }
 100                 else if (argument == _T("-Xapp:child")) {
 101                     parentProcess = false;
 102                 }
 103 #ifdef DEBUG
 104                 // There is a compiler bug on Mac when overloading ShowResponseMessage.
 105                 else if (argument == _T("-nativedebug")) {
 106                     if (platform.ShowResponseMessage(_T("Test"),
 107                                                      TString(_T("Would you like to debug?\n\nProcessID: ")) +
 108                                                      PlatformString(platform.GetProcessID()).toString()) == mrOK) {
 109                         while (platform.IsNativeDebuggerPresent() == false) {
 110                         }
 111                     }
 112                 }
 113 #endif //DEBUG
 114             }
 115 
 116             // Package must be initialized after Platform is fully initialized.
 117             Package& package = Package::GetInstance();
 118             Macros::Initialize();
 119             package.SetCommandLineArguments(argc, argv);
 120             platform.SetCurrentDirectory(package.GetPackageAppDirectory());
 121 
 122             switch (platform.GetAppCDSState()) {
 123                 case cdsDisabled:
 124                 case cdsUninitialized:
 125                 case cdsEnabled: {
 126                     break;
 127                 }
 128 
 129                 case cdsGenCache: {
 130                         TString cacheDirectory = package.GetAppCDSCacheDirectory();
 131 
 132                         if (FilePath::DirectoryExists(cacheDirectory) == false) {
 133                             FilePath::CreateDirectory(cacheDirectory, true);
 134                         }
 135                         else {
 136                             TString cacheFileName = package.GetAppCDSCacheFileName();
 137 
 138                             if (FilePath::FileExists(cacheFileName) == true) {
 139                                 FilePath::DeleteFile(cacheFileName);
 140                             }
 141                         }
 142 
 143                         break;
 144                     }
 145 
 146                 case cdsAuto: {
 147                     TString cacheFileName = package.GetAppCDSCacheFileName();
 148 
 149                     if (parentProcess == true && FilePath::FileExists(cacheFileName) == false) {
 150                         AutoFreePtr<Process> process = platform.CreateProcess();
 151                         std::vector<TString> args;
 152                         args.push_back(_T("-Xappcds:generatecache"));
 153                         args.push_back(_T("-Xapp:child"));
 154                         process->Execute(platform.GetModuleFileName(), args, true);
 155 
 156                         if (FilePath::FileExists(cacheFileName) == false) {
 157                             // Cache does not exist after trying to generate it,
 158                             // so run without cache.
 159                             platform.SetAppCDSState(cdsDisabled);
 160                             package.Clear();
 161                             package.Initialize();
 162                         }
 163                     }
 164 
 165                     break;
 166                 }
 167             }
 168 
 169             // Validation
 170             {
 171                 switch (platform.GetAppCDSState()) {
 172                     case cdsDisabled:
 173                     case cdsGenCache: {
 174                         // Do nothing.
 175                         break;
 176                     }
 177 
 178                     case cdsEnabled:
 179                     case cdsAuto: {
 180                             TString cacheFileName = package.GetAppCDSCacheFileName();
 181 
 182                             if (FilePath::FileExists(cacheFileName) == false) {
 183                                 Messages& messages = Messages::GetInstance();
 184                                 TString message = PlatformString::Format(messages.GetMessage(APPCDS_CACHE_FILE_NOT_FOUND), cacheFileName.data());
 185                                 throw FileNotFoundException(message);
 186                             }
 187                             break;
 188                         }
 189 
 190                     case cdsUninitialized: {
 191                         throw Exception(_T("Internal Error"));
 192                 }
 193             }
 194             }
 195 
 196             // Run App
 197             result = RunVM();
 198         }
 199         catch (FileNotFoundException &e) {
 200             platform.ShowMessage(e.GetMessage());
 201         }
 202 
 203         return result;
 204     }
 205 
 206 #ifdef WINDOWS
 207     __declspec(dllexport)
 208 #endif //WINDOWS
 209 
 210     void stop_launcher() {
 211     }
 212 }