|
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_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 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_JPACKAGE_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 jpackage |
|
264 // uses unless a jpackage 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 // JPackage 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(JPACKAGE_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 |