Android P Binder-ServiceManager 分析

  1. Service Manager 启动和初始化

ServiceManager作为binder的大管家,也是binder的守护进程,它本身也是binder的一个server端。

它本身逻辑比较简单,只是实现对binder 服务的注册和查询。但是它的逻辑主要是跟binder驱动进行交互,我们可以通过分析ServiceManger的相关逻辑

作为我们认识和学习binder的一个入口,以对binder驱动做深入的学习和认识。

serviceManager代码:/frameworks/native/cmds/servicemanager/

binder驱动代码:/kernel4.4/drivers/android/

 

1.1 ServiceManager启动

/system/core/rootdir/init.rc

312    start servicemanager

在init启动阶段通过解析init.rc启动servicemanager

它的启动函数在Service_manager.c 的main函数,主要执行逻辑如下

1. open /dev/binder

2.用户空间和内核空间 binder版本是否一致

3.调用mmap为serviceManager开辟内存空间

4.注册service_manager 为binder驱动的守护进程,成为上下文的管理者,执行binder_become_context_manager()

创建了全局的binder_node对象binder_context_mgr_node 的实体,并将binder_context_mgr_node的强弱引用各加1.

将新创建的node对象添加到proc红黑树

在Binder驱动层创建binder_node结构体对象,并将当前binder_proc加入到binder_node的node->proc。并创建binder_node的async_todo和binder_work两个队列

4.验证selinux权限,判断进程是否有权注册或查看指定服务 selinux_android_service_context_handle()

5.binder进入loop循环,不断的binder读写操作,读出的数据进行binder解析,由main()方法传递过来的参数func指向svcmgr_handler,处理解析后的内容

调用binder驱动,设置线程的loop状态

 

​​​​​​​1.2 binder_驱动初始化

首先说明binder驱动的初始化函数binder_init

(1)binder驱动初始化会在/sys/kernel/debug/binder/创建各种各种目录已保存各进程binder信息,binder传输Log等

(2)binder驱动是misc类型的驱动

(3)binder驱动也需要填写对应的file_operations结构体,用户进程调用binder驱动的公共接口,我们可以通过它找到对应的执行函数

       static const struct file_operations binder_fops = {

              .owner = THIS_MODULE,

              .poll = binder_poll,

              .unlocked_ioctl = binder_ioctl,

              .compat_ioctl = binder_ioctl,

              .mmap = binder_mmap,

              .open = binder_open,

              .flush = binder_flush,

              .release = binder_release,

       };

​​​​​​​1.2.1 binder_init

static int __init binder_init(void)

{

       //在/proc目录创建各种Binder相关的文件,供用户访问,我们sysinfo Log中相关的binder的信息就是从这些节点获取的

       //sys/kernel/debug/binder/failed_transaction_log

       binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);

       if (binder_debugfs_dir_entry_root)

              //sys/kernel/debug/binder/proc

              binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",

                                           binder_debugfs_dir_entry_root);

 

       if (binder_debugfs_dir_entry_root) {

              //sys/kernel/debug/binder/state

              debugfs_create_file("state",

                                0444,

                                binder_debugfs_dir_entry_root,

                                NULL,

                                &binder_state_fops);

              //sys/kernel/debug/binder/stats

              debugfs_create_file("stats",

                                0444,

                                binder_debugfs_dir_entry_root,

                                NULL,

                                &binder_stats_fops);

              //sys/kernel/debug/binder/transactions

              debugfs_create_file("transactions",

                                0444,

                                binder_debugfs_dir_entry_root,

                                NULL,

                                &binder_transactions_fops);

              //sys/kernel/debug/binder/transaction_log

              debugfs_create_file("transaction_log",

                                0444,

                                binder_debugfs_dir_entry_root,

                                &binder_transaction_log,

                                &binder_transaction_log_fops);

              //sys/kernel/debug/binder/failed_transaction_log

              debugfs_create_file("failed_transaction_log",

                                0444,

                                binder_debugfs_dir_entry_root,

                                &binder_transaction_log_failed,

                                &binder_transaction_log_fops);

       }

      

       //创建dev/binder 设备文件

       ret = init_binder_device(device_name);

}

 

​​​​​​​1.3 binder_open

binder_open函数主要做了一下工作

(1)通过filp指针读取存在filp->private_data中的binder_device数据,这里面包含binder_context对象

(2)创建并初始化binder_proc,然后存入filp->private_data

