功能:Android是基于Linux内核构建的上层系统软件,虽然Linux内核提供了 共享内存、信号、消息队列、socket、管道等等方式来进程进程间通信,但是Android并没有使用这些方式,而是使用一种Binder的机制(当然ril模块中用socket、蓝牙中貌似用了另外一种方式)。
Binder机制用来实现Android进程间的通信,Binder实现了RPC机制。传统的Linux进程间通信实现的都是消息传递的类型,而Binder实现的RPC使得应用程序调用一个远程对象,可以像调用本地对象一样使用。
原理:从上面的图形我们发现视乎是Client和Server共享了/dev/binder设备文件,ServiceManager用来统一管理添加的Service。我们猜测大致工作流程如下:
1.Server向ServiceManager中注册服务
2.Client向SM中查询某个服务
3.Client通过/dev/binder和Server进行通信
问题:ServiceManager的功能?、Client和Server通信如何知道对方?、Client和Server通信时做了什么?、通信的数据形式?、binder驱动的实现?
ServiceManager的功能
源码frameworks/base/cmds/servicemanager,主要用来登记服务。Server注册服务、Client利用它来查询服务。
初始化函数,ServiceManager是一个单独的进程。1.打开了/dev/binder 2.利用binder_become_context_manager将自己变成ServiceManager服务,服务的handle号置为默认0 3.闭合结构用来读数据、解析数据、并返回结果
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)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}
下面是关键操作binder_loop函数,利用ioctl读取bwr包(阻塞方式),并解析bwr包
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
unsigned readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(unsigned));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (unsigned) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
接下来是使binder_parse使用状态机解析bwr包,主要完成了下面工作:
解析BR_TRANSACTION(请求数据包)、BR_REPLY(返回数据包)等等,其中BR_TRANSACTION会使用svcmgr_handler回调函数来解析请求(SVC_MGR_GET_SERVICE、SVC_MGR_CHECK_SERVICE、SVC_MGR_ADD_SERVICE、SVC_MGR_LIST_SERVICES)
int binder_parse(struct binder_state *bs, struct binder_io *bio,uint32_t *ptr, uint32_t size, binder_handler func)
uint32_t *end = ptr + (size / 4);
while (ptr < end) {
uint32_t cmd = *ptr++;
switch(cmd) {
case BR_NOOP:
break;
case BR_TRANSACTION_COMPLETE:
break;
case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS:
ptr += 2;
break;
case BR_TRANSACTION: {
//请求数据包
break;
}
case BR_REPLY: {
//应答数据包
break
}
case BR_DEAD_BINDER: {
//死亡通知
break;
}
case BR_FAILED_REPLY:
//应答失败
break;
case BR_DEAD_REPLY:
r = -1;
break;
default:
ALOGE("parse: OOPS %d\n", cmd);
return -1;
}
}
return r;
}
关于
SVC_MGR_ADD_SERVICE、SVC_MGR_GET_SERVICE两个关键请求,实现都在svcmgr_handler中:
SVC_MGR_ADD_SERVICE
set服务时,需要创建svcinfo结构添加到svclist中,同时需要利用binder_acquire将服务注册到binder驱动中。添加失败返回-1,无replay。
SVC_MGR_GET_SERVICE
get服务时,需要查询svclist,并返回reply数据到binder驱动中
Client和Server通信如何知道对方
ServiceManager服务的handler号默认为0,并且公开,因此所有的Client都知道ServiceManager这个服务号。
知道服务号,请求数据又是如何传递过去的呢。这里Binder驱动中实际上记录了所有服务号和路径,Client的请求数据先发给Binder驱动,Binder驱动实现数据路由的功能(原理在底层), 这样请求就能正确的到答Server端。
Client和Server通信时做了什么
上面的图形强调了Client、Server、ServiceManager是出在同一层次的,它们都是通信的端点。只不过,ServiceManager的地址是公认的,所有其他的Client、Server都知道它的Handle号为0。因此ServiceManger起到了DNS的功能,Server注册服务到其中,Client在其中查询服务。
但是同时,它们有不是直接通信的,它们之间的请求、应答是通过Binder驱动来转发的,因此这里的Binder实现的相当于一个路由的功能。
IPCThreadState::talkWithDriver)、解析数据(executeCommand)、处理并返回(talkWithDriver)”。
int main(int argc, char** argv) //main_mediaserver.cpp代码
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
ServiceManager当中查询服务,获取服务handle号,进行发送数据(IPCThreadState::transact, 该函数利用writeTransactionData到缓存mOut, 并利用waitForResponse的talkWithDriver发送数据),当然waitForResponse里面包括了接受应答。
分析到这里,基本理解了Client与Server端的通信步骤,但是对于数据的形式、数据路由怎么实现,必须得深入到地下了。
Binder通信的数据形式
Binder驱动路由功能的实现
Binder总结