Android进程间通信(IPC)机制Binder

功能:Android是基于Linux内核构建的上层系统软件,虽然Linux内核提供了 共享内存、信号、消息队列、socket、管道等等方式来进程进程间通信,但是Android并没有使用这些方式,而是使用一种Binder的机制(当然ril模块中用socket、蓝牙中貌似用了另外一种方式)。

             Binder机制用来实现Android进程间的通信,Binder实现了RPC机制。传统的Linux进程间通信实现的都是消息传递的类型,而Binder实现的RPC使得应用程序调用一个远程对象,可以像调用本地对象一样使用。

             参考:http://blog.csdn.net/dr8737010/article/details/17657307

原理:从上面的图形我们发现视乎是ClientServer共享了/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通信如何知道对方

        从C++层来看,Client需要请求的服务,必须是Server在ServiceManager中注册过的服务。而ServiceManager实际上本身就是系统注册的一个服务,也就是说Client必须默认就知道ServiceManager服务对应的handle号。在Binder机制实现的时候,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实现的相当于一个路由的功能。

        Server端的工作包括:服务的创建,登记到ServiceManager当中(利用ProcessState打开/dev/binder,并获取defaultServiceManager),创建线程池,线程进入闭合结构“接收数据(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();
}

        Client段的工作包括:ServiceManager当中查询服务,获取服务handle号,进行发送数据(IPCThreadState::transact, 该函数利用writeTransactionData到缓存mOut, 并利用waitForResponse的talkWithDriver发送数据),当然waitForResponse里面包括了接受应答。

        分析到这里,基本理解了Client与Server端的通信步骤,但是对于数据的形式、数据路由怎么实现,必须得深入到地下了。


Binder通信的数据形式

        参考: http://blog.csdn.net/universus/article/details/6211589/





Binder驱动路由功能的实现

        





Binder总结

        



参考:http://blog.csdn.net/bathinbreeze/article/details/8989105

          http://blog.csdn.net/coding_glacier/article/details/7520199

          http://blog.csdn.net/luoshengyang/article/details/6618363

          http://blog.csdn.net/universus/article/details/6211589/


        

Binder驱动路由功能的实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值