Android入门之Binder学习(三)

 

接上一次的一篇,这样发的文章,感觉只是我自己懂了,看的人都不知道说些什么,有待重新整理后,守护进程的归守护进程,驱动的归驱动,从架构上阐述一下,而不是简单地逐行分析。...



现在假定有内容,读到了之后,即进行解析,调用了ServiceManager的binder_parse方法,看看:

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;// buffer大小,buffer是驱动用copy_to_user写的

while (ptr < end) {

uint32_t cmd = *(uint32_t *) ptr;// 读取命令

ptr += sizeof(uint32_t);// 命令的偏移量

#if TRACE

fprintf(stderr,"%s:
", cmd_name(cmd));

#endif

switch(cmd) {

case BR_NOOP:// 成功,没有回传数据

break;

case BR_TRANSACTION_COMPLETE:// 传输完毕

break;

case BR_INCREFS:

case BR_ACQUIRE:

case BR_RELEASE:

case BR_DECREFS:

#if TRACE

fprintf(stderr,"  %p, %p
", (void *)ptr, (void *)(ptr + sizeof(void *)));

#endif

ptr += sizeof(struct binder_ptr_cookie);// 偏移cookie的长度

break;

case BR_TRANSACTION: {// 交互,首先把地址的内容转回成binder_transaction_data

struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;

if ((end - ptr) < sizeof(*txn)) {

ALOGE("parse: txn too small!
");

return -1;

}

binder_dump_txn(txn);

if (func) {// svcmgr_handler这个回调函数,定义在service_manager.c中,main方法的入参

unsigned rdata[256/4];

struct binder_io msg;// 传来的消息,定义在binder.h,数据指针,偏移等存在里面

struct binder_io reply;// 回复的结构体

int res;

bio_init(&reply, rdata, sizeof(rdata), 4);// 传引用的方式初始化replay

bio_init_from_txn(&msg, txn);// 通过驱动写入的binder_transaction_data初始化binder_io这个结构体

res = func(bs, txn, &msg, &reply);// 回调

if (txn->flags & TF_ONE_WAY) {// 不必回传数据,直接释放buffer

binder_free_buffer(bs, txn->data.ptr.buffer);

} else {// 发送回传数据

binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);

}

}

ptr += sizeof(*txn);// 加偏移,又有一部分内存被用了

break;// 回传1

}

case BR_REPLY: {// 这就是回传回来的数据

struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;

if ((end - ptr) < sizeof(*txn)) {// buffer长度太短

ALOGE("parse: reply too small!
");

return -1;

}

binder_dump_txn(txn);

if (bio) {

bio_init_from_txn(bio, txn);// 初始化binder_io结构体

bio = 0;// 初始化

} else {

/* todo FREE BUFFER */

}

ptr += sizeof(*txn);// 消耗了内存,加偏移

r = 0;// 结果正常

break;

}

case BR_DEAD_BINDER: {// binder挂掉,传过来的是binder_death这个结构体

struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;

ptr += sizeof(binder_uintptr_t);

death->func(bs, death->ptr);回调处理

break;

}

case BR_FAILED_REPLY:// 收到对端关于收到Binder失败的回传

r = -1;// 返回错误码

break;

case BR_DEAD_REPLY:// 收到对端收到Binder dead的回传

r = -1;  // 返回错误码

break;

default:

ALOGE("parse: OOPS %d
", cmd);

return -1;

}

}

return r;

}

这里看看回调函数怎么处理的:

int svcmgr_handler(struct binder_state *bs,

struct binder_transaction_data *txn,

struct binder_io *msg,

struct binder_io *reply)

{

struct svcinfo *si;// 即service info,有是否允许孤立运行,handle,binder_death

uint16_t *s;

size_t len;

uint32_t handle;

uint32_t strict_policy;

int allow_isolated;

//ALOGI("target=%p code=%d pid=%d uid=%d
",

//      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);

if (txn->target.ptr != BINDER_SERVICE_MANAGER)// 非BINDER_SERVICE_MANAGER,这是servicemanager的回调,自然出错了

return -1;

if (txn->code == PING_TRANSACTION)// 查找远程binder是不是存在

return 0;

// 等价于Parcel::enforceInterface(), 读RPC头获取‘严苛模式‘的标记位,以及接口名。记住一点,那就是我们忽略严苛模式策略,且不再传递

// 它,因为我们并不对外RPC通讯。

strict_policy = bio_get_uint32(msg);

s = bio_get_string16(msg, &len);

if (s == NULL) {

return -1;

}

if ((len != (sizeof(svcmgr_id) / 2)) ||

memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {// 获取的svcmgr_id,

fprintf(stderr,"invalid id %s
", str8(s, len));

return -1;

}

……

switch(txn->code) {

case SVC_MGR_GET_SERVICE:// 获取服务或检查服务是否存在

case SVC_MGR_CHECK_SERVICE:

s = bio_get_string16(msg, &len);

if (s == NULL) {

return -1;

}

handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);// 通过euid,pid找服务

if (!handle)

break;

bio_put_ref(reply, handle);// 添加引用

return 0;

case SVC_MGR_ADD_SERVICE:// 注册服务,之后分析服务添加将走到这里,FWK的整个体系

s = bio_get_string16(msg, &len);

if (s == NULL) {

return -1;

}

handle = bio_get_ref(msg);

allow_isolated = bio_get_uint32(msg) ? 1 : 0;// 允许孤立运行

if (do_add_service(bs, s, len, handle, txn->sender_euid,

allow_isolated, txn->sender_pid))// 添加服务

return -1;

break;

case SVC_MGR_LIST_SERVICES: {// 列出其表

uint32_t n = bio_get_uint32(msg);

if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {

ALOGE("list_service() uid=%d - PERMISSION DENIED
",

txn->sender_euid);

return -1;

}

si = svclist;

while ((n-- > 0) && si)

si = si->next;// 遍历

if (si) {

bio_put_string16(reply, si->name);// 返回其name

return 0;

}

return -1;

}

default:

ALOGE("unknown code %d
", txn->code);

return -1;

}

bio_put_uint32(reply, 0);

return 0;

}

回调函数的内容很清楚,就是读取binder驱动写入的cmd,拿到命令,进行相关操作,主要有:

² pingBinder

² 查询服务是否存在,获取服务

² 获取服务名列表

² 添加服务


    关注 来哥的技术栈


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册