(3)初始化binder_alloc的buffers

 

然后我们简单介绍结构体binder_proc ,这个结构体每个进程都会创建一个,它保存了这个进程binder相关的一些重要信息,下面是比较重要的一些元素。

首先有四个红黑树的节点对象,threads,nodes,refs_by_desc,refs_by_node,这样使得binder_proc同时也挂载在四棵红黑树上。

1)threads树用来保存binder_proc进程内用于处理用户请求的线程,它的最大数量由max_threads来决定,我们目前普通进程为16

2)node树是用来保存binder_proc进程内的Binder实体;

3)refs_by_desc树和refs_by_node树用来保存binder_proc进程内的Binder引用,即引用的其它进程的Binder实体,一种是以句柄作

来key值来组织,一种是以引用的实体节点的地址值作来key值来组织,它们都是表示同一样东西,只不过是为了内部查找方便而用两个红黑树来表示

​​​​​​​1.3.1  binder_proc

struct binder_proc {

       struct hlist_node proc_node;//这个哈希表的节点就是让proc 可以挂在binder_procs这个全局哈希列表

       struct rb_root threads;

       struct rb_root nodes;

       struct rb_root refs_by_desc;

       struct rb_root refs_by_node;

       struct list_head waiting_threads;//wait队列链表头

       int pid;//进程pid

       struct task_struct *tsk;//进程的task_struct对象指针

       struct files_struct *files;//进程的file对象指针

       struct hlist_node deferred_work_node;

       bool is_dead;//进程是否已死

       struct list_head todo;//todo表示发往该进程的待处理数据事项列表

       struct binder_stats stats;binder统计信息

       struct list_head delivered_death;已分发的死亡通知

       int max_threads;最大线程数

       int requested_threads;请求的线程数

       int requested_threads_started;已启动的线程数

       struct binder_alloc alloc; //这个结构体主要是对binder地址空间管理的

};

 

​​​​​​​1.3.2  binder_open

static int binder_open(struct inode *nodp, struct file *filp)

{

struct binder_proc *proc;

struct binder_device *binder_dev;

proc = kzalloc(sizeof(*proc), GFP_KERNEL);

获取当前进程的tast_struct赋值给proc->tsk

proc->tsk = current->group_leader;

初始化todo的链表头结点

INIT_LIST_HEAD(&proc->todo);

判断policy是否是下面之一

SCHED_NORMAL,SCHED_BATCHeturn,SCHED_FIFO,SCHED_RR;

if (binder_supported_policy(current->policy)) {

       proc->default_priority.sched_policy = current->policy;

       proc->default_priority.prio = current->normal_prio;

} else {

       proc->default_priority.sched_policy = SCHED_NORMAL;

       proc->default_priority.prio = NICE_TO_PRIO(0);

}

 

根据filp->private_data我们可以获取binder_device的地址,并赋值给指针binder_dev

binder_dev = container_of(filp->private_data, struct binder_device,

                       miscdev);

//从binder_dev取出binder_context初始化proc->context 

proc->context = &binder_dev->context;

//一个把pid赋值给binder_alloc,另一个初始化binder_alloc的buffers

binder_alloc_init(&proc->alloc);

设置binder的state

binder_stats_created(BINDER_STAT_PROC);

这里面state有如下定义

enum binder_stat_types {

       BINDER_STAT_PROC,

       BINDER_STAT_THREAD,

       BINDER_STAT_NODE,

       BINDER_STAT_REF,

       BINDER_STAT_DEATH,

       BINDER_STAT_TRANSACTION,

       BINDER_STAT_TRANSACTION_COMPLETE,

       BINDER_STAT_COUNT

};

//给当前pid赋值给proc->pid

proc->pid = current->group_leader->pid;

//初始话死亡通知链表

INIT_LIST_HEAD(&proc->delivered_death);

//初始化wait队列

INIT_LIST_HEAD(&proc->waiting_threads);

将proc赋值给private_data,保存在file结构体中,这样之后ioctl操作时候,可以直接从file->private_data取出proc对象指针

filp->private_data = proc;

这个进程proc 结构体中的proc_node对象同时还会保存在一个全局哈希表binder_procs中,驱动程序内部使用,这样可以通过哈希表找到proc。

hlist_add_head(&proc->proc_node, &binder_procs);

//在sys/kernel/debug/binder/proc 创建对应pid的文件,里面记录了thread,node,ref,buffer等信息

if (binder_debugfs_dir_entry_proc) {

       char strbuf[11];

       snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);

       proc->debugfs_entry = debugfs_create_file(strbuf, 0444,

              binder_debugfs_dir_entry_proc,

              (void *)(unsigned long)proc->pid,

              &binder_proc_fops);

}

 

