11

使用此问题中描述的方法,我可以获得在 iOS 设备上运行的应用程序列表。我知道 PID 并且可以访问它们的kinfo_proc结构。如何确定哪些是前台进程,哪些是后台(假设我的应用程序是后台)?

我试图根据kinfo_procvia 中的信息(参见第一个链接)找到这一点kp_proc.p_priority,但看起来不可能从优先级推断背景/前景状态。

我真的不在乎这是否适用于 AppStore Review,但我更喜欢一种无需越狱即可工作的方法(即私有 API 可以,但哪些?)。我希望这至少可以在 iOS 5 上运行

我考虑过编写一个简单的MobileSubstrate扩展,将其注入所有应用程序并挂钩每个人的应用程序applicationDidBecomeActive,但这需要越狱并且侵入性太大。

4

3 回答 3

10

好吧,看起来在模拟器的 SpringBoardServices 二进制文件上使用 nm 和 IDA 对我有所帮助。以下代码适用于在 iPod Touch 4、iPhone 4 和 iPad1 WiFi(全非 JB)上运行的 iOS 5.0.1 当然,您永远不应该尝试将其提交到 AppStore

- (NSArray*) getActiveApps
{
mach_port_t *p;
void *uikit = dlopen(UIKITPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() = 
dlsym(uikit, "SBSSpringBoardServerPort");
p = (mach_port_t *)SBSSpringBoardServerPort(); 
dlclose(uikit);

void *sbserv = dlopen(SBSERVPATH, RTLD_LAZY);
NSArray* (*SBSCopyApplicationDisplayIdentifiers)(mach_port_t* port, BOOL runningApps,BOOL debuggable) = 
dlsym(sbserv, "SBSCopyApplicationDisplayIdentifiers");
//SBDisplayIdentifierForPID - protype assumed,verification of params done
void* (*SBDisplayIdentifierForPID)(mach_port_t* port, int pid,char * result) = 
dlsym(sbserv, "SBDisplayIdentifierForPID");
//SBFrontmostApplicationDisplayIdentifier - prototype assumed,verification of params done,don't call this TOO often(every second on iPod touch 4G is 'too often,every 5 seconds is not)
void* (*SBFrontmostApplicationDisplayIdentifier)(mach_port_t* port,char * result) = 
dlsym(sbserv, "SBFrontmostApplicationDisplayIdentifier");



//Get frontmost application
char frontmostAppS[256];
memset(frontmostAppS,sizeof(frontmostAppS),0);
SBFrontmostApplicationDisplayIdentifier(p,frontmostAppS);
NSString * frontmostApp=[NSString stringWithFormat:@"%s",frontmostAppS];
//NSLog(@"Frontmost app is %@",frontmostApp);
//get list of running apps from SpringBoard
NSArray *allApplications = SBSCopyApplicationDisplayIdentifiers(p,NO, NO);
//Really returns ACTIVE applications(from multitasking bar)
/*   NSLog(@"Active applications:");
 for(NSString *identifier in allApplications) {
 // NSString * locName=SBSCopyLocalizedApplicationNameForDisplayIdentifier(p,identifier);
 NSLog(@"Active Application:%@",identifier);
 }
 */ 

//get list of all apps from kernel
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
size_t 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 = size / sizeof(struct kinfo_proc);

        if (nprocess){

            NSMutableArray * array = [[NSMutableArray alloc] init];

            for (int i = nprocess - 1; i >= 0; i--){

                int ruid=process[i].kp_eproc.e_pcred.p_ruid;
                int uid=process[i].kp_eproc.e_ucred.cr_uid;
                //short int nice=process[i].kp_proc.p_nice;
                //short int u_prio=process[i].kp_proc.p_usrpri;
                short int prio=process[i].kp_proc.p_priority;
                NSString * processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid];
                NSString * processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm];


                BOOL systemProcess=YES;
                if (ruid==501)
                    systemProcess=NO;



                char * appid[256];
                memset(appid,sizeof(appid),0);
                int intID,intID2;
                intID=process[i].kp_proc.p_pid,appid;
                SBDisplayIdentifierForPID(p,intID,appid);/

                NSString * appId=[NSString stringWithFormat:@"%s",appid];

                if (systemProcess==NO)
                {
                    if ([appId isEqualToString:@""])
                    {
                        //final check.if no appid this is not springboard app
                        NSLog(@"(potentially system)Found process with PID:%@ name %@,isSystem:%d,Priority:%d",processID,processName,systemProcess,prio);
                    }
                    else
                    {

                        BOOL isFrontmost=NO;
                        if ([frontmostApp isEqualToString:appId])
                        {
                            isFrontmost=YES;
                        }
                        NSNumber *isFrontmostN=[NSNumber numberWithBool:isFrontmost];
                        NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName,appId,isFrontmostN, nil] 
                                                                            forKeys:[NSArray arrayWithObjects:@"ProcessID", @"ProcessName",@"AppID",@"isFrontmost", nil]];

                        NSLog(@"PID:%@, name: %@, AppID:%@,isFrontmost:%d",processID,processName,appId,isFrontmost);
                        [array addObject:dict];
                    }
                }
            }

            free(process);
            return array;
        }
    }
  }

    dlclose(sbserv);
}

