ProcessUtils_mac.mm (3947B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "ProcessUtils.h" 6 7 #include "nsObjCExceptions.h" 8 #include "nsCocoaUtils.h" 9 #include "nsString.h" 10 #include "mozilla/Sprintf.h" 11 12 #define UNDOCUMENTED_SESSION_CONSTANT ((int)-2) 13 14 namespace mozilla { 15 namespace ipc { 16 17 static void* sApplicationASN = NULL; 18 static void* sApplicationInfoItem = NULL; 19 20 // 21 // Sets the process name to the concatenation of the bundlekCFBundleNameKey 22 // value and the 'aProcessName' argument. If aProcessName is the empty string, 23 // the process name will be set to just the kCFBundleNameKey value. 24 // 25 void SetThisProcessName(const char* aProcessName) { 26 NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 27 nsAutoreleasePool localPool; 28 29 if (!aProcessName) { 30 return; 31 } 32 33 NSString* currentName = [[[NSBundle mainBundle] localizedInfoDictionary] 34 objectForKey:(NSString*)kCFBundleNameKey]; 35 36 char formattedName[1024]; 37 if (strcmp(aProcessName, "") == 0) { 38 SprintfLiteral(formattedName, "%s", [currentName UTF8String]); 39 } else { 40 SprintfLiteral(formattedName, "%s %s", [currentName UTF8String], 41 aProcessName); 42 } 43 44 aProcessName = formattedName; 45 46 // This function is based on Chrome/Webkit's and relies on potentially 47 // dangerous SPI. 48 typedef CFTypeRef (*LSGetASNType)(); 49 typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef, 50 CFStringRef, CFDictionaryRef*); 51 52 CFBundleRef launchServices = 53 ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices")); 54 if (!launchServices) { 55 NS_WARNING( 56 "Failed to set process name: Could not open LaunchServices bundle"); 57 return; 58 } 59 60 if (!sApplicationASN) { 61 sApplicationASN = ::CFBundleGetFunctionPointerForName( 62 launchServices, CFSTR("_LSGetCurrentApplicationASN")); 63 if (!sApplicationASN) { 64 NS_WARNING("Failed to set process name: Could not get function pointer " 65 "for LaunchServices"); 66 return; 67 } 68 } 69 70 LSGetASNType getASNFunc = reinterpret_cast<LSGetASNType>(sApplicationASN); 71 72 if (!sApplicationInfoItem) { 73 sApplicationInfoItem = ::CFBundleGetFunctionPointerForName( 74 launchServices, CFSTR("_LSSetApplicationInformationItem")); 75 } 76 77 LSSetInformationItemType setInformationItemFunc = 78 reinterpret_cast<LSSetInformationItemType>(sApplicationInfoItem); 79 80 void* displayNameKeyAddr = ::CFBundleGetDataPointerForName( 81 launchServices, CFSTR("_kLSDisplayNameKey")); 82 83 CFStringRef displayNameKey = nil; 84 if (displayNameKeyAddr) { 85 displayNameKey = 86 reinterpret_cast<CFStringRef>(*(CFStringRef*)displayNameKeyAddr); 87 } 88 89 // We need this to ensure we have a connection to the Process Manager, not 90 // doing so will silently fail and process name wont be updated. 91 ProcessSerialNumber psn; 92 if (::GetCurrentProcess(&psn) != noErr) { 93 return; 94 } 95 96 CFTypeRef currentAsn = getASNFunc ? getASNFunc() : nullptr; 97 98 if (!getASNFunc || !setInformationItemFunc || !displayNameKey || 99 !currentAsn) { 100 NS_WARNING("Failed to set process name: Accessing launchServices failed"); 101 return; 102 } 103 104 CFStringRef processName = 105 ::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII); 106 if (!processName) { 107 NS_WARNING("Failed to set process name: Could not create CFStringRef"); 108 return; 109 } 110 111 OSErr err = setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn, 112 displayNameKey, processName, 113 nil); // Optional out param 114 ::CFRelease(processName); 115 if (err != noErr) { 116 NS_WARNING("Failed to set process name: LSSetInformationItemType err"); 117 return; 118 } 119 120 return; 121 NS_OBJC_END_TRY_ABORT_BLOCK; 122 } 123 124 } // namespace ipc 125 } // namespace mozilla