IPC,进程间通信,a进程发送数据给b进程,就是跨进程通信。
RPC,远程调用,a进程想打开led,点亮led,调用led_open函数,通过IPC发送数据给b进程,b取出数据,然后调用b进程的led_open函数,看似a进程来直接操作led_open函数一样,实际上是a发送数据给b,b操作硬件
b进程服务端程序要先向servicemanager注册服务,a进程查询led_服务,得到一个handle,指向进程b。
数据一般存在char buf[1024]里面。a,b进程通过buffer传递数据双端。
谷歌的源码参考目录
binder.c(谷歌封装好的c函数)
2.流程servicemanager先由系统先运行,
open binder驱动告诉驱动程序自己就是servicemanagerwhile(1)循环,读数据,读取驱动,获取数据,没有数据就休眠,得到数据就解析数据。 服务端注册服务,在链表中记录服务名,客户端获取服务,查询链表中的服务,返回服务端进程服务端程序:
open驱动注册服务,向servicemanager发送服务的名字,while(1)读驱动,无数据就休眠,解析数据,调用系统对应的底层函数,客户端程序:
open驱动。获取服务,向servicemanager查询服务,获得一个handle,向handle句柄发送数据。打开驱动程序
告诉驱动程序自己就是servicemanager
循环读取数据,
binder_loop读数据,
解析数据
处理回复信息给客户端
客户端获取服务
注册服务
3.bctest.c 3.1 注册服务,打开binder驱动注册服务,构造好数据
发给目标target
我们看一下这个值
在头文件中定义,句柄是0,进程间通信,0就是servicemanager进程,
通过binder_call调用,code: 表示要调用servicemanager中的"addservice"函数
3.2 获取服务打开驱动, 循环查询服务列表
if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
return 0;
还是调用binder_call函数,msg中含有你想获取服务的名字,含有servicemanager回复的数据,
4.binder_call实现远程调用, 向谁发数据,
target,目的进程
code,调用的函数
msg,提供的数据参数
reply,返回值
构造我们要发送的数据,放在buffer中,用binder_io
调用ioctl发送数据。
int binder_call(struct binder_state *bs, struct binder_io *msg, struct binder_io *reply, uint32_t target, uint32_t code) { int res; struct binder_write_read bwr; struct { uint32_t cmd; struct binder_transaction_data txn; } __attribute__((packed)) writebuf; unsigned readbuf[32]; if (msg->flags & BIO_F_OVERFLOW) { fprintf(stderr,"binder: txn buffer overflow\n"); goto fail; } writebuf.cmd = BC_TRANSACTION; writebuf.txn.target.handle = target; writebuf.txn.code = code; writebuf.txn.flags = 0; writebuf.txn.data_size = msg->data - msg->data0; writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; bwr.write_size = sizeof(writebuf); bwr.write_consumed = 0; bwr.write_buffer = (uintptr_t) &writebuf; hexdump(msg->data0, msg->data - msg->data0); for (;;) { bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (uintptr_t) readbuf; //调用ioctl发送数据。bwr结构体 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if (res < 0) { fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); goto fail; } res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); if (res == 0) return 0; if (res < 0) goto fail; } fail: memset(reply, 0, sizeof(*reply)); reply->flags |= BIO_F_IOERROR; return -1; }数据要转换,binder_io参数是这个类型,内核驱动要求res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);bwr是上图的类型。
ioctl收数据,也会收到binder_write_read,然后转化为binder_io
svcmgr_lookup看下面源码
uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) { uint32_t handle; //binder_io对缓冲区的管理 unsigned iodata[512/4]; //初始化结构体binder_io struct binder_io msg, reply; //初始化就可以在缓冲池里面放数据 了 bio_init(&msg, iodata, sizeof(iodata), 4); bio_put_uint32(&msg, 0); // strict mode header bio_put_string16_x(&msg, SVC_MGR_NAME); bio_put_string16_x(&msg, name); //binder_io发送给驱动 if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) return 0; handle = bio_get_ref(&reply); if (handle) binder_acquire(bs, handle); binder_done(bs, &msg, &reply); return handle; }