​​​​​​​1.4 mmap

binder内存开辟和相关虚拟内存内容涉及过多,这里不做展开,以后做专题再学习一下linux内存申请分配映射相关内容,这里主要简单说明一下。

首先service manager调用mmap函数传入内存size,通过file_operations结构体 binder_fops我们找到对应驱动的实现函数binder_mmap,

在传入的参数filp,它的private_data变量保存binder_proc数据,内存映射信息放在vma参数中,这里的vma的数据类型是struct vm_area_struct,它表示的是一块连续的虚拟地址空间区域。

这里我们需要说明的是,使用mmap函数的目的,首先通过调用它用户程序进程可以申请一块虚拟内存地址,这个地址最终准定是指向物理地址的某个地方。

另一方面binder_proc->binder_alloc->buffer 这个指针也指向一个虚拟内存地址,是binder驱动的内核空间的地址,经过虚拟内存转换后实际指向的也是用户程序进程指向的物理地址。

这样的好处就是binder传输的时候,我们只需要把指向一次copy_from_user(),把client端用户进程的数据copy到server端的binder内核内存空间。因为server端用户进程和内核空间都指向

同一块物理地址,这样就避免再进程数据copy了。

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)

{

 

       //校验申请的内存是否大于4M上限,大于置为4M,这里申请128kb

       if ((vma->vm_end - vma->vm_start) > SZ_4M)

              vma->vm_end = vma->vm_start + SZ_4M;

       if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {

              ret = -EPERM;

              failure_string = "bad vm_flags";

              goto err_bad_arg;

       }

       //设置flag

       vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;

       vma->vm_flags &= ~VM_MAYWRITE;

       vma->vm_ops = &binder_vm_ops;

       vma->vm_private_data = proc;

       //申请内存并进行内存映射

       ret = binder_alloc_mmap_handler(&proc->alloc, vma);

       proc->files = get_files_struct(current);

}

 

​​​​​​​1.5 binder_become_context_manager

servicemanger在init.rc中是启动很早,这保证了它作为第一个向binder驱动注册的进程,并成为binder驱动的管理者,而核心就是binder_become_context_manager的执行。

它的主要逻辑就是调用ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);

找到驱动对应的处理函数ioctl,协议事件为BINDER_SET_CONTEXT_MGR

​​​​​​​1.5.1 binder_thread

它代表每个进程内用户可调用线程的信息,每个线程对应一个,我们上文介绍过binder_proc有棵threads的红黑树,thread的rb_node对象就是这颗红黑树的节点,这样可以把thread挂在这颗树上,这样便于查询,删除,插入。成员对象的解析请参考

struct binder_thread {

       struct binder_proc *proc;//thread 所属进程的信息

       struct rb_node rb_node;//用于挂载在threads树上

       struct list_head waiting_thread_node;

       int pid;//线程pid

       int looper; //looper状态

       bool looper_need_return; /* can be written by other thread */

       struct binder_transaction *transaction_stack;

       struct list_head todo;//将要初处理的链表队列

       bool process_todo;

       struct binder_error return_error;//return错误信息

       struct binder_error reply_error; //reply错误信息

       wait_queue_head_t wait;//等待队列的对头

       struct binder_stats stats;//binder线程的统计信息

       atomic_t tmp_ref;

       bool is_dead;//线程存活状态

       struct task_struct *task;

};

​​​​​​​1.5.2 binder_ioctl

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

thread = binder_get_thread(proc);获取或者创建线程

…..

       case BINDER_SET_CONTEXT_MGR:

              ret = binder_ioctl_set_ctx_mgr(filp);

              if (ret)

                     goto err;

              break;

}

再介绍两个结构体binder_node和binder_context

​​​​​​​1.5.3 binder_node

binder_node则是代表binder实体,对应于BBinder对象,记录BBinder的进程、指针、引用计数等

struct binder_node {

       int debug_id;创建的时候分配的id号,全局唯一

       union {

              struct rb_node rb_node;//binder节点正常使用

              struct hlist_node dead_node;//binder节点已销毁

       };

       struct binder_proc *proc;binder实体所在进程binder_proc对象

