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             if (package.CheckForSingleInstance()) {
 123                 // reactivate the first instance if the process Id is valid
 124                 platform.reactivateAnotherInstance();
 125                 if (package.GetArgs().size() > 0 && platform.GetSingleInstanceProcessId() != 0) {
 126                     // if user specified args, try to pass them to the first instance
 127                     return RunVM(SINGLE_INSTANCE_NOTIFICATION_LAUNCH);
 128                 }
 129                 return true;
 130             }
 131 
 132             switch (platform.GetAppCDSState()) {
 133                 case cdsDisabled:
 134                 case cdsUninitialized:
 135                 case cdsEnabled: {
 136                     break;
 137                 }
 138 
 139                 case cdsGenCache: {
 140                         TString cacheDirectory = package.GetAppCDSCacheDirectory();
 141 
 142                         if (FilePath::DirectoryExists(cacheDirectory) == false) {
 143                             FilePath::CreateDirectory(cacheDirectory, true);
 144                         }
 145                         else {
 146                             TString cacheFileName = package.GetAppCDSCacheFileName();
 147 
 148                             if (FilePath::FileExists(cacheFileName) == true) {
 149                                 FilePath::DeleteFile(cacheFileName);
 150                             }
 151                         }
 152 
 153                         break;
 154                     }
 155 
 156                 case cdsAuto: {
 157                     TString cacheFileName = package.GetAppCDSCacheFileName();
 158 
 159                     if (parentProcess == true && FilePath::FileExists(cacheFileName) == false) {
 160                         AutoFreePtr<Process> process = platform.CreateProcess();
 161                         std::vector<TString> args;
 162                         args.push_back(_T("-Xappcds:generatecache"));
 163                         args.push_back(_T("-Xapp:child"));
 164                         process->Execute(platform.GetModuleFileName(), args, true);
 165 
 166                         if (FilePath::FileExists(cacheFileName) == false) {
 167                             // Cache does not exist after trying to generate it,
 168                             // so run without cache.
 169                             platform.SetAppCDSState(cdsDisabled);
 170                             package.Clear();
 171                             package.Initialize();
 172                         }
 173                     }
 174 
 175                     break;
 176                 }
 177             }
 178 
 179             // Validation
 180             {
 181                 switch (platform.GetAppCDSState()) {
 182                     case cdsDisabled:
 183                     case cdsGenCache: {
 184                         // Do nothing.
 185                         break;
 186                     }
 187 
 188                     case cdsEnabled:
 189                     case cdsAuto: {
 190                             TString cacheFileName = package.GetAppCDSCacheFileName();
 191 
 192                             if (FilePath::FileExists(cacheFileName) == false) {
 193                                 Messages& messages = Messages::GetInstance();
 194                                 TString message = PlatformString::Format(messages.GetMessage(APPCDS_CACHE_FILE_NOT_FOUND), cacheFileName.data());
 195                                 throw FileNotFoundException(message);
 196                             }
 197                             break;
 198                         }
 199 
 200                     case cdsUninitialized: {
 201                         throw Exception(_T("Internal Error"));
 202                 }
 203             }
 204             }
 205             // Run App
 206             result = RunVM(USER_APP_LAUNCH);
 207         }
 208         catch (FileNotFoundException &e) {
 209             platform.ShowMessage(e.GetMessage());
 210         }
 211 
 212         return result;
 213     }
 214 
 215 #ifdef WINDOWS
 216     __declspec(dllexport)
 217 #endif //WINDOWS
 218 
 219     void stop_launcher() {
 220     }
 221 }