Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 1 | //===-- RNBServices.cpp -----------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // Created by Christopher Friesen on 3/21/08. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
Bruce Mitchener | a026de0 | 2015-07-22 17:31:44 +0000 | [diff] [blame] | 14 | #include "RNBServices.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 15 | |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 16 | #include "CFString.h" |
Bruce Mitchener | a026de0 | 2015-07-22 17:31:44 +0000 | [diff] [blame] | 17 | #include "DNBLog.h" |
Greg Clayton | 6f35f5c | 2010-09-09 06:32:46 +0000 | [diff] [blame] | 18 | #include "MacOSX/CFUtils.h" |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 19 | #include <CoreFoundation/CoreFoundation.h> |
| 20 | #include <libproc.h> |
| 21 | #include <sys/sysctl.h> |
| 22 | #include <unistd.h> |
| 23 | #include <vector> |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 24 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 25 | // For now only SpringBoard has a notion of "Applications" that it can list for |
| 26 | // us. |
Jason Molenda | a332978 | 2014-03-29 18:54:20 +0000 | [diff] [blame] | 27 | // So we have to use the SpringBoard API's here. |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 28 | #if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) |
Bruce Mitchener | a026de0 | 2015-07-22 17:31:44 +0000 | [diff] [blame] | 29 | #include <SpringBoardServices/SpringBoardServices.h> |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 30 | #endif |
| 31 | |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 32 | // From DNB.cpp |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 33 | size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos); |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 34 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 35 | int GetProcesses(CFMutableArrayRef plistMutableArray, bool all_users) { |
| 36 | if (plistMutableArray == NULL) |
| 37 | return -1; |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 38 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 39 | // Running as root, get all processes |
| 40 | std::vector<struct kinfo_proc> proc_infos; |
| 41 | const size_t num_proc_infos = GetAllInfos(proc_infos); |
| 42 | if (num_proc_infos > 0) { |
| 43 | const pid_t our_pid = getpid(); |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 44 | const uid_t our_uid = getuid(); |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 45 | uint32_t i; |
| 46 | CFAllocatorRef alloc = kCFAllocatorDefault; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 47 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 48 | for (i = 0; i < num_proc_infos; i++) { |
| 49 | struct kinfo_proc &proc_info = proc_infos[i]; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 50 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 51 | bool kinfo_user_matches; |
| 52 | // Special case, if lldb is being run as root we can attach to anything. |
| 53 | if (all_users) |
| 54 | kinfo_user_matches = true; |
| 55 | else |
| 56 | kinfo_user_matches = proc_info.kp_eproc.e_pcred.p_ruid == our_uid; |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 57 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 58 | const pid_t pid = proc_info.kp_proc.p_pid; |
| 59 | // Skip zombie processes and processes with unset status |
| 60 | if (kinfo_user_matches == false || // User is acceptable |
| 61 | pid == our_pid || // Skip this process |
| 62 | pid == 0 || // Skip kernel (kernel pid is zero) |
| 63 | proc_info.kp_proc.p_stat == |
| 64 | SZOMB || // Zombies are bad, they like brains... |
| 65 | proc_info.kp_proc.p_flag & P_TRACED || // Being debugged? |
| 66 | proc_info.kp_proc.p_flag & P_WEXIT || // Working on exiting? |
| 67 | proc_info.kp_proc.p_flag & |
| 68 | P_TRANSLATED) // Skip translated ppc (Rosetta) |
| 69 | continue; |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 70 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 71 | // Create a new mutable dictionary for each application |
| 72 | CFReleaser<CFMutableDictionaryRef> appInfoDict( |
| 73 | ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, |
| 74 | &kCFTypeDictionaryValueCallBacks)); |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 75 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 76 | // Get the process id for the app (if there is one) |
| 77 | const int32_t pid_int32 = pid; |
| 78 | CFReleaser<CFNumberRef> pidCFNumber( |
| 79 | ::CFNumberCreate(alloc, kCFNumberSInt32Type, &pid_int32)); |
| 80 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PID_KEY, |
| 81 | pidCFNumber.get()); |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 82 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 83 | // Set the a boolean to indicate if this is the front most |
| 84 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, |
| 85 | kCFBooleanFalse); |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 86 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 87 | const char *pid_basename = proc_info.kp_proc.p_comm; |
| 88 | char proc_path_buf[PATH_MAX]; |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 89 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 90 | int return_val = proc_pidpath(pid, proc_path_buf, PATH_MAX); |
| 91 | if (return_val > 0) { |
| 92 | // Okay, now search backwards from that to see if there is a |
| 93 | // slash in the name. Note, even though we got all the args we don't |
| 94 | // care |
| 95 | // because the list data is just a bunch of concatenated null terminated |
| 96 | // strings |
| 97 | // so strrchr will start from the end of argv0. |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 98 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 99 | pid_basename = strrchr(proc_path_buf, '/'); |
| 100 | if (pid_basename) { |
| 101 | // Skip the '/' |
| 102 | ++pid_basename; |
| 103 | } else { |
| 104 | // We didn't find a directory delimiter in the process argv[0], just |
| 105 | // use what was in there |
| 106 | pid_basename = proc_path_buf; |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 107 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 108 | CFString cf_pid_path(proc_path_buf); |
| 109 | if (cf_pid_path.get()) |
| 110 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PATH_KEY, |
| 111 | cf_pid_path.get()); |
| 112 | } |
| 113 | |
| 114 | if (pid_basename && pid_basename[0]) { |
| 115 | CFString pid_name(pid_basename); |
| 116 | ::CFDictionarySetValue(appInfoDict.get(), |
| 117 | DTSERVICES_APP_DISPLAY_NAME_KEY, pid_name.get()); |
| 118 | } |
| 119 | |
| 120 | // Append the application info to the plist array |
| 121 | ::CFArrayAppendValue(plistMutableArray, appInfoDict.get()); |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 122 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 123 | } |
| 124 | return 0; |
| 125 | } |
| 126 | int ListApplications(std::string &plist, bool opt_runningApps, |
| 127 | bool opt_debuggable) { |
| 128 | int result = -1; |
| 129 | |
| 130 | CFAllocatorRef alloc = kCFAllocatorDefault; |
| 131 | |
| 132 | // Create a mutable array that we can populate. Specify zero so it can be of |
| 133 | // any size. |
| 134 | CFReleaser<CFMutableArrayRef> plistMutableArray( |
| 135 | ::CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks)); |
| 136 | |
| 137 | const uid_t our_uid = getuid(); |
| 138 | |
| 139 | #if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) |
| 140 | |
| 141 | if (our_uid == 0) { |
| 142 | bool all_users = true; |
| 143 | result = GetProcesses(plistMutableArray.get(), all_users); |
| 144 | } else { |
| 145 | CFReleaser<CFStringRef> sbsFrontAppID( |
| 146 | ::SBSCopyFrontmostApplicationDisplayIdentifier()); |
| 147 | CFReleaser<CFArrayRef> sbsAppIDs(::SBSCopyApplicationDisplayIdentifiers( |
| 148 | opt_runningApps, opt_debuggable)); |
| 149 | |
| 150 | // Need to check the return value from SBSCopyApplicationDisplayIdentifiers. |
| 151 | CFIndex count = sbsAppIDs.get() ? ::CFArrayGetCount(sbsAppIDs.get()) : 0; |
| 152 | CFIndex i = 0; |
| 153 | for (i = 0; i < count; i++) { |
| 154 | CFStringRef displayIdentifier = |
| 155 | (CFStringRef)::CFArrayGetValueAtIndex(sbsAppIDs.get(), i); |
| 156 | |
| 157 | // Create a new mutable dictionary for each application |
| 158 | CFReleaser<CFMutableDictionaryRef> appInfoDict( |
| 159 | ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, |
| 160 | &kCFTypeDictionaryValueCallBacks)); |
| 161 | |
| 162 | // Get the process id for the app (if there is one) |
| 163 | pid_t pid = INVALID_NUB_PROCESS; |
| 164 | if (::SBSProcessIDForDisplayIdentifier((CFStringRef)displayIdentifier, |
| 165 | &pid) == true) { |
| 166 | CFReleaser<CFNumberRef> pidCFNumber( |
| 167 | ::CFNumberCreate(alloc, kCFNumberSInt32Type, &pid)); |
| 168 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PID_KEY, |
| 169 | pidCFNumber.get()); |
| 170 | } |
| 171 | |
| 172 | // Set the a boolean to indicate if this is the front most |
| 173 | if (sbsFrontAppID.get() && displayIdentifier && |
| 174 | (::CFStringCompare(sbsFrontAppID.get(), displayIdentifier, 0) == |
| 175 | kCFCompareEqualTo)) |
| 176 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, |
| 177 | kCFBooleanTrue); |
| 178 | else |
| 179 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, |
| 180 | kCFBooleanFalse); |
| 181 | |
| 182 | CFReleaser<CFStringRef> executablePath( |
| 183 | ::SBSCopyExecutablePathForDisplayIdentifier(displayIdentifier)); |
| 184 | if (executablePath.get() != NULL) { |
| 185 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PATH_KEY, |
| 186 | executablePath.get()); |
| 187 | } |
| 188 | |
| 189 | CFReleaser<CFStringRef> iconImagePath( |
| 190 | ::SBSCopyIconImagePathForDisplayIdentifier(displayIdentifier)); |
| 191 | if (iconImagePath.get() != NULL) { |
| 192 | ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY, |
| 193 | iconImagePath.get()); |
| 194 | } |
| 195 | |
| 196 | CFReleaser<CFStringRef> localizedDisplayName( |
| 197 | ::SBSCopyLocalizedApplicationNameForDisplayIdentifier( |
| 198 | displayIdentifier)); |
| 199 | if (localizedDisplayName.get() != NULL) { |
| 200 | ::CFDictionarySetValue(appInfoDict.get(), |
| 201 | DTSERVICES_APP_DISPLAY_NAME_KEY, |
| 202 | localizedDisplayName.get()); |
| 203 | } |
| 204 | |
| 205 | // Append the application info to the plist array |
| 206 | ::CFArrayAppendValue(plistMutableArray.get(), appInfoDict.get()); |
| 207 | } |
| 208 | } |
Jason Molenda | a332978 | 2014-03-29 18:54:20 +0000 | [diff] [blame] | 209 | #else // #if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 210 | // When root, show all processes |
| 211 | bool all_users = (our_uid == 0); |
| 212 | GetProcesses(plistMutableArray.get(), all_users); |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 213 | #endif |
Greg Clayton | 9eb4e03 | 2012-11-06 23:36:26 +0000 | [diff] [blame] | 214 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 215 | CFReleaser<CFDataRef> plistData( |
| 216 | ::CFPropertyListCreateXMLData(alloc, plistMutableArray.get())); |
| 217 | |
| 218 | // write plist to service port |
| 219 | if (plistData.get() != NULL) { |
| 220 | CFIndex size = ::CFDataGetLength(plistData.get()); |
| 221 | const UInt8 *bytes = ::CFDataGetBytePtr(plistData.get()); |
| 222 | if (bytes != NULL && size > 0) { |
| 223 | plist.assign((char *)bytes, size); |
| 224 | return 0; // Success |
| 225 | } else { |
| 226 | DNBLogError("empty application property list."); |
| 227 | result = -2; |
| 228 | } |
| 229 | } else { |
| 230 | DNBLogError("serializing task list."); |
| 231 | result = -3; |
| 232 | } |
| 233 | |
| 234 | return result; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 235 | } |