1. Binder驱动初探
任务目标
编写一个C程序,读取/proc/binder/proc文件,解析其中记录的Binder进程信息,并输出每个使用Binder的进程PID、进程名(若可获取)以及该进程的Binder线程数量。该文件由内核Binder驱动在启用CONFIG_ANDROID_BINDER_IPC且挂载debugfs时生成,是观察Binder驱动运行时状态的最直接入口。
前置条件
- Linux内核已启用Binder驱动(Android环境或加载了
binder_linux模块的自编译内核) debugfs已挂载到/sys/kernel/debug,且当前用户有读取权限(通常需要root)- 系统中有至少一个进程正在使用Binder(如
servicemanager、surfaceflinger等),否则文件内容为空
实现思路
/proc/binder/proc的文本格式为:每个使用Binder的进程以proc开头,后跟PID;随后若干行以thread开头,后跟线程ID,表示该进程创建的Binder线程。解析时逐行扫描,遇到proc行记录新进程,遇到thread行累加计数。进程名通过读取/proc/[pid]/comm获得。
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE 256
#define PROC_PATH "/proc/binder/proc"
/* 从 /proc/[pid]/comm 读取进程名 */
static void get_process_name(int pid, char *buf, size_t size) {
char path[64];
FILE *fp;
snprintf(path, sizeof(path), "/proc/%d/comm", pid);
fp = fopen(path, "r");
if (fp) {
if (fgets(buf, size, fp)) {
buf[strcspn(buf, "\n")] = '\0'; /* 去掉换行 */
}
fclose(fp);
} else {
snprintf(buf, size, "<unknown>");
}
}
int main(void) {
FILE *fp = fopen(PROC_PATH, "r");
if (!fp) {
perror("fopen");
fprintf(stderr, "无法打开 %s(需要root权限且内核已启用Binder驱动)\n", PROC_PATH);
return 1;
}
char line[MAX_LINE];
int current_pid = -1;
int thread_count = 0;
int first = 1;
while (fgets(line, sizeof(line), fp)) {
/* 去掉行尾空白 */
line[strcspn(line, "\r\n")] = '\0';
if (strncmp(line, "proc ", 5) == 0) {
/* 先输出上一个进程的统计 */
if (current_pid != -1) {
char name[64];
get_process_name(current_pid, name, sizeof(name));
printf("PID %d (%s): %d Binder线程\n",
current_pid, name, thread_count);
}
/* 解析新进程PID */
current_pid = atoi(line + 5);
thread_count = 0;
first = 0;
} else if (strncmp(line, "thread ", 7) == 0 && current_pid != -1) {
thread_count++;
}
}
/* 输出最后一个进程 */
if (current_pid != -1) {
char name[64];
get_process_name(current_pid, name, sizeof(name));
printf("PID %d (%s): %d Binder线程\n",
current_pid, name, thread_count);
}
if (first) {
printf("当前没有进程使用Binder,或文件为空。\n");
}
fclose(fp);
return 0;
}
编译与运行
gcc -o binder_proc binder_proc.c
sudo ./binder_proc
验证方法
运行程序后,观察输出是否列出系统中使用Binder的进程及其线程数。可通过以下方式交叉验证:
- 直接执行
cat /proc/binder/proc,对比程序输出的PID和线程数量是否与原始文件一致 - 使用
ps -ef | grep servicemanager确认servicemanager进程存在,且其PID出现在程序输出中 - 若程序输出为空,检查
/proc/binder/proc是否存在且非空;若文件不存在,说明内核未启用Binder驱动或debugfs未挂载
预期输出示例
以下为基于文件内容的确定性解析结果(非实测数据),用于说明输出格式:
PID 1234 (servicemanager): 1 Binder线程
PID 5678 (surfaceflinger): 4 Binder线程
常见问题
- 无法打开文件:确认以root运行,且内核已加载Binder驱动(
ls /dev/binder应存在) - 输出为空:当前系统没有进程创建Binder上下文,或文件权限不足导致读到空内容
- 进程名显示unknown:进程可能在读取瞬间已退出,属正常现象