【android10】【binder】【2.servicemanager启动——全源码分析】

系列文章目录

 可跳转到下面链接查看下表所有内容https://blog.youkuaiyun.com/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.youkuaiyun.com/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501


目录

系列文章目录

目录

1.简介

1.1 流程介绍

1.2 时序图

2.源码分析

2.1 servicemanager的启动

2.2 servicemanager.rc

 2.3 main.cpp

2.4 binder_open

2.5 驱动的binder_open

2.6 获取版本号binder_ioctl

2.7 binder_mmap

 2.8 binder_update_page_range

2.9 binder_become_context_manager

2.10 binder_ioctl

2.11 binder_new_node

2.12 binder_loop

2.13 binder_write

2.14 binder_ioctl

2.15 binder_thread_write

2.16 binder_ioctl

2.17 binder_thread_read


1.简介

1.1 流程介绍

第一步:首先init进程启动后会读取各个进程的rc启动文件,然后会去启动servermanager服务。

第二步:在servermanager服务的main函数中,首先会打开/dev/binder驱动,并申请一块内存,通过mmap的进行内存映射,将servermanager服务的用户空间映射到驱动中,从而会减少数据的拷贝。

第三步:becomeContextManager通知驱动成为binder的管理者。

第四步:servermanager服务向binder驱动发出了BC_ENTER_LOOPER命令,告诉binder驱动"本线程要进入循环状态了",接着进入一个for循环不断调用ioctl()读取发来的数据,接着解析这些数据。当没有消息的时候会阻塞。等待消息的到来。

1.2 时序图

  (为了保证流程的完整性,较为模糊,可放大观看)


2.源码分析

2.1 servicemanager的启动

1.在init.rc中,当init进程启动后,会去启动servicemanager、hwservicemanager、vndservicemanager 三个binder的守护进程。

[/system/core/rootdir/init.rc]
on init
    ...
    start servicemanager //启动sericemanager服务
    start hwservicemanager
    start vndservicemanager

2.2 servicemanager.rc

1.init进程启动后,会从指定路径加载进程的rc文件,然后启动servicemanager服务。

service servicemanager /system/bin/servicemanager
    class core animation //服务的类为core和animation
    user system //在启动服务前将用户切换为system
    group system readproc //在启动前将用户组切换为system和readproc
    critical //表明这个服务是至关重要的服务,如果它在四分钟内退出超过四次,则设备将重启进入恢复模式
    onrestart restart apexd //当此服务重启后,重启apexd服务
    onrestart restart audioserver //当此服务重启后,重启audioserver服务
    onrestart restart gatekeeperd //当此服务重启后,重启gatekeeperd服务
    onrestart class_restart main //当此服务重启后,重启所有class为main的服务
    onrestart class_restart hal //当此服务重启后,重启所有class为 hal的服务
    onrestart class_restart early_hal //当此服务重启后,重启所有class为early_hal的服务
    writepid /dev/cpuset/system-background/tasks //写入当前servicemanager进程的pid到/dev/cpuset/system-background/tasks文件中
    shutdown critical //设置Service进程的关闭行为。在关机期间,当前服务在shutdown超时之前不会被关闭。

 2.3 main.cpp

主要作用为:

1.打开/dev/binder驱动,并完成mmap的内存映射。内核中会创建servicemanager对应的proc对象。

2.becomeContextManager通知驱动成为binder的管理者。

3.servermanager服务向binder驱动发出了BC_ENTER_LOOPER命令,告诉binder驱动"本线程要进入循环状态了",接着进入一个for循环不断调用ioctl()读取发来的数据,接着解析这些数据。当没有消息的时候会阻塞。等待消息的到来。

int main(int argc, char** argv)//servicemanager入口,与/dev/binder交互
    
