Bug 1885602 - Part 4: Implement navigating to the settings from the menu header for...
[gecko.git] / ipc / glue / ProcessUtils_mac.mm
blobe850c486aa87300c8422b109b89bb0b679f205fd
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/. */
5 #include "ProcessUtils.h"
7 #include "nsObjCExceptions.h"
8 #include "nsCocoaUtils.h"
9 #include "nsString.h"
10 #include "mozilla/Sprintf.h"
12 #define UNDOCUMENTED_SESSION_CONSTANT ((int)-2)
14 namespace mozilla {
15 namespace ipc {
17 static void* sApplicationASN = NULL;
18 static void* sApplicationInfoItem = NULL;
20 void SetThisProcessName(const char* aProcessName) {
21   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
22   nsAutoreleasePool localPool;
24   if (!aProcessName || strcmp(aProcessName, "") == 0) {
25     return;
26   }
28   NSString* currentName = [[[NSBundle mainBundle] localizedInfoDictionary]
29       objectForKey:(NSString*)kCFBundleNameKey];
31   char formattedName[1024];
32   SprintfLiteral(formattedName, "%s %s", [currentName UTF8String],
33                  aProcessName);
35   aProcessName = formattedName;
37   // This function is based on Chrome/Webkit's and relies on potentially
38   // dangerous SPI.
39   typedef CFTypeRef (*LSGetASNType)();
40   typedef OSStatus (*LSSetInformationItemType)(int, CFTypeRef, CFStringRef,
41                                                CFStringRef, CFDictionaryRef*);
43   CFBundleRef launchServices =
44       ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
45   if (!launchServices) {
46     NS_WARNING(
47         "Failed to set process name: Could not open LaunchServices bundle");
48     return;
49   }
51   if (!sApplicationASN) {
52     sApplicationASN = ::CFBundleGetFunctionPointerForName(
53         launchServices, CFSTR("_LSGetCurrentApplicationASN"));
54     if (!sApplicationASN) {
55       NS_WARNING("Failed to set process name: Could not get function pointer "
56                  "for LaunchServices");
57       return;
58     }
59   }
61   LSGetASNType getASNFunc = reinterpret_cast<LSGetASNType>(sApplicationASN);
63   if (!sApplicationInfoItem) {
64     sApplicationInfoItem = ::CFBundleGetFunctionPointerForName(
65         launchServices, CFSTR("_LSSetApplicationInformationItem"));
66   }
68   LSSetInformationItemType setInformationItemFunc =
69       reinterpret_cast<LSSetInformationItemType>(sApplicationInfoItem);
71   void* displayNameKeyAddr = ::CFBundleGetDataPointerForName(
72       launchServices, CFSTR("_kLSDisplayNameKey"));
74   CFStringRef displayNameKey = nil;
75   if (displayNameKeyAddr) {
76     displayNameKey =
77         reinterpret_cast<CFStringRef>(*(CFStringRef*)displayNameKeyAddr);
78   }
80   // We need this to ensure we have a connection to the Process Manager, not
81   // doing so will silently fail and process name wont be updated.
82   ProcessSerialNumber psn;
83   if (::GetCurrentProcess(&psn) != noErr) {
84     return;
85   }
87   CFTypeRef currentAsn = getASNFunc ? getASNFunc() : nullptr;
89   if (!getASNFunc || !setInformationItemFunc || !displayNameKey ||
90       !currentAsn) {
91     NS_WARNING("Failed to set process name: Accessing launchServices failed");
92     return;
93   }
95   CFStringRef processName =
96       ::CFStringCreateWithCString(nil, aProcessName, kCFStringEncodingASCII);
97   if (!processName) {
98     NS_WARNING("Failed to set process name: Could not create CFStringRef");
99     return;
100   }
102   OSErr err = setInformationItemFunc(UNDOCUMENTED_SESSION_CONSTANT, currentAsn,
103                                      displayNameKey, processName,
104                                      nil);  // Optional out param
105   ::CFRelease(processName);
106   if (err != noErr) {
107     NS_WARNING("Failed to set process name: LSSetInformationItemType err");
108     return;
109   }
111   return;
112   NS_OBJC_END_TRY_ABORT_BLOCK;
115 }  // namespace ipc
116 }  // namespace mozilla