MacOS开发-获取正在运行的所有进程名及pid

方法一: 用applescript获取

applescript在开发中也非常好用。

tell application "System Events"
	set listOfProcesses to every process
	set allProcess to {}
	
	repeat with processItem in listOfProcesses
		set procname to name of processItem as string
		set processId to unix id of processItem as string
		set processDic to {ProcessName:procname, processId:processId}
		copy processDic to end of allProcess
	end repeat
	
	return allProcess
end tell

在项目中运行上述脚本,可获取到大部分正在运行中的Process,注意,是大部分,例如adb使用该方式获取不到,因此,继续探索其他方式。

方法二: 用ps ax获取

可以通过ps命令获取,但是该方法需要自己解析,速度和效率较低,在此不适用。

方法三: 用GetBSDProcessList获取

GetBSDProcessList函数(点我)可以获取到所有进程,但是在访问kinfo_proc结构体的kp_proc.p_comm时只有16位的长度。其定义如下:

#define MAXCOMLEN 16 //defined in param.h
struct extern_proc {  //defined in proc.h
  ...snip...
  char p_comm[MAXCOMLEN+1];
  ...snip...
};

方法四: 使用libProc.h获取

pid_t pids[1024];
int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);   
proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));    
for (int i = 0; i < numberOfProcesses; ++i) {
  if (pids[i] == 0) { continue; }
  char name[1024];
  proc_name(pids[i], name, sizeof(name));
  printf("Found process: %s\n", name);
}

虽然可以检索到信息,但是和GetBSDProcessList一样存在进程名显示不全的问题

方法五: 使用 ProcessManager 函数检索进程信息

ProcessSerialNumber psn;
psn.lowLongOfPSN = kNoProcess;
psn.highLongOfPSN = 0;
while (GetNextProcess(&psn) == noErr) {
  CFStringRef procName = NULL;
  if (CopyProcessName(&psn, &procName) == noErr) {
    NSLog(@"Found process: %@", (NSString *)procName);
  }
  CFRelease(procName);
}

抱歉,这种方式行不通。它只返回在WindowServer(或类似的东西)中注册的进程。换句话说,它只返回带有UI的应用程序,而且只针对当前用户。

方法六: 使用-[NSWorkspace launchedApplications]

只返回当前用户在Dock中出现的应用程序的信息。

方法七:虽然很简洁好用,但是OSX10.15beta中不管用的方法

#import <sys/proc_info.h>
#import <libproc.h>

int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
pid_t pids[numberOfProcesses];
bzero(pids, sizeof(pids));
proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
for (int i = 0; i < numberOfProcesses; ++i) {
    if (pids[i] == 0) { continue; }
    char pathBuffer[PROC_PIDPATHINFO_MAXSIZE];
    bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE);
    proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer));
    if (strlen(pathBuffer) > 0) {
        printf("path: %s\n", pathBuffer);
    }
}

这个方法很是管用,但是在OSX10.15beta系统中有问题,获取到的numberOfProcesses为0

方法八:终极解决办法,强烈建议使用!

#import <sys/sysctl.h>
#import <libproc.h>

- (NSArray *)runningProcesses {
    
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    u_int miblen = 4;
    
    size_t size;
    int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
    
    struct kinfo_proc * process = NULL;
    struct kinfo_proc * newprocess = NULL;
    
    do {
        size += size / 10;
        newprocess = realloc(process, size);
        
        if (!newprocess){
            
            if (process){
                free(process);
            }
            return nil;
        }
        process = newprocess;
        st = sysctl(mib, miblen, process, &size, NULL, 0);
        
    } while (st == -1 && errno == ENOMEM);
    
    if (st == 0){
        if (size % sizeof(struct kinfo_proc) == 0){
            int nprocess = (int)(size / sizeof(struct kinfo_proc));
            
            if (nprocess){
                NSMutableArray * array = [[NSMutableArray alloc] init];
                
                for (int i = nprocess - 1; i >= 0; i--){
                    pid_t pid = process[i].kp_proc.p_pid;
                    NSString * processID = [[NSString alloc] initWithFormat:@"%d", pid];
                    NSString * processName = [self getProcessNameWithPid:pid];
                    if (processName.length > 0 && processID.length > 0) {
                        NSDictionary * dict = @{@"ProcessName" : processName, @"ProcessID" : processID };
                        [array addObject:dict];
                    }
                }
                
                free(process);
                return [array copy];
            }
        }
    }
    
    return nil;
}

- (NSString *)getProcessNameWithPid:(pid_t)pid
{
    NSString *processName = @"";
    char pathBuffer [PROC_PIDPATHINFO_MAXSIZE];
    proc_pidpath(pid, pathBuffer, sizeof(pathBuffer));
    
    char nameBuffer[256];
    
    int position = (int)strlen(pathBuffer);
    while(position >= 0 && pathBuffer[position] != '/')
    {
        position--;
    }
    
    strcpy(nameBuffer, pathBuffer + position + 1);
    
    processName = [NSString stringWithUTF8String:nameBuffer];
    return processName;
}

该方法虽然稍显复杂,但是思路可做参考:它巧妙地通过processID,获取到该进程的路径path,然后截取路径path的lastComponent为其名称,进而获取到了进程名和id。
经过测试,该方法在OSX10.15beta中也可以正常获取到。

以上只是个人项目中所用总结,如有错误,恳请批评指正!如对您有帮助,点赞支持,谢谢!

参考资料

MacOS开发-获取正在运行的所有进程名及pidMacOS开发-获取正在运行的所有进程名及pid auspark 发布了49 篇原创文章 · 获赞 5 · 访问量 2万+ 私信 关注
上一篇:Android.22.Retrifit文件上传和下载


下一篇:MySQL学习记录