Mercurial > minori
view dep/animia/src/util/osx.cc @ 163:44c5e6dd9488
dep/animia/osx: move GetProcessName to util/osx so we can use it in quartz
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sat, 18 Nov 2023 00:47:40 -0500 |
parents | 61b76c7b656a |
children | 8937fb7f2d66 |
line wrap: on
line source
#include "animia/util/osx.h" #ifdef HAVE_COREFOUNDATION #include <CoreFoundation/CoreFoundation.h> #endif namespace animia::internal::osx::util { #ifdef HAVE_COREFOUNDATION /* All of these LaunchServices things use *internal functions* that are subject ** to change. Granted, it's not very likely that these will change very much ** because I'm fairly sure Apple uses them lots in their own internal code. */ /* from RDProcess */ typedef CFTypeRef (*LSASNCreateWithPidSpec)(CFAllocatorRef, pid_t); typedef CFDictionaryRef (*LSCopyApplicationInformationSpec)(int, CFTypeRef, CFArrayRef); static LSCopyApplicationInformationSpec LSCopyApplicationInformation = nullptr; static LSASNCreateWithPidSpec LSASNCreateWithPid = nullptr; /* retrieved from LaunchServicesSPI.h in WebKit */ static constexpr int kLSDefaultSessionID = -2; static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.LaunchServices"); /* retrieved dynamically */ static CFStringRef kLSDisplayNameKey = nullptr; static CFStringRef kLSPIDKey = nullptr; static bool GetLaunchServicesPrivateSymbols() { CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID); if (!launch_services_bundle) return false; LSCopyApplicationInformation = (LSCopyApplicationInformationSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSCopyApplicationInformation")); if (!LSCopyApplicationInformation) return false; LSASNCreateWithPid = (LSASNCreateWithPidSpec)CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSASNCreateWithPid")); if (!LSASNCreateWithPid) return false; kLSDisplayNameKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSDisplayNameKey")); if (!kLSDisplayNameKey) return false; kLSPIDKey = *(CFStringRef*)CFBundleGetDataPointerForName(launch_services_bundle, CFSTR("_kLSPIDKey")); if (!kLSPIDKey) return false; return true; } static bool LaunchServicesGetProcessName(pid_t pid, std::string& result) { if (!LSCopyApplicationInformation || !LSASNCreateWithPid) if (!GetLaunchServicesPrivateSymbols()) return false; CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); CFArrayRef request_array = CFArrayCreate(NULL, (const void **)kLSDisplayNameKey, 1, NULL); CFDictionaryRef dictionary = LSCopyApplicationInformation(kLaunchServicesMagicConstant, asn, request_array); CFRelease(request_array); if (!dictionary) return false; CFStringRef str; if (!CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, (CFTypeRef*)&str) || !str) { CFRelease(dictionary); return false; } CFRetain(str); CFRelease(dictionary); result.reserve(CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1); if (!CFStringGetCString(str, &result.front(), result.length(), result.length())) { CFRelease(str); return false; } CFRelease(str); return true; } #endif // HAVE_COREFOUNDATION static bool GetProcessArgs(pid_t pid, std::string& args) { /* sysctl shouldn't touch these, so we define them as const */ const int mib[3] = {CTL_KERN, KERN_PROCARGS2, static_cast<int>(pid)}; const size_t mib_size = sizeof(mib)/sizeof(*mib); /* Get the initial size of the array */ size_t size; { int ret = sysctl((int*)mib, mib_size, nullptr, &size, nullptr, 0); if (ret) return false; } /* Reserve the space for it in args */ args.resize(size); /* Get the contents of argc and argv */ { int ret = sysctl((int*)mib, mib_size, &args.front(), &size, NULL, 0); if (ret) return false; } /* Is the size big enough to hold at least argc? */ if (size < sizeof(int)) return false; args.resize(size); } static bool GetProcessNameFromArgs(pid_t pid, std::string& result) { if (!GetProcessArgs(pid, result)) return false; /* Get argc using memcpy */ int argc; memcpy(&argc, &args.front(), sizeof(argc)); /* Do we even have argv[0]? */ if (argc < 1) return false; /* Find the first null character */ size_t null_pos = args.find('\0', sizeof(argc)); if (null_pos == std::string::npos) return false; /* Find the last slash */ size_t last_slash = args.rfind('/', null_pos); if (last_slash == std::string::npos) return false; /* Return our result */ result = args.substr(last_slash + 1, null_pos - last_slash - 1); return true; } static bool GetProcessNameFromKernel(pid_t pid, std::string& result) { result.reserve(2*MAXCOMLEN); if (!proc_name(pid, &result.front(), result.length())) return false; result.shrink_to_fit(); return true; } static bool GetProcessName(pid_t pid, std::string& result) { #ifdef HAVE_COREFOUNDATION if (LaunchServicesGetProcessName(pid, result)) return true; #endif // HAVE_COREFOUNDATION /* Try parsing the arguments, this prevents the process name being cut off to 2*MAXCOMLEN (32 chars) */ if (GetProcessNameFromArgs(pid, result)) return true; /* Then attempt getting it from the kernel, which results in the process name being cut to 32 chars (worse, 16 chars if p_name is unavailable) */ if (GetProcessNameFromKernel(pid, result)) return true; return false; } }