{
    struct binder_state *bs;//存储binder的三个信息
	/*struct binder_state
	{
    int fd;//binder设备的文件描述符
    void *mapped;//binder设备文件映射到进程的用户地址空间(内核地址空间或物理地址)
    size_t mapsize;//内存映射后,系统分配的地址空间大小
	};*/
    union selinux_callback cb;
    char *driver;

    if (argc > 1) {
        driver = argv[1];
    } else {
        driver = "/dev/binder";//dev/binder
    }

    bs = binder_open(driver, 128*1024);//打开/dev/binder,下文有展开。
	
	/**
    if (!bs) {
#ifdef VENDORSERVICEMANAGER
        ALOGW("failed to open binder driver %s\n", driver);
        while (true) {
            sleep(UINT_MAX);
        }
#else
        ALOGE("failed to open binder driver %s\n", driver);
#endif
        return -1;
    }
	*/

    if (binder_become_context_manager(bs)) {//下文有展开。sm成为管理者,只能调用一次
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }
	/**selinux相关,不分析
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
#ifdef VENDORSERVICEMANAGER
    cb.func_log = selinux_vendor_log_callback;
#else
    cb.func_log = selinux_log_callback;
#endif
    selinux_set_callback(SELINUX_CB_LOG, cb);

#ifdef VENDORSERVICEMANAGER
    sehandle = selinux_android_vendor_service_context_handle();
#else
    sehandle = selinux_android_service_context_handle();
#endif
    selinux_status_open(true);

    if (sehandle == NULL) {
        ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
        abort();
    }

    if (getcon(&service_manager_context) != 0) {
        ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
        abort();
    }
	*/


    binder_loop(bs, svcmgr_handler);//下文有展开。binder_loop()会先向binder驱动发出了BC_ENTER_LOOPER命令,
	//告诉binder驱动"本线程要进入循环状态了",接着进入一个for循环不断调用ioctl()读取发来的数据,接着解析这些数据

    return 0;
}

2.4 binder_open

1.调用驱动的binder_open函数。

2.调用驱动的mmap函数,完成内存映射。

struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    struct binder_state *bs;
    struct binder_version vers;

    bs = malloc(sizeof(*bs));//为bs变量分配空间
    if (!bs) {
        errno = ENOMEM;
        return NULL;
    }

    bs->fd = open(driver, O_RDWR | O_CLOEXEC);//下文有展开。driver值是/dev/binder,打开binder驱动,陷入内核,此
	//open对应_open,然后对应binder驱动层的binder_open,binder_open中主要是为/dev/binder这个驱动设备节点,创建
	//对应的sm进程的proc对象,然后通过fd返回。这样就可以和驱动进行通信。
	
	/**
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open %s (%s)\n",
                driver, strerror(errno));
        goto fail_open;
    }
	*/

    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {//下文有展开。获取binder驱动的版本信息,用vers保存,
		//查看内核版本和用户空间版本是否匹配
        fprintf(stderr,
                "binder: kernel driver version (%d) differs from user space version (%d)\n",
                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
        goto fail_open;
    }

    bs->mapsize = mapsize;//128k
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//下文有展开。内存映射。128k的内存地址,
	//申请128k的内存地址用来接收事务,对应binder驱动的binder_mmap函数。
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return NULL;
}

2.5 驱动的binder_open

主要作用为:

1.为当前sm服务进程分配保存binder_proc的对象。binder_proc结构体保存的是sm服务的进程的信息。

2.对sm服务的binder_proc的对象进行初始化,如初始化todo队列,设置进程优先级等。

3.将sm服务的binder_proc添加到binder_procs队列中,驱动有一个全局的binder_procss的列表,用于存储所有进程的binder_proc对象。

//主要作用:binder驱动为用户进程创建了用户进程自己的binder——proc实体
static int binder_open(struct inode *nodp, struct file *filp)
{
	struct binder_proc *proc;//proc表示该进程(SM)的binder进程信息。


	proc = kzalloc(sizeof(*proc), GFP_KERNEL);//为binder_proc结构体在分配kernel内存空间
	if (proc == NULL)
		return -ENOMEM;
	//下面是对binder_proc进行初始化,binder_proc用于管理数据的记录体
	get_task_struct(current);
	proc->tsk = current;//current代表当前线程。当前线程的task保存在binder进程的tsk
	INIT_LIST_HEAD(&proc->todo);//初始化to消息列表
	init_waitqueue_head(&proc->wait);//初始化wait列表
	proc->default_priority = task_nice(current);//当前进程的nice值转化为进程优先级

	binder_lock(__func__);

	binder_stats_created(BINDER_STAT_PROC);//BINDER_PROC对象创建+1
	hlist_add_head(&proc->proc_node, &binder_procs);//将当前SM的binder_proc对象添加到binder_procs为表头的队列
	proc->pid = current->group_leader->pid;
	INIT_LIST_HEAD(&proc->delivered_death);
	filp->private_data = proc;//将 sm的proc 保存到filp中,此filp对应的就是fd,这样下次可以通过filp找到此proc

	binder_unlock(__func__);

	if (binder_debugfs_dir_entry_proc) {
		char strbuf[11];
		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
		proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
			binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
	}

	return 0;
}

2.6 获取版本号binder_ioctl

主要作用为:

1.此时用于获取版本号。

<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值