       struct hlist_head refs;所有指向该节点的binder引用队列,是一个哈希表

       //强索引计数

       int internal_strong_refs;

       int local_weak_refs;

       int local_strong_refs;

       int tmp_refs;

      

       binder_uintptr_t ptr;指向用户空间binder_node的指针

       binder_uintptr_t cookie;附属数据

       bool has_async_transaction;//同异步传输标志值

       struct list_head async_todo;//异步队列,链表

}

​​​​​​​1.5.4 binder_context

binder_context,这个结构体我的理解主要保存了service_manager的binder实体和uid信息

struct binder_context {

       struct binder_node *binder_context_mgr_node;//这个是service manager的binder实体,在binder_ioctl_set_ctx_mgr完成初始化

       struct mutex(miutaikesi) context_mgr_node_lock;//mutex锁对象

 

       kuid_t binder_context_mgr_uid;//service Manger的binder实体

       const char *name;

};

 

​​​​​​​1.5.5 binder_ioctl_set_ctx_mgr

static int binder_ioctl_set_ctx_mgr(struct file *filp)

{

       int ret = 0;

       struct binder_proc *proc = filp->private_data;

       struct binder_context *context = proc->context;

       //定义新的binder_node指针,后面赋值给context->binder_context_mgr_node

       struct binder_node *new_node;

       //获取当前进程uid

       kuid_t curr_euid = current_euid();

 

       mutex_lock(&context->context_mgr_node_lock);

       //正常第一次为null,如果不为null则说明该进程已经设置过context mgr则直接退出

       if (context->binder_context_mgr_node) {

              pr_err("BINDER_SET_CONTEXT_MGR already set\n");

              ret = -EBUSY;

              goto out;

       }

       //检查当前进程是否具有注册Context Manager的SEAndroid安全权限。当前进程是通过本地变量proc来描述的,它指向的是一个类型为binder_proc的对象。在结构体binder_proc中,有一个类型为task_struct的成员变量task,它指向的就是内核中用来描述进程的一个控制块。在前面SEAndroid安全机制中的进程安全上下文关联分析一文中提到,进程的安全上下文是保存在内核中用来描述该进程的一个task_struct结构体中的,因此,当知道一个进程的task_struct结构体之后,我们就可以获得它的安全上下文

       ret = security_binder_set_context_mgr(proc->tsk);

       if (ret < 0)

              goto out;

       if (uid_valid(context->binder_context_mgr_uid)) {

              //读取binder_context_mgr_uid和当前的比,如果不一样,报错。

              if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {

                     pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",

                            from_kuid(&init_user_ns, curr_euid),

                            from_kuid(&init_user_ns,

                                    context->binder_context_mgr_uid));

                     ret = -EPERM;

                     goto out;

              }

       } else {

              //将当前进程的uid赋值给context的binder_context_mgr_uid变量以作保存

              context->binder_context_mgr_uid = curr_euid;

       }

       new_node = binder_new_node(proc, NULL);//主要逻辑在binder_init_node_ilocked实现

       if (!new_node) {

              ret = -ENOMEM;

              goto out;

       }

       binder_node_lock(new_node);

       然后给新创建的binder_node 的local_weak_refs和local_strong_refs 弱强引用分别加1

       new_node->local_weak_refs++;

       new_node->local_strong_refs++;

       new_node->has_strong_ref = 1;

       new_node->has_weak_ref = 1;

       //我们把新创建的node对象赋值给binder_context_mgr_node,成为serviceManager的binder管理实体

       context->binder_context_mgr_node = new_node;

       binder_node_unlock(new_node);

       binder_put_node(new_node);

out:

       mutex_unlock(&context->context_mgr_node_lock);

       return ret;

}

​​​​​​​1.5.6 binder_init_node_ilocked

static struct binder_node *binder_init_node_ilocked(

                                          struct binder_proc *proc,

                                          struct binder_node *new_node,

                                          struct flat_binder_object *fp)

{

       struct rb_node **p = &proc->nodes.rb_node;

       struct rb_node *parent = NULL;

       struct binder_node *node;

       s8 priority;

 

       assert_spin_locked(&proc->inner_lock);

       while (*p) {

 

              parent = *p;

              node = rb_entry(parent, struct binder_node, rb_node);

 

              if (ptr < node->ptr)

                     p = &(*p)->rb_left;

              else if (ptr > node->ptr)

                     p = &(*p)->rb_right;

              else {

                     /*

                      * A matching node is already in

                      * the rb tree. Abandon the init

                      * and return it.

                      */

                     binder_inc_node_tmpref_ilocked(node);

                     return node;

              }

       }

