binder 进程间通讯关于handle一点疑问?(自己已经弄明白了一点)
来源:互联网 发布:编写手机程序软件 编辑:程序博客网 时间:2024/05/19 11:44
疑问的提出:
我只知道servcemanger是固定死了是0,其他的服务呢?
以CameraService为例
mediaserver启动,创建Camera服务端
CameraService::instantiate();
--> defaultServiceManager()->addService("media.camera",new CamraService)
--> IServiceManger::addService
{
Parcel data
data.writeString16("android.os.IServiceManger");
data.writeString16(name);
data.writeStrongBinder(service);
-->flatten_binder(ProcessState::self(), service, this); //就在这个函数里有点疑问
IPCThreadState::transact(data);
}
flatten_binder函数源码:
status_t flatten_binder(const sp<ProcessState>& proc,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) { //执行这个分支
IBinder *local = binder->localBinder(); //由于CameraService是继承于BBinder,所以local返回对象实列,local是不空的
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
LOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.handle = handle;
obj.cookie = NULL;
} else { //执行这个分支
obj.type = BINDER_TYPE_BINDER;
obj.binder = local->getWeakRefs();
obj.cookie = local;
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = NULL;
obj.cookie = NULL;
}
return finish_flatten_binder(binder, obj, out);
}
将这个 flat_binder_object写入到Parcel类中,再调用 IPCThreadState::transact将Parcel数据填充binder_transaction_data数据结构,将此数据结构写入内 核,在内核具体作了什么不是很清楚,没看过代码。
ServiceManger服务进程
Service_manger.c main()
从内核读到数据后会一层层的分析,会调用到svcmgr_handler函数,其中涉及到addService的代码:
svcmgr_handler(){
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len); //这个是取出字符串,就是“media.camera”
ptr = bio_get_ref(msg); //这个就是取出handle,但是是0,后面会分析这个函数
if (do_add_service(bs, s, len, ptr, txn->sender_euid)) //这个函数因为ptr是0,直接返回并没于把(name,handle)加到svrlist全局列表里,这明显分析 的是不对的,困惑呀????
return -1;
break;
}
}
bio_get_ref
{
struct binder_object *obj;
obj = _bio_get_obj(bio); //这个取出在flatten_binder函 数设置的flat_binder_object变量值(binder_object与flat_binder_object结构体一样)
if (!obj)
return 0;
if (obj->type == BINDER_TYPE_HANDLE) //这个分支 不满足,因为之前设置的是BINDER_TYPE_BINDER
return obj->pointer;
return 0; //函数返回0
}
疑问解决:
今天粗略的看了一下内核知道一点原因了将把flat_binder_object写入内核时,会调用
ioctl(BINDER_WRITE_READ)
内核
-->binder_ioctl-->binder_thread_write->binder_transaction
binder_transaction{fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
case BINDER_TYPE_BINDER: //前面分析,传进来的是这个类型
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
struct binder_node *node = binder_get_node(proc, fp->binder);
if (node == NULL) {
node = binder_new_node(proc, fp->binder, fp->cookie);
if (node == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_new_node_failed;
}
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
if (fp->cookie != node->cookie) {
binder_user_error("binder: %d:%d sending u%p "
"node %d, cookie mismatch %p != %p\n",
proc->pid, thread->pid,
fp->binder, node->debug_id,
fp->cookie, node->cookie);
goto err_binder_get_ref_for_node_failed;
}
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
if (fp->type == BINDER_TYPE_BINDER) //在这里类型变了
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc; //handle就是在这里设置的,后面再简单说明一下 ref->desc是怎么来的,就在前面的binder_get_ref_for_node的函数里设置的
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
binder_debug(BINDER_DEBUG_TRANSACTION,
" node %d u%p -> ref %d desc %d\n",
node->debug_id, node->ptr, ref->debug_id,
ref->desc);
} break;
}
将fp设置后等待对应的进程读
binder_thread_read
{
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (void *)t->buffer->data +
proc->user_buffer_offset;
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
返回tr给用户空间
}
再来以前提出的函数
bio_get_ref
{
struct binder_object *obj;
obj = _bio_get_obj(bio);
if (!obj)
return 0;
if (obj->type == BINDER_TYPE_HANDLE)//第一次分析错误,其实走这个分支
return obj->pointer; //pointer就是fp->handle
return 0;
}
这样分析就对了,将name和handle加到了svrlist列表里,上面就是addService的过程,再简单所一下相对应的getService过程,用户空间的我就简单的提一下
defaultServiceManager()->getService("media.camera")
--> IServiceManger::checkService
{
Parcel data
data.writeString16("android.os.IServiceManger");
data.writeString16(name);
IPCThreadState::transact(data,replay);
-->ioctrl(BINDER_WRITE_READ)
replay.readStrongBinder();
-->unflatten_binder(ProcessState::self(), this,&val);
}
将字符串传给servicemanger,servicemanger会在svrlist列表里根据name查找handle,在将handle填充flat_binder_object写入内核
int svcmgr_handler(){
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
ptr = do_find_service(bs, s, len);
if (!ptr)
break;
bio_put_ref(reply, ptr);
return 0;
}
}
void bio_put_ref(struct binder_io *bio, void *ptr)
{
struct binder_object *obj;
if (ptr)
obj = bio_alloc_obj(bio);
else
obj = bio_alloc(bio, sizeof(*obj));
if (!obj)
return;
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj->type = BINDER_TYPE_HANDLE; //注意类型
obj->pointer = ptr; //pointer指向handle
obj->cookie = 0;
}
内核代码
binder_transaction{
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
case BINDER_TYPE_HANDLE://前面分析,传进来的是这个类型
case BINDER_TYPE_WEAK_HANDLE: {
struct binder_ref *ref = binder_get_ref(proc, fp->handle); //根据handle查找binder_ref节点,每个handle对应于一个
if (ref == NULL) {
binder_user_error("binder: %d:%d got "
"transaction with invalid "
"handle, %ld\n", proc->pid,
thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
if (ref->node->proc == target_proc) { //要接受数据的进程与handle所标识的服务进程是同一个
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER; //返回给用户前,类型又变了,告诉接受进程“你可以直接使用fp->cookie保存的对象引用,因为你跟对象在一个进程里”
else
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie; //这个指向服务进程内的服务对象的实例
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> node %d u%p\n",
ref->debug_id, ref->desc, ref->node->debug_id,
ref->node->ptr);
} else {//要接受数据的进程与handle所标识的服务进程不是同一个
struct binder_ref *new_ref;
new_ref = binder_get_ref_for_node(target_proc, ref->node);
if (new_ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
fp->handle = new_ref->desc; //赋值服务对象的handle,这里很重要,是我一直想要弄明白的地方,在这里真相大白,不过还有一点点不懂,那就不管了
binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> ref %d desc %d (node %d)\n",
ref->debug_id, ref->desc, new_ref->debug_id,
new_ref->desc, ref->node->debug_id);
}
} break;
}
将这个fp返回给用户空间
用户空间
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = static_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE: //不在同一个进程的话执行这个分支
*out = proc->getStrongProxyForHandle(flat->handle);//根据handle创建BpBinder,分析到这里就可以结束了,通过getService调用返回相应服务对象的handle并根据handle创建BpBinder
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
- binder 进程间通讯关于handle一点疑问?(自己已经弄明白了一点)
- binder 进程间通讯关于handle一点疑问
- snprintf明白了一点
- 关于CCombox一点疑问
- 关于bitset的一点疑问
- 关于foreach的一点疑问
- 关于路由器的一点疑问
- 关于JSP的一点疑问
- 关于sizeof的一点疑问
- 关于strcat的一点疑问
- 关于mmap的一点疑问
- 关于count的一点疑问
- 一点疑问
- 关于System.in(out、err)的一点疑问
- 关于onreadystatechange属性的一点疑问
- 关于onreadystatechange属性的一点疑问
- 关于onreadystatechange属性的一点疑问
- 关于嵌入式Linux的一点疑问
- java学习 --接口的多重继承
- div各种属性
- android中dip、dp、px、sp和屏幕密度
- FIX标准的工作流服务组件
- 在VMware server 中安装 CentOS5.6+Oracle11gR2 swap 空间不够,增加swap 空间
- binder 进程间通讯关于handle一点疑问?(自己已经弄明白了一点)
- ccs中的cmd
- How to use an ASP.NET application to query an Indexing Service catalog by using Visual Basic .NET
- 养成好的习惯
- 使用System.Transactions
- 操作datatable进行分页,绑定repeqter或者gridView
- 网摘
- 每天学习一算法系列(18)(n 个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m 个数字)
- QC的安装注意点