src/jdk.incubator.jpackage/macosx/native/libapplauncher/MacPlatform.mm
branchJDK-8200758-branch
changeset 58994 b09ba68c6a19
parent 58455 0d95b41d0895
equal deleted inserted replaced
58993:b5e1baa9d2c3 58994:b09ba68c6a19
       
     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 
       
    28 #include "MacPlatform.h"
       
    29 #include "Helpers.h"
       
    30 #include "Package.h"
       
    31 #include "PropertyFile.h"
       
    32 #include "IniFile.h"
       
    33 
       
    34 #include <sys/sysctl.h>
       
    35 #include <pthread.h>
       
    36 #include <vector>
       
    37 #include <signal.h>
       
    38 #include <mach-o/dyld.h>
       
    39 
       
    40 #import <Foundation/Foundation.h>
       
    41 #import <AppKit/NSRunningApplication.h>
       
    42 
       
    43 #include <CoreFoundation/CoreFoundation.h>
       
    44 #include <CoreFoundation/CFString.h>
       
    45 
       
    46 #ifdef __OBJC__
       
    47 #import <Cocoa/Cocoa.h>
       
    48 #endif //__OBJC__
       
    49 
       
    50 #define MAC_JPACKAGE_TMP_DIR \
       
    51         "/Library/Application Support/Java/JPackage/tmp"
       
    52 
       
    53 NSString* StringToNSString(TString Value) {
       
    54     NSString* result = [NSString stringWithCString : Value.c_str()
       
    55             encoding : [NSString defaultCStringEncoding]];
       
    56     return result;
       
    57 }
       
    58 
       
    59 FileSystemStringToString::FileSystemStringToString(const TCHAR* value) {
       
    60     bool release = false;
       
    61     PlatformString lvalue = PlatformString(value);
       
    62     Platform& platform = Platform::GetInstance();
       
    63     TCHAR* buffer = platform.ConvertFileSystemStringToString(lvalue, release);
       
    64     FData = buffer;
       
    65 
       
    66     if (buffer != NULL && release == true) {
       
    67         delete[] buffer;
       
    68     }
       
    69 }
       
    70 
       
    71 FileSystemStringToString::operator TString() {
       
    72     return FData;
       
    73 }
       
    74 
       
    75 StringToFileSystemString::StringToFileSystemString(const TString &value) {
       
    76     FRelease = false;
       
    77     PlatformString lvalue = PlatformString(value);
       
    78     Platform& platform = Platform::GetInstance();
       
    79     FData = platform.ConvertStringToFileSystemString(lvalue, FRelease);
       
    80 }
       
    81 
       
    82 StringToFileSystemString::~StringToFileSystemString() {
       
    83     if (FRelease == true) {
       
    84         delete[] FData;
       
    85     }
       
    86 }
       
    87 
       
    88 StringToFileSystemString::operator TCHAR* () {
       
    89     return FData;
       
    90 }
       
    91 
       
    92 MacPlatform::MacPlatform(void) : Platform(), PosixPlatform() {
       
    93 }
       
    94 
       
    95 MacPlatform::~MacPlatform(void) {
       
    96 }
       
    97 
       
    98 TString MacPlatform::GetPackageAppDirectory() {
       
    99     return FilePath::IncludeTrailingSeparator(
       
   100             GetPackageRootDirectory()) + _T("app");
       
   101 }
       
   102 
       
   103 TString MacPlatform::GetPackageLauncherDirectory() {
       
   104     return FilePath::IncludeTrailingSeparator(
       
   105             GetPackageRootDirectory()) + _T("MacOS");
       
   106 }
       
   107 
       
   108 TString MacPlatform::GetPackageRuntimeBinDirectory() {
       
   109     return FilePath::IncludeTrailingSeparator(GetPackageRootDirectory()) +
       
   110             _T("runtime/Contents/Home/bin");
       
   111 }
       
   112 
       
   113 bool MacPlatform::UsePListForConfigFile() {
       
   114     return FilePath::FileExists(GetConfigFileName()) == false;
       
   115 }
       
   116 
       
   117 void MacPlatform::ShowMessage(TString Title, TString Description) {
       
   118     NSString *ltitle = StringToNSString(Title);
       
   119     NSString *ldescription = StringToNSString(Description);
       
   120 
       
   121     NSLog(@"%@:%@", ltitle, ldescription);
       
   122 }
       
   123 
       
   124 void MacPlatform::ShowMessage(TString Description) {
       
   125     TString appname = GetModuleFileName();
       
   126     appname = FilePath::ExtractFileName(appname);
       
   127     ShowMessage(appname, Description);
       
   128 }
       
   129 
       
   130 TString MacPlatform::getTmpDirString() {
       
   131     return TString(MAC_JPACKAGE_TMP_DIR);
       
   132 }
       
   133 
       
   134 TCHAR* MacPlatform::ConvertStringToFileSystemString(TCHAR* Source,
       
   135         bool &release) {
       
   136     TCHAR* result = NULL;
       
   137     release = false;
       
   138     CFStringRef StringRef = CFStringCreateWithCString(kCFAllocatorDefault,
       
   139             Source, kCFStringEncodingUTF8);
       
   140 
       
   141     if (StringRef != NULL) {
       
   142         @ try {
       
   143             CFIndex length =
       
   144                     CFStringGetMaximumSizeOfFileSystemRepresentation(StringRef);
       
   145             result = new char[length + 1];
       
   146             if (result != NULL) {
       
   147                 if (CFStringGetFileSystemRepresentation(StringRef,
       
   148                         result, length)) {
       
   149                     release = true;
       
   150                 } else {
       
   151                     delete[] result;
       
   152                     result = NULL;
       
   153                 }
       
   154             }
       
   155         }
       
   156         @finally
       
   157         {
       
   158             CFRelease(StringRef);
       
   159         }
       
   160     }
       
   161 
       
   162     return result;
       
   163 }
       
   164 
       
   165 TCHAR* MacPlatform::ConvertFileSystemStringToString(TCHAR* Source,
       
   166         bool &release) {
       
   167     TCHAR* result = NULL;
       
   168     release = false;
       
   169     CFStringRef StringRef = CFStringCreateWithFileSystemRepresentation(
       
   170             kCFAllocatorDefault, Source);
       
   171 
       
   172     if (StringRef != NULL) {
       
   173         @ try {
       
   174             CFIndex length = CFStringGetLength(StringRef);
       
   175 
       
   176             if (length > 0) {
       
   177                 CFIndex maxSize = CFStringGetMaximumSizeForEncoding(
       
   178                         length, kCFStringEncodingUTF8);
       
   179 
       
   180                 result = new char[maxSize + 1];
       
   181                 if (result != NULL) {
       
   182                     if (CFStringGetCString(StringRef, result, maxSize,
       
   183                             kCFStringEncodingUTF8) == true) {
       
   184                         release = true;
       
   185                     } else {
       
   186                         delete[] result;
       
   187                         result = NULL;
       
   188                     }
       
   189                 }
       
   190             }
       
   191         }
       
   192         @finally
       
   193         {
       
   194             CFRelease(StringRef);
       
   195         }
       
   196     }
       
   197 
       
   198     return result;
       
   199 }
       
   200 
       
   201 TString MacPlatform::GetPackageRootDirectory() {
       
   202     NSBundle *mainBundle = [NSBundle mainBundle];
       
   203     NSString *mainBundlePath = [mainBundle bundlePath];
       
   204     NSString *contentsPath =
       
   205             [mainBundlePath stringByAppendingString : @"/Contents"];
       
   206     TString result = [contentsPath UTF8String];
       
   207     return result;
       
   208 }
       
   209 
       
   210 TString MacPlatform::GetAppDataDirectory() {
       
   211     TString result;
       
   212     NSArray *paths = NSSearchPathForDirectoriesInDomains(
       
   213             NSApplicationSupportDirectory, NSUserDomainMask, YES);
       
   214     NSString *applicationSupportDirectory = [paths firstObject];
       
   215     result = [applicationSupportDirectory UTF8String];
       
   216     return result;
       
   217 }
       
   218 
       
   219 TString MacPlatform::GetBundledJavaLibraryFileName(TString RuntimePath) {
       
   220     TString result;
       
   221 
       
   222     // first try lib/, then lib/jli
       
   223     result = FilePath::IncludeTrailingSeparator(RuntimePath) +
       
   224             _T("Contents/Home/lib/libjli.dylib");
       
   225 
       
   226     if (FilePath::FileExists(result) == false) {
       
   227         result = FilePath::IncludeTrailingSeparator(RuntimePath) +
       
   228                 _T("Contents/Home/lib/jli/libjli.dylib");
       
   229 
       
   230         if (FilePath::FileExists(result) == false) {
       
   231             // cannot find
       
   232             NSLog(@"Cannot find libjli.dysym!");
       
   233             result = _T("");
       
   234         }
       
   235     }
       
   236 
       
   237     return result;
       
   238 }
       
   239 
       
   240 TString MacPlatform::GetAppName() {
       
   241     NSString *appName = [[NSProcessInfo processInfo] processName];
       
   242     TString result = [appName UTF8String];
       
   243     return result;
       
   244 }
       
   245 
       
   246 void PosixProcess::Cleanup() {
       
   247     if (FOutputHandle != 0) {
       
   248         close(FOutputHandle);
       
   249         FOutputHandle = 0;
       
   250     }
       
   251 
       
   252     if (FInputHandle != 0) {
       
   253         close(FInputHandle);
       
   254         FInputHandle = 0;
       
   255     }
       
   256 
       
   257     sigaction(SIGINT, &savintr, (struct sigaction *) 0);
       
   258     sigaction(SIGQUIT, &savequit, (struct sigaction *) 0);
       
   259     sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *) 0);
       
   260 }
       
   261 
       
   262 #define PIPE_READ 0
       
   263 #define PIPE_WRITE 1
       
   264 
       
   265 bool PosixProcess::Execute(const TString Application,
       
   266         const std::vector<TString> Arguments, bool AWait) {
       
   267     bool result = false;
       
   268 
       
   269     if (FRunning == false) {
       
   270         FRunning = true;
       
   271 
       
   272         int handles[2];
       
   273 
       
   274         if (pipe(handles) == -1) {
       
   275             return false;
       
   276         }
       
   277 
       
   278         struct sigaction sa;
       
   279         sa.sa_handler = SIG_IGN;
       
   280         sigemptyset(&sa.sa_mask);
       
   281         sa.sa_flags = 0;
       
   282         sigemptyset(&savintr.sa_mask);
       
   283         sigemptyset(&savequit.sa_mask);
       
   284         sigaction(SIGINT, &sa, &savintr);
       
   285         sigaction(SIGQUIT, &sa, &savequit);
       
   286         sigaddset(&sa.sa_mask, SIGCHLD);
       
   287         sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock);
       
   288 
       
   289         FChildPID = fork();
       
   290 
       
   291         // PID returned by vfork is 0 for the child process and the
       
   292         // PID of the child process for the parent.
       
   293         if (FChildPID == -1) {
       
   294             // Error
       
   295             TString message = PlatformString::Format(
       
   296                     _T("Error: Unable to create process %s"),
       
   297                     Application.data());
       
   298             throw Exception(message);
       
   299         } else if (FChildPID == 0) {
       
   300             Cleanup();
       
   301             TString command = Application;
       
   302 
       
   303             for (std::vector<TString>::const_iterator iterator =
       
   304                     Arguments.begin(); iterator != Arguments.end();
       
   305                     iterator++) {
       
   306                 command += TString(_T(" ")) + *iterator;
       
   307             }
       
   308 #ifdef DEBUG
       
   309             printf("%s\n", command.data());
       
   310 #endif // DEBUG
       
   311 
       
   312             dup2(handles[PIPE_READ], STDIN_FILENO);
       
   313             dup2(handles[PIPE_WRITE], STDOUT_FILENO);
       
   314 
       
   315             close(handles[PIPE_READ]);
       
   316             close(handles[PIPE_WRITE]);
       
   317 
       
   318             execl("/bin/sh", "sh", "-c", command.data(), (char *) 0);
       
   319 
       
   320             _exit(127);
       
   321         } else {
       
   322             FOutputHandle = handles[PIPE_READ];
       
   323             FInputHandle = handles[PIPE_WRITE];
       
   324 
       
   325             if (AWait == true) {
       
   326                 ReadOutput();
       
   327                 Wait();
       
   328                 Cleanup();
       
   329                 FRunning = false;
       
   330                 result = true;
       
   331             } else {
       
   332                 result = true;
       
   333             }
       
   334         }
       
   335     }
       
   336 
       
   337     return result;
       
   338 }
       
   339 
       
   340 void AppendPListArrayToIniFile(NSDictionary *infoDictionary,
       
   341         IniFile *result, TString Section) {
       
   342     NSString *sectionKey =
       
   343             [NSString stringWithUTF8String : PlatformString(Section).toMultibyte()];
       
   344     NSDictionary *array = [infoDictionary objectForKey : sectionKey];
       
   345 
       
   346     for (id option in array) {
       
   347         if ([option isKindOfClass : [NSString class]]) {
       
   348             TString arg = [option UTF8String];
       
   349 
       
   350             TString name;
       
   351             TString value;
       
   352 
       
   353             if (Helpers::SplitOptionIntoNameValue(arg, name, value) == true) {
       
   354                 result->Append(Section, name, value);
       
   355             }
       
   356         }
       
   357     }
       
   358 }
       
   359 
       
   360 void AppendPListDictionaryToIniFile(NSDictionary *infoDictionary,
       
   361         IniFile *result, TString Section, bool FollowSection = true) {
       
   362     NSDictionary *dictionary = NULL;
       
   363 
       
   364     if (FollowSection == true) {
       
   365         NSString *sectionKey = [NSString stringWithUTF8String : PlatformString(
       
   366                 Section).toMultibyte()];
       
   367         dictionary = [infoDictionary objectForKey : sectionKey];
       
   368     } else {
       
   369         dictionary = infoDictionary;
       
   370     }
       
   371 
       
   372     for (id key in dictionary) {
       
   373         id option = [dictionary valueForKey : key];
       
   374 
       
   375         if ([key isKindOfClass : [NSString class]] &&
       
   376                 [option isKindOfClass : [NSString class]]) {
       
   377             TString name = [key UTF8String];
       
   378             TString value = [option UTF8String];
       
   379             result->Append(Section, name, value);
       
   380         }
       
   381     }
       
   382 }
       
   383 
       
   384 // Convert parts of the info.plist to the INI format the rest of the jpackage
       
   385 // uses unless a jpackage config file exists.
       
   386 ISectionalPropertyContainer* MacPlatform::GetConfigFile(TString FileName) {
       
   387     IniFile* result = new IniFile();
       
   388     if (result == NULL) {
       
   389         return NULL;
       
   390     }
       
   391 
       
   392     if (UsePListForConfigFile() == false) {
       
   393         result->LoadFromFile(FileName);
       
   394     } else {
       
   395         NSBundle *mainBundle = [NSBundle mainBundle];
       
   396         NSDictionary *infoDictionary = [mainBundle infoDictionary];
       
   397         std::map<TString, TString> keys = GetKeys();
       
   398 
       
   399         // JPackage options.
       
   400         AppendPListDictionaryToIniFile(infoDictionary, result,
       
   401                 keys[CONFIG_SECTION_APPLICATION], false);
       
   402 
       
   403         // jvmargs
       
   404         AppendPListArrayToIniFile(infoDictionary, result,
       
   405                 keys[CONFIG_SECTION_JAVAOPTIONS]);
       
   406 
       
   407         // Generate AppCDS Cache
       
   408         AppendPListDictionaryToIniFile(infoDictionary, result,
       
   409                 keys[CONFIG_SECTION_APPCDSJAVAOPTIONS]);
       
   410         AppendPListDictionaryToIniFile(infoDictionary, result,
       
   411                 keys[CONFIG_SECTION_APPCDSGENERATECACHEJAVAOPTIONS]);
       
   412 
       
   413         // args
       
   414         AppendPListArrayToIniFile(infoDictionary, result,
       
   415                 keys[CONFIG_SECTION_ARGOPTIONS]);
       
   416     }
       
   417 
       
   418     return result;
       
   419 }
       
   420 
       
   421 TString GetModuleFileNameOSX() {
       
   422     Dl_info module_info;
       
   423     if (dladdr(reinterpret_cast<void*> (GetModuleFileNameOSX),
       
   424             &module_info) == 0) {
       
   425         // Failed to find the symbol we asked for.
       
   426         return std::string();
       
   427     }
       
   428     return TString(module_info.dli_fname);
       
   429 }
       
   430 
       
   431 TString MacPlatform::GetModuleFileName() {
       
   432     TString result;
       
   433     DynamicBuffer<TCHAR> buffer(MAX_PATH);
       
   434     uint32_t size = buffer.GetSize();
       
   435 
       
   436     if (_NSGetExecutablePath(buffer.GetData(), &size) == 0) {
       
   437         result = FileSystemStringToString(buffer.GetData());
       
   438     }
       
   439 
       
   440     return result;
       
   441 }
       
   442 
       
   443 bool MacPlatform::IsMainThread() {
       
   444     bool result = (pthread_main_np() == 1);
       
   445     return result;
       
   446 }
       
   447 
       
   448 TPlatformNumber MacPlatform::GetMemorySize() {
       
   449     unsigned long long memory = [[NSProcessInfo processInfo] physicalMemory];
       
   450 
       
   451     // Convert from bytes to megabytes.
       
   452     TPlatformNumber result = memory / 1048576;
       
   453 
       
   454     return result;
       
   455 }
       
   456 
       
   457 std::map<TString, TString> MacPlatform::GetKeys() {
       
   458     std::map<TString, TString> keys;
       
   459 
       
   460     if (UsePListForConfigFile() == false) {
       
   461         return Platform::GetKeys();
       
   462     } else {
       
   463         keys.insert(std::map<TString, TString>::value_type(CONFIG_VERSION,
       
   464                 _T("app.version")));
       
   465         keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINJAR_KEY,
       
   466                 _T("JavaMainJarName")));
       
   467         keys.insert(std::map<TString,
       
   468                 TString>::value_type(CONFIG_MAINMODULE_KEY,
       
   469                 _T("JavaMainModuleName")));
       
   470         keys.insert(std::map<TString, TString>::value_type(
       
   471                 CONFIG_MAINCLASSNAME_KEY, _T("JavaMainClassName")));
       
   472         keys.insert(std::map<TString, TString>::value_type(
       
   473                 CONFIG_CLASSPATH_KEY, _T("JavaAppClasspath")));
       
   474         keys.insert(std::map<TString, TString>::value_type(APP_NAME_KEY,
       
   475                 _T("CFBundleName")));
       
   476         keys.insert(std::map<TString, TString>::value_type(JAVA_RUNTIME_KEY,
       
   477                 _T("JavaRuntime")));
       
   478         keys.insert(std::map<TString,
       
   479                 TString>::value_type(JPACKAGE_APP_DATA_DIR,
       
   480                 _T("CFBundleIdentifier")));
       
   481 
       
   482         keys.insert(std::map<TString, TString>::value_type(CONFIG_SPLASH_KEY,
       
   483                 _T("app.splash")));
       
   484         keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_MEMORY,
       
   485                 _T("app.memory")));
       
   486         keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_DEBUG,
       
   487                 _T("app.debug")));
       
   488         keys.insert(std::map<TString, TString>::value_type(
       
   489                 CONFIG_APPLICATION_INSTANCE, _T("app.application.instance")));
       
   490 
       
   491         keys.insert(std::map<TString, TString>::value_type(
       
   492                 CONFIG_SECTION_APPLICATION, _T("Application")));
       
   493         keys.insert(std::map<TString, TString>::value_type(
       
   494                 CONFIG_SECTION_JAVAOPTIONS, _T("JavaOptions")));
       
   495         keys.insert(std::map<TString, TString>::value_type(
       
   496                 CONFIG_SECTION_APPCDSJAVAOPTIONS, _T("AppCDSJavaOptions")));
       
   497         keys.insert(std::map<TString, TString>::value_type(
       
   498                 CONFIG_SECTION_APPCDSGENERATECACHEJAVAOPTIONS,
       
   499                 _T("AppCDSGenerateCacheJavaOptions")));
       
   500         keys.insert(std::map<TString, TString>::value_type(
       
   501                 CONFIG_SECTION_ARGOPTIONS, _T("ArgOptions")));
       
   502     }
       
   503 
       
   504     return keys;
       
   505 }