       //新binder_node创建的指针

       node = new_node;

       //设置binder状态为BINDER_STAT_NODE

       binder_stats_created(BINDER_STAT_NODE);

       node->tmp_refs++;

       新创建的binder_node加入到proc的nodes红黑树

       rb_link_node(&node->rb_node, parent, p);

       rb_insert_color(&node->rb_node, &proc->nodes);

       然后做相关node信息的初始化

       node->debug_id = atomic_inc_return(&binder_last_id);

       node->proc = proc;

       node->ptr = ptr;

       node->cookie = cookie;

       node->work.type = BINDER_WORK_NODE;

       priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;

       node->sched_policy = (flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK) >>

              FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT;

       node->min_priority = to_kernel_prio(node->sched_policy, priority);

       node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);

       node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT);

       spin_lock_init(&node->lock);

       初始化async_todo 和work队列

       INIT_LIST_HEAD(&node->work.entry);

       INIT_LIST_HEAD(&node->async_todo);

       binder_debug(BINDER_DEBUG_INTERNAL_REFS,

                   "%d:%d node %d u%016llx c%016llx created\n",

                   proc->pid, current->pid, node->debug_id,

                   (u64)node->ptr, (u64)node->cookie);

 

       return node;

}

 

​​​​​​​1.6 binder_loop

传入两个参数binder_state 和handler处理函数svcmgr_handler

binder_loop(bs, svcmgr_handler);

这里我们说明两个点

(1)binder协议 binder传输也是通过协议实现,这里我们使用BC_ENTER_LOOPER,以后关于协议再做详细介绍

(2)协议的传输通过ioctl 函数执行BINDER_WRITE_READ,将协议写入binder_write_read传输给binder驱动

然后我们再说loop函数执行逻辑

(1)给binder驱动传入BC_ENTER_LOOPER协议命令,然后进入loop状态

(2)从binder驱动不断读写数据,然后交给binder_parse函数解析,并交给svcmgr_handler处理

​​​​​​​1.6.1 binder_loop

void binder_loop(struct binder_state *bs, binder_handler func)

{

    int res;

    struct binder_write_read bwr;

    uint32_t readbuf[32];

 

    bwr.write_size = 0;

    bwr.write_consumed = 0;

    bwr.write_buffer = 0;

 

    readbuf[0] = BC_ENTER_LOOPER;

    binder_write(bs, readbuf, sizeof(uint32_t));

 

    for (;;) {

        bwr.read_size = sizeof(readbuf);

        bwr.read_consumed = 0;

        bwr.read_buffer = (uintptr_t) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

              //解析cmd,然后根据协议命令执行不同的调用逻辑,BR_TRANSACTION协议命令则交给svcmgr_handler

        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);

 

    }

}

​​​​​​​1.6.2 binder_ioctl_write_read

ioctl的BINDER_WRITE_READ命令交给binder驱动的binder_ioctl_write_read函数处理,write主要交给binder_thread_write函数处理,同事这个函数也可以处理read操作,读取发来的数据。

static int binder_ioctl_write_read(struct file *filp,

                            unsigned int cmd, unsigned long arg,

                            struct binder_thread *thread)

{

       int ret = 0;

       struct binder_proc *proc = filp->private_data;

       //用户进程写入的数据都写入到了arg指向的内存空间

       unsigned int size = _IOC_SIZE(cmd);

       void __user *ubuf = (void __user *)arg;

       struct binder_write_read bwr;

       //将数据copy到内核空间,因为serviceManger是用户空间和内核指向同一个物理内存,数据不做操作。

       if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {

              ret = -EFAULT;

              goto out;

       }

       //write_size>0代表有需要写入的数据

       if (bwr.write_size > 0) {

              ret = binder_thread_write(proc, thread,

                                     bwr.write_buffer,

                                     bwr.write_size,

                                     &bwr.write_consumed);

              trace_binder_write_done(ret);

              if (ret < 0) {

                     bwr.read_consumed = 0;

                     if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

                            ret = -EFAULT;

                     goto out;

              }

       }

       //read_size>0代表有需要读取的数据

