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
² 查询服务是否存在,获取服务
² 获取服务名列表
² 添加服务
关注 来哥的技术栈
微信扫一扫关注公众号