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的管理,可以细分为
上文我们提到过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;
}