       if (bwr.read_size > 0) {

              ret = binder_thread_read(proc, thread, bwr.read_buffer,

                                    bwr.read_size,

                                    &bwr.read_consumed,

                                    filp->f_flags & O_NONBLOCK);

              trace_binder_read_done(ret);

              binder_inner_proc_lock(proc);

              if (!binder_worklist_empty_ilocked(&proc->todo))

                     binder_wakeup_proc_ilocked(proc);

              binder_inner_proc_unlock(proc);

              if (ret < 0) {

                     if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

                            ret = -EFAULT;

                     goto out;

              }

       }

       if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {

              ret = -EFAULT;

              goto out;

       }

out:

       return ret;

}

​​​​​​​1.6.3 binder_thread_write

binder_thread_write中会通过解析cmd 协议命令,来做处理

case BC_ENTER_LOOPER:

       if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {

              thread->looper |= BINDER_LOOPER_STATE_INVALID;

              binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",

                     proc->pid, thread->pid);

       }

       thread->looper |= BINDER_LOOPER_STATE_ENTERED;//设置thread->looperflag为BINDER_LOOPER_STATE_ENTERED

       break;

 

​​​​​​​1.6.4 binder_parse

这个方法主要是读取binder驱动传递的数据,然后解析出相关协议命令,并根据不同命令执行不同逻辑

这里我们主要关注下面两个协议的处理

BR_TRANSACTION //Binder驱动向Server端发送请求数据

BR_DEAD_BINDER //Binder驱动向client端发送死亡通知

 

函数传入参数解析:

bs :binder_state对象,存储binder dev open后的状态信息

bio :为0

ptr :ServiceManager读取binder驱动传递数据的内存地址指针

size :数据大小

func :处理函数

int binder_parse(struct binder_state *bs, struct binder_io *bio,

                 uintptr_t ptr, size_t size, binder_handler func)

