4. Binder进程上下文管理

任务目标

在Binder IPC框架中,每个客户端进程与服务端进程都需要独立的上下文记录,用于保存进程标识、调度优先级以及当前Binder通信状态。本案例实现一个轻量级的binder_proc_ctx结构体及其管理接口,支持上下文的创建、查询、更新与销毁,并模拟多进程并发访问时的状态切换。

核心实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define MAX_CTX 64
#define CTX_ACTIVE   0
#define CTX_BLOCKED  1
#define CTX_DEAD     2

typedef struct {
    int pid;
    int priority;      /* 0-99,数值越小优先级越高 */
    int state;         /* CTX_ACTIVE / CTX_BLOCKED / CTX_DEAD */
    char process_name[32];
} binder_proc_ctx;

static binder_proc_ctx ctx_table[MAX_CTX];
static int ctx_count = 0;
static pthread_mutex_t ctx_lock = PTHREAD_MUTEX_INITIALIZER;

/* 创建或更新进程上下文 */
int binder_ctx_register(int pid, const char *name, int priority) {
    if (!name || priority < 0 || priority > 99) return -1;
    pthread_mutex_lock(&ctx_lock);
    for (int i = 0; i < ctx_count; i++) {
        if (ctx_table[i].pid == pid) {
            ctx_table[i].priority = priority;
            ctx_table[i].state = CTX_ACTIVE;
            snprintf(ctx_table[i].process_name, sizeof(ctx_table[i].process_name), "%s", name);
            pthread_mutex_unlock(&ctx_lock);
            return 0;  /* 已存在,更新 */
        }
    }
    if (ctx_count >= MAX_CTX) {
        pthread_mutex_unlock(&ctx_lock);
        return -2;  /* 表满 */
    }
    ctx_table[ctx_count].pid = pid;
    ctx_table[ctx_count].priority = priority;
    ctx_table[ctx_count].state = CTX_ACTIVE;
    snprintf(ctx_table[ctx_count].process_name, sizeof(ctx_table[ctx_count].process_name), "%s", name);
    ctx_count++;
    pthread_mutex_unlock(&ctx_lock);
    return 1;  /* 新建 */
}

/* 查询进程上下文,返回指针;未找到返回NULL */
binder_proc_ctx *binder_ctx_lookup(int pid) {
    pthread_mutex_lock(&ctx_lock);
    for (int i = 0; i < ctx_count; i++) {
        if (ctx_table[i].pid == pid) {
            pthread_mutex_unlock(&ctx_lock);
            return &ctx_table[i];
        }
    }
    pthread_mutex_unlock(&ctx_lock);
    return NULL;
}

/* 更新进程状态 */
int binder_ctx_set_state(int pid, int new_state) {
    if (new_state != CTX_ACTIVE && new_state != CTX_BLOCKED && new_state != CTX_DEAD)
        return -1;
    binder_proc_ctx *ctx = binder_ctx_lookup(pid);
    if (!ctx) return -2;
    ctx->state = new_state;
    return 0;
}

/* 移除进程上下文 */
int binder_ctx_unregister(int pid) {
    pthread_mutex_lock(&ctx_lock);
    for (int i = 0; i < ctx_count; i++) {
        if (ctx_table[i].pid == pid) {
            ctx_table[i] = ctx_table[ctx_count - 1];
            ctx_count--;
            pthread_mutex_unlock(&ctx_lock);
            return 0;
        }
    }
    pthread_mutex_unlock(&ctx_lock);
    return -1;
}

/* 打印当前所有上下文(调试用) */
void binder_ctx_dump(void) {
    pthread_mutex_lock(&ctx_lock);
    printf("=== Binder进程上下文表 (共%d个) ===\n", ctx_count);
    for (int i = 0; i < ctx_count; i++) {
        const char *state_str = ctx_table[i].state == CTX_ACTIVE ? "ACTIVE" :
                                ctx_table[i].state == CTX_BLOCKED ? "BLOCKED" : "DEAD";
        printf("  [%d] pid=%d name=%s prio=%d state=%s\n",
               i, ctx_table[i].pid, ctx_table[i].process_name,
               ctx_table[i].priority, state_str);
    }
    pthread_mutex_unlock(&ctx_lock);
}

/* 模拟两个进程并发注册与状态切换 */
void *worker_thread(void *arg) {
    int pid = *(int *)arg;
    char name[16];
    snprintf(name, sizeof(name), "proc_%d", pid);
    binder_ctx_register(pid, name, pid % 50);
    binder_ctx_set_state(pid, CTX_BLOCKED);
    usleep(100);
    binder_ctx_set_state(pid, CTX_ACTIVE);
    return NULL;
}

int main(void) {
    pthread_t t1, t2;
    int pid1 = 1001, pid2 = 1002;

    /* 注册两个进程 */
    binder_ctx_register(pid1, "system_server", 20);
    binder_ctx_register(pid2, "surfaceflinger", 35);

    /* 查询并验证 */
    binder_proc_ctx *ctx = binder_ctx_lookup(pid1);
    if (ctx) {
        printf("查询pid=%d: name=%s priority=%d state=%d\n",
               ctx->pid, ctx->process_name, ctx->priority, ctx->state);
    }

    /* 并发状态切换 */
    pthread_create(&t1, NULL, worker_thread, &pid1);
    pthread_create(&t2, NULL, worker_thread, &pid2);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    /* 更新优先级 */
    binder_ctx_set_state(pid1, CTX_BLOCKED);
    binder_ctx_register(pid1, "system_server", 10);  /* 提升优先级 */

    binder_ctx_dump();

    /* 注销 */
    binder_ctx_unregister(pid2);
    printf("注销pid=%d后,剩余上下文数: %d\n", pid2, ctx_count);
    return 0;
}

编译与运行

gcc -o binder_ctx binder_ctx.c -lpthread
./binder_ctx

验证方法

程序输出应包含以下关键信息,满足即判定通过:

  • 查询pid=1001时返回name=system_server priority=20 state=0(state=0表示ACTIVE);
  • 并发线程执行后,两个进程均完成BLOCKED→ACTIVE状态切换,最终dump表中无BLOCKED状态;
  • 重新注册pid=1001后优先级从20变为10,且上下文数量不增加(更新而非重复创建);
  • 注销pid=1002后,dump表只剩pid=1001一项,输出剩余上下文数为1。

关键说明

  • 上下文表使用全局数组+互斥锁保护,模拟内核中binder_proc的哈希表管理;
  • 优先级范围0-99与Linux实时优先级语义一致,数值越小优先级越高;
  • 状态机仅包含ACTIVE/BLOCKED/DEAD三种,对应Binder线程在等待事务、处理事务或已退出时的核心状态;
  • 实际内核中每个进程的binder_proc还包含线程树、待处理事务链表等,本案例聚焦上下文管理核心逻辑。
进程注册 binder_ctx_register() 加锁 ctx_lock 遍历查找 pid 存在→更新 | 不存在→追加 解锁返回 状态管理 binder_ctx_set_state() ACTIVE BLOCKED DEAD 阻塞 唤醒 退出 退出 查询/注销 binder_ctx_lookup() binder_ctx_unregister() binder_ctx_dump() 所有操作均通过 互斥锁保证线程安全