Service Manager进程启动,睡眠等待在进程proc->wait

本文详细解析了Android Service Manager的启动过程,包括打开和映射Binder设备文件、注册为Binder上下文管理者以及循环等待客户端请求的步骤。通过分析`service_manager.c`和`binder.c`的源代码,揭示了Service Manager如何与Binder驱动进行交互并进入睡眠等待状态。

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

本文参考《Android系统源代码情景分析》,作者罗升阳。

一、~/Android/frameworks/base/cmd/servicemanager

        -----binder.h

        -----binder.c

        -----service_manager.c

        ~/Android//kernel/goldfish/drivers/staging/android

        -----binder.c

        -----binder.h


二、源码分析

       1、从service_manager.c的main开始执行。

        ----~/Android/frameworks/base/cmd/servicemanager/service_manager.c

int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1; 
    }   

    svcmgr_handle = svcmgr;//注意svcmgr_handle与下面的svcmgr_handler不一样,svcmgr_handle为全局变量,目前为空的函数指针,((void*)0)
    binder_loop(bs, svcmgr_handler);//svcmgr_handler是一个函数指针,指向具体的函数
    return 0;
}
        ---- ~/Android/frameworks/base/cmd/servicemanager/binder.c

struct binder_state
{       
    int fd;
    void *mapped;
    unsigned mapsize;
};
       ---- ~/Android/frameworks/base/cmd/servicemanager/binder.h

#define BINDER_SERVICE_MANAGER ((void*) 0)

     Service Manager是一个特殊的Service组件,它的特殊之处就在于与Service Manager进程的Binder本地对象是一个虚拟的对象。这个虚拟的Binder本地对象的地址值等于0,并且在Binder驱动程序中引用了它的Binder引用对象的句柄值也等于0。

     ServiceManager的启动过程由三个步骤组成:第一是调用函数binder_open打开设备文件/dev/binder,以及将它映射到本进程地址空间;第二是调用binder_become_context_manager将自己注册为Binder进程间通信机制的上下文管理者;第三步是调用函数binder_loop来循环等待和处理Client进程的通信要求。


      2、打开和映射Binder设备文件

      ----~/Android/frameworks/base/cmd/servicemanager/binder.c

struct binder_state *binder_open(unsigned mapsize)
{       
    struct binder_state *bs;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return 0;
    }

    bs->fd = open("/dev/binder", O_RDWR);//文件描述符保存在fd中
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }
        
    bs->mapsize = mapsize;//128*1024
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//映射到本进程地址空间
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

        /* TODO: check version */

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return 0;
} 
      其中open("/dev/binder", O_RDWR)映射到binder驱动程序binder_open方法。

      binder_open方法位于~/Android/kernel/goldfish/drivers/staging/android/binder.c