当然,第二个循环并不是绝对必要的,但我也需要非本地化的名称和 PID。

于 2011-11-26T13:41:50.603 回答
5

很好的答案!但是您的代码中有一个小错字,应该是:

首先确保定义了 SBSERVPATH 并且包含了正确的头文件:

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

#define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"

然后先找到正确的SB口:

mach_port_t *port;
void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() = 
dlsym(lib, "SBSSpringBoardServerPort");
port = (mach_port_t *)SBSSpringBoardServerPort(); 
dlclose(lib);

然后找到活动的应用程序:

mach_port_t * port = [self getSpringBoardPort];
// open springboard lib
void *lib = dlopen(SBSERVPATH, RTLD_LAZY);

// retrieve function SBFrontmostApplicationDisplayIdentifier
void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) =
dlsym(lib, "SBFrontmostApplicationDisplayIdentifier");

// reserve memory for name
char appId[256];
memset(appId, 0, sizeof(appId));

// retrieve front app name
SBFrontmostApplicationDisplayIdentifier(port, appId);

// close dynlib
dlclose(lib);
于 2012-09-07T09:50:31.303 回答
-1

这适用于所有 IOS 设备:

#define UIKITPATH "/System/Library/Framework/UIKit.framework/UIKit"
#define SBSERVPATH "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"

 - (NSArray*) getActiveApps
 {
mach_port_t *p;
void *uikit = dlopen(UIKITPATH, RTLD_LAZY);
int (*SBSSpringBoardServerPort)() =
dlsym(uikit, "SBSSpringBoardServerPort");
p = (mach_port_t *)SBSSpringBoardServerPort();
dlclose(uikit);

if(self.frameWorkPath == nil || self.frameWorkPath.length == 0)
{
    self.frameWorkPath = @SBSERVPATH;
    self.frameWorkPath = [self.frameWorkPath stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}

const char *cString = [self.frameWorkPath cStringUsingEncoding:NSUTF8StringEncoding];
//const char *bar = [self.frameWorkPath UTF8String];
void *sbserv = dlopen(cString, RTLD_LAZY);
NSArray* (*SBSCopyApplicationDisplayIdentifiers)(mach_port_t* port, BOOL runningApps,BOOL debuggable) =
dlsym(sbserv, "SBSCopyApplicationDisplayIdentifiers");
//SBDisplayIdentifierForPID - protype assumed,verification of params done
void* (*SBDisplayIdentifierForPID)(mach_port_t* port, int pid,char * result) =
dlsym(sbserv, "SBDisplayIdentifierForPID");
//SBFrontmostApplicationDisplayIdentifier - prototype assumed,verification of params done,don't call this TOO often(every second on iPod touch 4G is 'too often,every 5 seconds is not)
void* (*SBFrontmostApplicationDisplayIdentifier)(mach_port_t* port,char * result) =
dlsym(sbserv, "SBFrontmostApplicationDisplayIdentifier");



//Get frontmost application
char frontmostAppS[512];
memset(frontmostAppS,sizeof(frontmostAppS),0);
SBFrontmostApplicationDisplayIdentifier(p,frontmostAppS);
NSString * frontmostApp=[NSString stringWithFormat:@"%s",frontmostAppS];

if([self iOsMajorVersion] >= 7){
    NSNumber *topmost = [NSNumber numberWithBool:YES];
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    NSMutableArray  * splitted = [frontmostApp componentsSeparatedByString:@"."];
    if(frontmostApp.length > 0 && splitted != nil && splitted.count > 1 && topmost.boolValue == YES){
        NSString *appname = [splitted lastObject];
        [dict setObject:[appname capitalizedString] forKey:@"ProcessName"];
        [dict setObject:frontmostApp forKey:@"ProcessID"];
        [dict setObject:frontmostApp forKey:@"AppID"];
        [dict setObject:topmost forKey:@"isFrontmost"];
        NSLog(@"Running TOPMOST App %@",dict);
        return @[dict];
    }
    else{
        return nil;
    }
}
//NSLog(@"Frontmost app is %@",frontmostApp);
//get list of running apps from SpringBoard
NSArray *allApplications = SBSCopyApplicationDisplayIdentifiers(p,NO, NO);
//Really returns ACTIVE applications(from multitasking bar)
   NSLog(@"Active applications:");
 for(NSString *identifier in allApplications) {
     // NSString * locName=SBSCopyLocalizedApplicationNameForDisplayIdentifier(p,identifier);
     NSLog(@"Active Application:%@",identifier);
 }


//get list of all apps from kernel
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
size_t 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 = size / sizeof(struct kinfo_proc);

        if (nprocess){

            NSMutableArray * array = [[NSMutableArray alloc] init];

            for (int i = nprocess - 1; i >= 0; i--){

                int ruid=process[i].kp_eproc.e_pcred.p_ruid;
                int uid=process[i].kp_eproc.e_ucred.cr_uid;
                //short int nice=process[i].kp_proc.p_nice;
                //short int u_prio=process[i].kp_proc.p_usrpri;
                short int prio=process[i].kp_proc.p_priority;
                NSString * processID = [[NSString alloc] initWithFormat:@"%d", process[i].kp_proc.p_pid];
                NSString * processName = [[NSString alloc] initWithFormat:@"%s", process[i].kp_proc.p_comm];


                BOOL systemProcess=YES;
                if (ruid==501){
                    systemProcess=NO;
                }


                char * appid[256];
                memset(appid,sizeof(appid),0);
                int intID,intID2;
                intID=process[i].kp_proc.p_pid,appid;
                SBDisplayIdentifierForPID(p,intID,appid);

                NSString * appId=[NSString stringWithFormat:@"%s",appid];

                if (systemProcess==NO)
                {
                    if ([appId isEqualToString:@""])
                    {
                        //final check.if no appid this is not springboard app
                        //NSLog(@"(potentially system)Found process with PID:%@ name %@,isSystem:%d,Priority:%d",processID,processName,systemProcess,prio);
                    }
                    else
                    {

                        BOOL isFrontmost=NO;
                        if ([frontmostApp isEqualToString:appId])
                        {
                            isFrontmost=YES;
                        }
                        NSNumber *isFrontmostN=[NSNumber numberWithBool:isFrontmost];
                        NSDictionary * dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:processID, processName,appId,isFrontmostN, nil] 
                                                                            forKeys:[NSArray arrayWithObjects:@"ProcessID", @"ProcessName",@"AppID",@"isFrontmost", nil]];
                        NSLog(@"PID:%@, name: %@, AppID:%@,isFrontmost:%d",processID,processName,appId,isFrontmost);
                        [array addObject:dict];
                    }
                }
            }

            free(process);
            return array;
        }
    }
}

dlclose(sbserv);
 }
于 2014-06-09T14:51:25.883 回答