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 28 #ifdef MAC 29 30 #include "MacPlatform.h" 31 #include "Helpers.h" 32 #include "Package.h" 33 #include "PropertyFile.h" 34 #include "IniFile.h" 35 36 #include <sys/sysctl.h> 37 #include <pthread.h> 38 #include <vector> 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_JPACKAGER_TMP_DIR \ 51 "/Library/Application Support/Oracle/Java/JPackager/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 MacPlatform::MacPlatform(void) : Platform(), GenericPlatform(), PosixPlatform() { 60 } 61 62 MacPlatform::~MacPlatform(void) { 63 } 64 65 bool MacPlatform::UsePListForConfigFile() { 66 return FilePath::FileExists(GetConfigFileName()) == false; 67 } 68 69 void MacPlatform::ShowMessage(TString Title, TString Description) { 70 NSString *ltitle = StringToNSString(Title); 71 NSString *ldescription = StringToNSString(Description); 72 73 NSLog(@"%@:%@", ltitle, ldescription); 74 } 75 76 void MacPlatform::ShowMessage(TString Description) { 77 TString appname = GetModuleFileName(); 78 appname = FilePath::ExtractFileName(appname); 79 ShowMessage(appname, Description); 80 } 81 82 TString MacPlatform::getTmpDirString() { 83 return TString(MAC_JPACKAGER_TMP_DIR); 84 } 85 86 void MacPlatform::reactivateAnotherInstance() { 87 if (singleInstanceProcessId == 0) { 88 printf("Unable to reactivate another instance, PID is undefined"); 89 return; 90 } 91 NSRunningApplication* app = 92 [NSRunningApplication runningApplicationWithProcessIdentifier: 93 singleInstanceProcessId]; 94 if (app != nil) { 95 [app activateWithOptions: NSApplicationActivateIgnoringOtherApps]; 96 } else { 97 printf("Unable to reactivate another instance PID: %d", 98 singleInstanceProcessId); 99 } 100 } 101 102 TCHAR* MacPlatform::ConvertStringToFileSystemString(TCHAR* Source, 103 bool &release) { 104 TCHAR* result = NULL; 105 release = false; 106 CFStringRef StringRef = CFStringCreateWithCString(kCFAllocatorDefault, 107 Source, kCFStringEncodingUTF8); 108 109 if (StringRef != NULL) { 110 @try { 111 CFIndex length = 112 CFStringGetMaximumSizeOfFileSystemRepresentation(StringRef); 113 result = new char[length + 1]; 114 if (result != NULL) { 115 if (CFStringGetFileSystemRepresentation(StringRef, 116 result, length)) { 117 release = true; 118 } 119 else { 120 delete[] result; 121 result = NULL; 122 } 123 } 124 } 125 @finally { 126 CFRelease(StringRef); 127 } 128 } 129 130 return result; 131 } 132 133 TCHAR* MacPlatform::ConvertFileSystemStringToString(TCHAR* Source, 134 bool &release) { 135 TCHAR* result = NULL; 136 release = false; 137 CFStringRef StringRef = CFStringCreateWithFileSystemRepresentation( 138 kCFAllocatorDefault, Source); 139 140 if (StringRef != NULL) { 141 @try { 142 CFIndex length = CFStringGetLength(StringRef); 143 144 if (length > 0) { 145 CFIndex maxSize = CFStringGetMaximumSizeForEncoding( 146 length, kCFStringEncodingUTF8); 147 148 result = new char[maxSize + 1]; 149 if (result != NULL) { 150 if (CFStringGetCString(StringRef, result, maxSize, 151 kCFStringEncodingUTF8) == true) { 152 release = true; 153 } 154 else { 155 delete[] result; 156 result = NULL; 157 } 158 } 159 } 160 } 161 @finally { 162 CFRelease(StringRef); 163 } 164 } 165 166 return result; 167 } 168 169 void MacPlatform::SetCurrentDirectory(TString Value) { 170 chdir(PlatformString(Value).toPlatformString()); 171 } 172 173 TString MacPlatform::GetPackageRootDirectory() { 174 NSBundle *mainBundle = [NSBundle mainBundle]; 175 NSString *mainBundlePath = [mainBundle bundlePath]; 176 NSString *contentsPath = 177 [mainBundlePath stringByAppendingString:@"/Contents"]; 178 TString result = [contentsPath UTF8String]; 179 return result; 180 } 181 182 TString MacPlatform::GetAppDataDirectory() { 183 TString result; 184 NSArray *paths = NSSearchPathForDirectoriesInDomains( 185 NSApplicationSupportDirectory, NSUserDomainMask, YES); 186 NSString *applicationSupportDirectory = [paths firstObject]; 187 result = [applicationSupportDirectory UTF8String]; 188 return result; 189 } 190 191 TString MacPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) { 192 TString result; 193 194 // first try lib/, then lib/jli 195 result = FilePath::IncludeTrailingSeparator(RuntimePath) + 196 _T("Contents/Home/lib/libjli.dylib"); 197 198 if (FilePath::FileExists(result) == false) { 199 result = FilePath::IncludeTrailingSeparator(RuntimePath) + 200 _T("Contents/Home/lib/jli/libjli.dylib"); 201 202 if (FilePath::FileExists(result) == false) { 203 // cannot find 204 NSLog(@"Cannot find libjli.dysym!"); 205 result = _T(""); 206 } 207 } 208 209 return result; 210 } 211 212 TString MacPlatform::GetAppName() { 213 NSString *appName = [[NSProcessInfo processInfo] processName]; 214 TString result = [appName UTF8String]; 215 return result; 216 } 217 218 void AppendPListArrayToIniFile(NSDictionary *infoDictionary, 219 IniFile *result, TString Section) { 220 NSString *sectionKey = 221 [NSString stringWithUTF8String:PlatformString(Section).toMultibyte()]; 222 NSDictionary *array = [infoDictionary objectForKey:sectionKey]; 223 224 for (id option in array) { 225 if ([option isKindOfClass:[NSString class]]) { 226 TString arg = [option UTF8String]; 227 228 TString name; 229 TString value; 230 231 if (Helpers::SplitOptionIntoNameValue(arg, name, value) == true) { 232 result->Append(Section, name, value); 233 } 234 } 235 } 236 } 237 238 void AppendPListDictionaryToIniFile(NSDictionary *infoDictionary, 239 IniFile *result, TString Section, bool FollowSection = true) { 240 NSDictionary *dictionary = NULL; 241 242 if (FollowSection == true) { 243 NSString *sectionKey = [NSString stringWithUTF8String:PlatformString( 244 Section).toMultibyte()]; 245 dictionary = [infoDictionary objectForKey:sectionKey]; 246 } 247 else { 248 dictionary = infoDictionary; 249 } 250 251 for (id key in dictionary) { 252 id option = [dictionary valueForKey:key]; 253 254 if ([key isKindOfClass:[NSString class]] && 255 [option isKindOfClass:[NSString class]]) { 256 TString name = [key UTF8String]; 257 TString value = [option UTF8String]; 258 result->Append(Section, name, value); 259 } 260 } 261 } 262 263 // Convert parts of the info.plist to the INI format the rest of the jpackager 264 // uses unless a jpackager config file exists. 265 ISectionalPropertyContainer* MacPlatform::GetConfigFile(TString FileName) { 266 IniFile* result = new IniFile(); 267 if (result == NULL) { 268 return NULL; 269 } 270 271 if (UsePListForConfigFile() == false) { 272 if (result->LoadFromFile(FileName) == false) { 273 // New property file format was not found, 274 // attempt to load old property file format. 275 Helpers::LoadOldConfigFile(FileName, result); 276 } 277 } 278 else { 279 NSBundle *mainBundle = [NSBundle mainBundle]; 280 NSDictionary *infoDictionary = [mainBundle infoDictionary]; 281 std::map<TString, TString> keys = GetKeys(); 282 283 // JPackager options. 284 AppendPListDictionaryToIniFile(infoDictionary, result, 285 keys[CONFIG_SECTION_APPLICATION], false); 286 287 // jvmargs 288 AppendPListArrayToIniFile(infoDictionary, result, 289 keys[CONFIG_SECTION_JVMOPTIONS]); 290 291 // Generate AppCDS Cache 292 AppendPListDictionaryToIniFile(infoDictionary, result, 293 keys[CONFIG_SECTION_APPCDSJVMOPTIONS]); 294 AppendPListDictionaryToIniFile(infoDictionary, result, 295 keys[CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS]); 296 297 // args 298 AppendPListArrayToIniFile(infoDictionary, result, 299 keys[CONFIG_SECTION_ARGOPTIONS]); 300 } 301 302 return result; 303 } 304 305 TString GetModuleFileNameOSX() { 306 Dl_info module_info; 307 if (dladdr(reinterpret_cast<void*>(GetModuleFileNameOSX), 308 &module_info) == 0) { 309 // Failed to find the symbol we asked for. 310 return std::string(); 311 } 312 return TString(module_info.dli_fname); 313 } 314 315 #include <mach-o/dyld.h> 316 317 TString MacPlatform::GetModuleFileName() { 318 //return GetModuleFileNameOSX(); 319 320 TString result; 321 DynamicBuffer<TCHAR> buffer(MAX_PATH); 322 uint32_t size = buffer.GetSize(); 323 324 if (_NSGetExecutablePath(buffer.GetData(), &size) == 0) { 325 result = FileSystemStringToString(buffer.GetData()); 326 } 327 328 return result; 329 } 330 331 bool MacPlatform::IsMainThread() { 332 bool result = (pthread_main_np() == 1); 333 return result; 334 } 335 336 TPlatformNumber MacPlatform::GetMemorySize() { 337 unsigned long long memory = [[NSProcessInfo processInfo] physicalMemory]; 338 339 // Convert from bytes to megabytes. 340 TPlatformNumber result = memory / 1048576; 341 342 return result; 343 } 344 345 std::map<TString, TString> MacPlatform::GetKeys() { 346 std::map<TString, TString> keys; 347 348 if (UsePListForConfigFile() == false) { 349 return GenericPlatform::GetKeys(); 350 } 351 else { 352 keys.insert(std::map<TString, TString>::value_type(CONFIG_VERSION, 353 _T("app.version"))); 354 keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINJAR_KEY, 355 _T("JVMMainJarName"))); 356 keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINMODULE_KEY, 357 _T("JVMMainModuleName"))); 358 keys.insert(std::map<TString, TString>::value_type( 359 CONFIG_MAINCLASSNAME_KEY, _T("JVMMainClassName"))); 360 keys.insert(std::map<TString, TString>::value_type( 361 CONFIG_CLASSPATH_KEY, _T("JVMAppClasspath"))); 362 keys.insert(std::map<TString, TString>::value_type(APP_NAME_KEY, 363 _T("CFBundleName"))); 364 keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_ID_KEY, 365 _T("JVMPreferencesID"))); 366 keys.insert(std::map<TString, TString>::value_type(JVM_RUNTIME_KEY, 367 _T("JVMRuntime"))); 368 keys.insert(std::map<TString, TString>::value_type(JPACKAGER_APP_DATA_DIR, 369 _T("CFBundleIdentifier"))); 370 371 keys.insert(std::map<TString, TString>::value_type(CONFIG_SPLASH_KEY, 372 _T("app.splash"))); 373 keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_MEMORY, 374 _T("app.memory"))); 375 keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_DEBUG, 376 _T("app.debug"))); 377 keys.insert(std::map<TString, TString>::value_type( 378 CONFIG_APPLICATION_INSTANCE, _T("app.application.instance"))); 379 380 keys.insert(std::map<TString, TString>::value_type( 381 CONFIG_SECTION_APPLICATION, _T("Application"))); 382 keys.insert(std::map<TString, TString>::value_type( 383 CONFIG_SECTION_JVMOPTIONS, _T("JVMOptions"))); 384 keys.insert(std::map<TString, TString>::value_type( 385 CONFIG_SECTION_APPCDSJVMOPTIONS, _T("AppCDSJVMOptions"))); 386 keys.insert(std::map<TString, TString>::value_type( 387 CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS, 388 _T("AppCDSGenerateCacheJVMOptions"))); 389 keys.insert(std::map<TString, TString>::value_type( 390 CONFIG_SECTION_ARGOPTIONS, _T("ArgOptions"))); 391 } 392 393 return keys; 394 } 395 396 #ifdef DEBUG 397 bool MacPlatform::IsNativeDebuggerPresent() { 398 int state; 399 int mib[4]; 400 struct kinfo_proc info; 401 size_t size; 402 403 info.kp_proc.p_flag = 0; 404 405 mib[0] = CTL_KERN; 406 mib[1] = KERN_PROC; 407 mib[2] = KERN_PROC_PID; 408 mib[3] = getpid(); 409 410 size = sizeof(info); 411 state = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); 412 assert(state == 0); 413 return ((info.kp_proc.p_flag & P_TRACED) != 0); 414 } 415 416 int MacPlatform::GetProcessID() { 417 int pid = [[NSProcessInfo processInfo] processIdentifier]; 418 return pid; 419 } 420 #endif //DEBUG 421 422 #endif //MAC