Android手游绘制基础--02动态获取游戏pid

本文介绍了在Android平台上动态获取游戏进程PID的方法,包括简单获取PID的API使用和考虑兼容性的目录遍历方案。通过阅读进程目录中的cmdline文件与包名匹配,找到对应进程的PID,为后续读取游戏内存数据奠定基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何动态获取游戏的pid

在读取第三方应用的时候需要使用到pid数据,读取内存,但是pid数据每次app杀死后重启都会变,动态获取pid是必须要的功能,也是基础。

简单获取pid

在Android中其实有api可以获取pid。

# pidof 完整包名
dipper:/ $ su
dipper:/ # pidof com.herocraft.game.free.mig29
25452

这个是在终端上面获取的,在我们写代码之前,都可以先在终端做尝试,然后想办法转成代码。下面就是c++的实现。

/**
 * 传递包名
 * @param name 目标包名
 * @return 返回app的pid
 */
pid_t get_game_pid(char *name) {
    FILE *fp;
    // 储存拿到的pid
    pid_t pid;
    // 命令拼接
    char cmd[0x100] = "pidof %s";
    char exec[128] = {0};
    // 把pidof 和包名拼接在一起组成命令
    sprintf(exec, cmd, name);
    // popen执行命令,等同于终端执行
    fp = popen(exec, "r");
    // 拿到结构后储存到pid变量中
    fscanf(fp, "%d", &pid);
    pclose(fp);
    return pid;
}

根据我们前面文章配置好的环境一键编译运行:
在这里插入图片描述
可以拿到正常app对应的pid了。这种方式可能存在兼容性问题。

获取pid的兼容性方案

在系统的/proc目录中全部进程的pid都创建一个文件夹:
在这里插入图片描述
现在杀死app,重新读取一次pid看看他在哪个文件夹中。

dipper:/proc # pidof com.herocraft.game.free.mig29
28910 # 通过pidof拿到了app的pid是28910
dipper:/proc # cd 28910/
dipper:/proc/28910 # ls
attr                    cpuset                  map_files   oom_score             sched_wake_up_idle  task
auxv                    cwd                     maps        oom_score_adj         schedstat           time_in_state
cgroup                  environ                 mem         pagemap               smaps               timerslack_ns
clear_refs              exe                     mountinfo   personality           smaps_rollup        wchan
cmdline                 fd                      mounts      reclaim               stack
comm                    fdinfo                  mountstats  root                  stat
concurrent_active_time  hang_detection_enabled  net         sched                 statm
concurrent_policy_time  io                      ns          sched_group_id        status
coredump_filter         limits                  oom_adj     sched_init_task_load  syscall
dipper:/proc/28910 # cat cmdline
com.herocraft.game.free.mig29 # 在pid目录中有一个文件cmdline里面保存了包名

也就是我们遍历/proc/目录中的所有一级目录的cmdline文件读取他和我们目标的包名判断,如果他们一致,就表示找到了,当前文件所在的目录就是pid了。
上面的规则用代码实现:

int getPID(const char *packageName) {
    // 默认pid是-1,如果返回-1就是读取失败
    int id = -1;
    DIR *dir;
    FILE *fp;
    char filename[64];
    char cmdline[64];
    struct dirent *entry;
    // 打开proc目录
    dir = opendir("/proc");
    while ((entry = readdir(dir)) != NULL) {
        // 目录名字就是pid,转int
        id = atoi(entry->d_name);
        if (id != 0) {
            // 把目录和cmdline拼接一起读取
            sprintf(filename, "/proc/%d/cmdline", id);
            fp = fopen(filename, "r");
            if (fp) {
                fgets(cmdline, sizeof(cmdline), fp);
                fclose(fp);
                // 判断传递进来的包名和cmdline中字符串是否一样
                if (strcmp(packageName, cmdline) == 0) {
                    // 如果一致,上面目录就是pid了
                    return id;
                }
            }
        }
    }
    closedir(dir);
    return -1;
}

在这里插入图片描述
这样遍历也能拿到pid,兼容性高,至于使用那个方案,自己喜欢就行。

下面是完整的代码:

#include <stdio.h>
#include <unistd.h>
#include <string>
#include <dirent.h>

/**
 * 传递包名
 * @param name 目标包名
 * @return 返回app的pid
 */
pid_t get_game_pid(char *name) {
    FILE *fp;
    // 储存拿到的pid
    pid_t pid;
    // 命令拼接
    char cmd[0x100] = "pidof %s";
    char exec[128] = {0};
    // 把pidof 和包名拼接在一起组成命令
    sprintf(exec, cmd, name);
    // popen执行命令,等同于终端执行
    fp = popen(exec, "r");
    // 拿到结构后储存到pid变量中
    fscanf(fp, "%d", &pid);
    pclose(fp);
    return pid;
}

int getPID(const char *packageName) {
    // 默认pid是-1,如果返回-1就是读取失败
    int id = -1;
    DIR *dir;
    FILE *fp;
    char filename[64];
    char cmdline[64];
    struct dirent *entry;
    // 打开proc目录
    dir = opendir("/proc");
    while ((entry = readdir(dir)) != NULL) {
        // 目录名字就是pid,转int
        id = atoi(entry->d_name);
        if (id != 0) {
            // 把目录和cmdline拼接一起读取
            sprintf(filename, "/proc/%d/cmdline", id);
            fp = fopen(filename, "r");
            if (fp) {
                fgets(cmdline, sizeof(cmdline), fp);
                fclose(fp);
                // 判断传递进来的包名和cmdline中字符串是否一样
                if (strcmp(packageName, cmdline) == 0) {
                    // 如果一致,上面目录就是pid了
                    return id;
                }
            }
        }
    }
    closedir(dir);
    return -1;
}

int main() {
    printf("读取游戏的pid\n");

    pid_t game_pid = get_game_pid("com.herocraft.game.free.mig29");
    printf("pid: %d\n", game_pid);

    int pid = getPID("com.herocraft.game.free.mig29");
    printf("pid_proc: %d\n", pid);

    return 0;
}

总结

1、动态读取app的pid。
2、这些代码都是模板,写一次就足够了,可以自己收集起来统一存放到一个头文件中。
3、下一篇是读取app的内存中的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hello223344

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值