static int binder_open(struct inode *nodp, struct file *filp)
{
        struct binder_proc *proc;      

        if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
                printk(KERN_INFO "binder_open: %d:%d\n", current->group_leader->pid, current->pid);

        proc = kzalloc(sizeof(*proc), GFP_KERNEL);//创建binder_proc结构体
        if (proc == NULL)     
                return -ENOMEM;                
        get_task_struct(current);      
        proc->tsk = current;  //初始化各个参数
        INIT_LIST_HEAD(&proc->todo);   
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);
        mutex_lock(&binder_lock);      
        binder_stats.obj_created[BINDER_STAT_PROC]++;
        hlist_add_head(&proc->proc_node, &binder_procs);//将binder_proc结构体proc加入到一个全局hash队列binder_procs中
        proc->pid = current->group_leader->pid;//进程的pid
        INIT_LIST_HEAD(&proc->delivered_death);
        filp->private_data = proc;//将binder_proc结构体proc保存在参数filp的成员变量private_data中  
        mutex_unlock(&binder_lock);    

        if (binder_proc_dir_entry_proc) {/
基本思路 _ 初始优先级设定:进程初始优先级通常依据进程属性确定,如进程所需执行时间、进程类型等。比如执行时间长的进程初始优先级可设低些。 _ 时间片轮转:系统将CPU时间划分成固定长度的时间片,每个进程被分配一个时间片来执行。若时间片结束时进程未执行完,会暂停执行,重新进入就绪队列。 _ 动态优先级调整:在每个时间片结束后,系统会动态调整各个进程的优先级。通常当前执行进程优先级降低,就绪队列中进程优先级提升。 _ 进程选择:每个时间片开始时,系统从就绪队列中挑选优先级最高的进程投入运行。 _ 算法步骤 _ 初始化 _ 创建就绪队列、运行队列和完成队列。 _ 用户输入进程标识符、进程所需时间等信息,为每个进程创建PCB(进程控制块),并设定初始优先级。例如可将初始优先级设为一个较大值(如50)减去进程运行所需时间。 _ 调度循环 _ 从就绪队列选取优先级最高的进程,将其移入运行队列开始执行。 _ 执行一个时间片,期间更新进程的已执行时间和剩余执行时间。 _ 时间片结束后,若进程执行完毕(所需时间为0),将其状态置为完成,移入完成队列;否则进行优先级调整。 _ 调整优先级:当前执行进程优先级降低,就绪队列中进程优先级提升。 _ 重新从就绪队列选取优先级最高的进程,重复上述步骤,直到就绪队列为空。 _ 代码示例(C语言) _   #include <stdio.h> #include <stdlib.h> // 定义进程控制块结构体 typedef struct Process { char name[10]; int priority; int timeNeeded; int timeSlice; int timeElapsed; struct Process *next; } Process; // 定义队列结构体 typedef struct Queue { Process *front; Process *rear; } Queue; // 初始化队列 void initQueue(Queue *q) { q->front = q->rear = NULL; } // 入队操作 void enqueue(Queue *q, Process *p) { if (q->rear == NULL) { q->front = q->rear = p; } else { q->rear->next = p; q->rear = p; } p->next = NULL; } // 出队操作 Process* dequeue(Queue *q) { if (q->front == NULL) { return NULL; } Process *p = q->front; q->front = q->front->next; if (q->front == NULL) { q->rear = NULL; } return p; } // 查找优先级最高的进程 Process* findHighestPriority(Queue *q) { if (q->front == NULL) { return NULL; } Process *max = q->front; Process *current = q->front->next; while (current != NULL) { if (current->priority > max->priority) { max = current; } current = current->next; } return max; } // 移除指定进程 void removeProcess(Queue *q, Process *p) { if (q->front == NULL) { return; } if (q->front == p) { q->front = q->front->next; if (q->front == NULL) { q->rear = NULL; } return; } Process *prev = q->front; Process *current = q->front->next; while (current != NULL) { if (current == p) { prev->next = current->next; if (current == q->rear) { q->rear = prev; } return; } prev = current; current = current->next; } } // 动态优先级时间片调度算法 void dynamicPriorityScheduling(Queue *readyQueue, Queue *finishedQueue, int timeSlice) { while (readyQueue->front != NULL) { Process *current = findHighestPriority(readyQueue); removeProcess(readyQueue, current); if (current->timeNeeded <= timeSlice) { current->timeElapsed += current->timeNeeded; current->timeNeeded = 0; } else { current->timeElapsed += timeSlice; current->timeNeeded -= timeSlice; } // 调整优先级 current->priority -= 2; Process *temp = readyQueue->front; while (temp != NULL) { temp->priority += 1; temp = temp->next; } if (current->timeNeeded == 0) { enqueue(finishedQueue, current); } else { enqueue(readyQueue, current); } } } int main() { Queue readyQueue, finishedQueue; initQueue(&readyQueue); initQueue(&finishedQueue); // 示例进程 Process p1 = {"P1", 50 - 5, 5, 2, 0, NULL}; Process p2 = {"P2", 50 - 3, 3, 2, 0, NULL}; Process p3 = {"P3", 50 - 7, 7, 2, 0, NULL}; enqueue(&readyQueue, &p1); enqueue(&readyQueue, &p2); enqueue(&readyQueue, &p3); int timeSlice = 2; dynamicPriorityScheduling(&readyQueue, &finishedQueue, timeSlice); // 输出完成队列中的进程信息 Process *temp = finishedQueue.front; while (temp != NULL) { printf("进程 %s 已完成,执行时间: %d\n", temp->name, temp->timeElapsed); temp = temp->next; } return 0; }   _ 优缺点 _ 优点 _ 综合了动态优先级和时间片轮转的优势,能平衡短进程和长进程的需求,提高系统整体性能。 _ 可根据进程执行情况动态调整优先级,使资源分配更合理。 _ 缺点 _ 优先级调整策略较复杂,需根据系统特点和需求精心设计。 _ 频繁的优先级调整和进程切换会增加系统开销。 加入进程到达时间
最新发布
06-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值