{

    int r = 1;

    uintptr_t end = ptr + (uintptr_t) size;

 

    while (ptr < end) {

              从ptr指向的地址读取cmd(协议)命令

        uint32_t cmd = *(uint32_t *) ptr;

        ptr += sizeof(uint32_t);

#if TRACE

        fprintf(stderr,"%s:\n", cmd_name(cmd));

#endif

        switch(cmd) {

        ......

        case BR_TRANSACTION: {

            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;

            if ((end - ptr) < sizeof(*txn)) {

                ALOGE("parse: txn too small!\n");

                return -1;

            }

                     //打印binder_transaction_data数据

            binder_dump_txn(txn);

            if (func) {

                unsigned rdata[256/4];

                struct binder_io msg;//收到数据封装

                struct binder_io reply;//发送数据封装

                int res;

                            //reply初始化

                bio_init(&reply, rdata, sizeof(rdata), 4);

                            //从txn初始化msg

                bio_init_from_txn(&msg, txn);

                            //调用func svcmgr_handler处理

                res = func(bs, txn, &msg, &reply);

                if (txn->flags & TF_ONE_WAY) {

                                   //释放txn->data的数据

                    binder_free_buffer(bs, txn->data.ptr.buffer);

                } else {

                                   //给binder驱动回复数据

                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);

                }

            }

            ptr += sizeof(*txn);

            break;

        }

        ......

        case BR_DEAD_BINDER: {

                     //获取binder_death数据

            struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;

            ptr += sizeof(binder_uintptr_t);

                     ///调用func svcmgr_handler处理

            death->func(bs, death->ptr);

            break;

        }

        ......

    return r;

}

2. ServiceManager的核心功能

这一章我们主要分析Service_manager.c的内部逻辑,分析它主要实现的功能和相关逻辑。而getService,addService的完整的链条逻辑(服务client端,server端,kernel)其实就是整个binder通信传输的完整流程,后续会以某个服务为例子专门去分析学习一下。

那么ServiceManager主要实现的功能包括Service的管理,可以细分为

  1. Service的存储管理
  2. Service 注册
  3. Service 查询

上文我们提到过binder驱动的数据会交给binder_parse解析处理cmd,然后重要的协议交给函数svcmgr_handler函数处理,这里面在具体解析需要处理的功能是查询,注册,还是死亡通知等信息。

int svcmgr_handler(struct binder_state *bs,struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply)

       struct svcinfo *si;

    uint16_t *s;

    size_t len;

    uint32_t handle;

    uint32_t strict_policy;

    int allow_isolated;

    uint32_t dumpsys_priority;

       做信息检查

    if (txn->target.ptr != BINDER_SERVICE_MANAGER)

        return -1;

    if (txn->code == PING_TRANSACTION)

        return 0;

    strict_policy = bio_get_uint32(msg);

       //读取服务名字和长度,分别存在s和len

    s = bio_get_string16(msg, &len);

    if (s == NULL) {

        return -1;

    }

    if ((len != (sizeof(svcmgr_id) / 2)) ||

        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {

        fprintf(stderr,"invalid id %s\n", str8(s, len));

        return -1;

    }

​​​​​​​2.1 Service的存储管理

SM对于Service的管理比较简单

Service在SM是通过svcinfo结构体保存的,每一个binder服务对应一个svcinfo对象。

而svcinfo在SM又是通过链表维护起来的,查找指针为svclist,它是一个全局变量。插入删除也是通过它找到对应的svcinfo实例。

struct svcinfo

{

    struct svcinfo *next;//指向的下一个节点

    uint32_t handle;//Service的句柄

    struct binder_death death;//死亡通知信息

    int allow_isolated;

    uint32_t dumpsys_priority;

    size_t len;//名字长度

    uint16_t name[0];//服务名字

};

​​​​​​​2.2 服务查询

上文提到注册是在svcmgr_handler处理的,我们看下具体代码

switch(txn->code) {

     case SVC_MGR_GET_SERVICE:

    case SVC_MGR_CHECK_SERVICE:

        s = bio_get_string16(msg, &len);

        if (s == NULL) {

            return -1;

        }

              //通过name s查询对应的handle

        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);

        if (!handle)

            break;

              //将handle封装到reply然后发给驱动

        bio_put_ref(reply, handle);

        return 0;

​​​​​​​2.2.1 do_find_service

uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)

{

    struct svcinfo *si = find_svc(s, len);//查询对应name的svcinfo

 

    if (!si || !si->handle) {

        return 0;

    }

       //权限校验

    if (!svc_can_find(s, len, spid, uid)) {

        return 0;

    }

 

    return si->handle;

}

​​​​​​​2.2.2 find_svc

struct svcinfo *find_svc(const uint16_t *s16, size_t len)

{

    struct svcinfo *si;

       //遍历链表查询name长度,内容一致的svcinfo

    for (si = svclist; si; si = si->next) {

        if ((len == si->len) &&

            !memcmp(s16, si->name, len * sizeof(uint16_t))) {

            return si;

        }

    }

    return NULL;

}

​​​​​​​2.3 服务注册

    switch(txn->code) {

      case SVC_MGR_ADD_SERVICE:

        s = bio_get_string16(msg, &len);

        if (s == NULL) {

            return -1;

        }

              //获取服务对应的句柄

        handle = bio_get_ref(msg);

        allow_isolated = bio_get_uint32(msg) ? 1 : 0;

        dumpsys_priority = bio_get_uint32(msg);

              //调用do_add_service

        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,

                           txn->sender_pid))

            return -1;

        break;

​​​​​​​​​​​​​​2.3.1 do_add_service

int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,

                   uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {

    struct svcinfo *si;

       //service的name长度不能大于127

    if (!handle || (len == 0) || (len > 127))

        return -1;

       //主要调用selinux_check_access进程权限校验

    if (!svc_can_register(s, len, spid, uid)) {

        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",

             str8(s, len), handle, uid);

        return -1;

    }

       //查询是否包含该name的svcinfo

    si = find_svc(s, len);

    if (si) {

        if (si->handle) {

            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",

                 str8(s, len), handle, uid);

            svcinfo_death(bs, si);

        }

              更新handle

        si->handle = handle;

    } else {

              //新建svcinfo

        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));

        if (!si) {

            ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",

                 str8(s, len), handle, uid);

            return -1;

        }

              对svcinfo进行初始化赋值

        si->handle = handle;

        si->len = len;

        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));

        si->name[len] = '\0';

        si->death.func = (void*) svcinfo_death;

        si->death.ptr = si;

        si->allow_isolated = allow_isolated;

        si->dumpsys_priority = dumpsys_priority;

        si->next = svclist;

        svclist = si;

    }

       //以BC_ACQUIRE命令,handle为目标的信息,通过ioctl发送给binder驱动

    binder_acquire(bs, handle);

       //以BC_REQUEST_DEATH_NOTIFICATION命令的信息,通过ioctl发送给binder驱动    binder_link_to_death(bs, handle, &si->death);

    return 0;

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值