登录
  • 欢迎访问 Sharezer Blog

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

IOS sharezer 来源:山里孩子往外走 2209次浏览 已收录 0个评论

方法一: 用 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 中也可以正常获取到。

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

参考资料


Sharezer , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明MacOS开发-获取正在运行的所有进程名及pid
喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址