在笔者的上一篇博客中主要分享了 Binder的通信过程是如何实现的,大致内容就是下面这张图:
笔者也提到Binder机制主要对象有Binder Client、Binder Server、Binder Driver、Service Manager
,它的完整过程是这样的:(此处是从Gityuan大佬的博客copy过来的一张图)
对比两者或者说仔细看了笔者的上篇博客,会发现介绍通信过程忽略了Service Manager
这个角色,所以本篇的目的就是介绍它了。
ServerManager
和Binder
的关系?ServerManager
的作用ServerManager
的大致工作过程
Service Manager 与 实名Binder
ServiceManager的角色作用什么呢?
ServiceManager是安卓中一个重要的类,正如它的名字所表达的意思,用于管理所有的系统服务,维护着系统服务和客户端的binder
通信。
那ServiceManager
和Binder
是什么样的关系呢?
简单点说,ServiceManager
作用是将字符形式的 Binder
名字转化成 Client
中对该 Binder
的引用,使得 Client
能够通过 Binder
的名字获得对 Binder
实体的引用。(这个注册了名字的 Binder
叫实名 Binder
)
但现在就有个问题,Service Manager
是一个进程,Server
是一个进程,Server
向 Service Manager
中注册 Binder
就涉及到进程间通信。但当前进程间通信又要用到进程间通信,这就好像蛋可以孵出鸡的前提却是要先找只鸡下蛋。那如何解决这个没有鸡生蛋的问题呢?
巧妙的实现:
要打破这个问题,就要预先创造一只鸡去生蛋,这只鸡就是ServiceManager
的Binder
实体。ServiceManager
提供的 Binder
比较特殊,它没有名字也不需要注册。当一个进程使用 BINDER_SET_CONTEXT_MGR
命令就会将自己注册成 ServiceManager
时, Binder
驱动会自动为它创建 Binder
实体(这就是那只预先造好的那只鸡)
Server端的注册方式
这个 Binder
实体的引用在所有 Client
中都固定为 0 而无需通过其它手段获得。也就是说,一个 Server
想要向 ServiceManager
注册自己的 Binder
就必须通过这个 0 号引用和 ServiceManager
的 Binder
通信。
类比网络通信,这个0号引用就像是
DNS
的地址,是需要首先配置好的(相对于这个DNS
服务器,其他所有都是客户端)。同理 ,一个进程或者应用程序即使是提供服务的Server
,相对于SM
,它也是客户端。
整个过程大致是:
当一个Binder Service
创建后,它们就将自己的[名称、Binder句柄]对应关系告知SM
进行备案,完成注册。
Client端获取Service的Binder引用
Server
向 ServiceManager
中注册了 Binder
后, Client
就能通过名字获得 Binder
的引用了。由于 Client
和 SM
通信也需要Binder,所以Client
也是通过这个0号引用去向SM
获取某个Service
的Binder
。
因为
ServiceManager
对于Client
端来说Handle句柄
是固定的,都是0,所以ServiceManager
服务并不需要查询,可以直接使用。
整个过程大致是:
Client
发送数据包向SM
请求某个名字的Binder
引用SM
收到这个请求后,从请求数据包中去找名称,在查找表里找到对应的Binder
的引用- 将找到的
Binder
引用作为回复发送给请求的Client
现在Client和Server 与 SM 的注册与获取有了基本的了解,具体实现细节就不再这里阐述了,可以去看源码了解。我们要着重关注一下 SM
SM的启动和创建
通过init
程序解析init.rc
时启动的,当它重启后,其他的系统服务的zygote
、media
、surfaceflinger
也会被重新加载
//frameworks/native/cmds/servicemanager/servicemanager.rc
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
onrestart restart keystore
onrestart restart gatekeeperd
writepid /dev/cpuset/system-background/tasks
shutdown critical
因为SM
启动的比较早,所以能保证它是系统中第一个向Binder
驱动注册成“大管家”的程序。
//frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char** argv)
{
struct binder_state *bs;
//1.打开Binder设备,申请128kb内存
bs = binder_open(driver, 128*1024);
//2.将自己设置成Binder大管家,系统中只允许一个ServiceManager存在
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
//3.进入循环,等待并处理客户端的请求
binder_loop(bs, svcmgr_handler);
return 0;
}
当准备工作做完后,SM
就开始等待客户端的请求。这部分是SM
的一个重点。
SM的工作过程
SM
的工作过程,如何处理请求是较为重要的一步,根据上面分析的源码,我们可以从 binder_loop(bs, svcmgr_handler)
入手来看SM
是如何来处理请求的?
//frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func){
struct binder_write_read bwr;
uint32_t readbuf[32];
//向Binder驱动发送BC_ENTER_LOOPER协议,让SM进入循环
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);
//解析binder信息
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
}
}
它通过不断循环去处理请求队列,感觉和Handler
的消息管理机制有点相似,但要注意的是,SM
中是没有消息队列的,它的消息是通过Binder驱动去获取的。
具体大概分三个步骤:
- 从
Binder驱动
中读取消息 - 处理消息
- 不断循环,永远不会主动退出(除非出现错误)
处理消息是较为复杂的一步,它是怎么处理的呢?
从Binder驱动
中读取到消息后,它会调用 binder_parse()
的方法解析消息,主要工作就是针对不同的BR协议,采用不同的处理:
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) {
switch(cmd) {
case BR_NOOP:
break;
case BR_TRANSACTION_COMPLETE:
break;
case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS:
case BR_TRANSACTION: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
binder_dump_txn(txn);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
int res;
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
//具体处理消息的操作
res = func(bs, txn, &msg, &reply);
if (txn->flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn->data.ptr.buffer);
} else {
//回应消息处理结果
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
}
ptr += sizeof(*txn);
break;
}
case BR_REPLY: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
binder_dump_txn(txn);
if (bio) {
bio_init_from_txn(bio, txn);
bio = 0;
}
ptr += sizeof(*txn);
r = 0;
break;
}
case BR_DEAD_BINDER:
case BR_FAILED_REPLY:
case BR_DEAD_REPLY:
default:
}
}
return r;
}
从代码中可以看出有很多BR协议,其中要着重关注其中的两个: 一个是BR_TRANSCATION
和 BR_REPLY
,尤其是BR_TRANSCATION
BR_TRANSCATION
对BR_TRANSCATION
命令的处理主要是由func
函数完成,然后将结果返回给Binder
驱动,Binder驱动收到消息进而传给客户端。
追溯之前的代码,这个fun
函数其实是 binder_loop(bs, svcmgr_handler)
函数 传递过来的,也就是svcmgr_handler
函数,它的实现如下:
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
//服务名
s = bio_get_string16(msg, &len);
//根据名称查找对应的服务的handle句柄
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
dumpsys_priority = bio_get_uint32(msg);
//注册指定服务
if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
txn->sender_pid))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {
uint32_t n = bio_get_uint32(msg);
uint32_t req_dumpsys_priority = bio_get_uint32(msg);
while (si) {
if (si->dumpsys_priority & req_dumpsys_priority) {
if (n == 0) break;
n--;
}
si = si->next;
}
if (si) {
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
可以清晰的看到,该方法的功能是根据不同的code去做不同的处理,比如查询服务,注册服务,以及列举所有服务。
BR_REPLY
和 BR_TRANSCATION
实现类似。
举个栗子
//获取WindowManager服务的对象引用
WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);
//准备一个view
View view=LayoutInflater.from(getApplication()).inflate(R.layout.float_layout, null);
//添加view到wm
wm.addView(view, layoutParams);
上面这段代码我们很熟悉,通过getSystemService(getApplication().WINDOW_SERVICE)
获取WindowManager
对象的引用,接着调用WindowManager
的addView
函数,把一个view
添加到窗口上。
代码看着很简单,但我们知道,系统服务都是运行在SystemServer
进程中,所以整个过程涉及到跨进程通信。
从跨进程的角度分析一下,它是如何实现addView
过程的呢?
根据以上的知识,getSystemService(getApplication().WINDOW_SERVICE)
函数内部原理就是向ServiceManager
查询标识符为getApplication().WINDOW_SERVICE
的远程对象的引用。即WindowManager
对象的引用。
不过这个引用的真正实现是WindowManager
的某个代理。得到这个引用后,在调用addView时,真正的实现是在代理里面,代理把参数打包到Parcel对象中,然后调用transact
函数,再触发Binder驱动的一系列调用过程。