跟我学Thrift 4:由浅入深Thrift文件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跟我学Thrift 4:由浅入深Thrift文件相关的知识,希望对你有一定的参考价值。
参考技术A 我们以顾客下单买车为例子,来深入了解下Thrift的一些细节1.自定义标识符VS自动标识符
2.Optional VS Required VS Default
3.struct的组合(struct不支持继承)
首先是Thrift文件定义如下:
namespace java com.whp.demo.thrift.optional
struct Car
1:required i32 carId,
2:required string carName,
3:required i64 price,
4: optional i16 age=0
struct Consumer
1:required i32 consumerId,
2:optional string name
struct Order
required i64 orderId,
required Car car,
required Consumer consumer,
service CarService
Order createBuyCarOder(1:required Car car, 2:required Consumer consumer)
include "other.thrift" //包含其它的thrift文件
namespace java com.whp.demo //java下的namespace com.whp.demo
typedef i32 int; //tydef 语法
typedef i64 long;
enum Player
JAVA = 0;
FLASH = 1;
#required:一定会被序列号,并且如果没有被复制,将会被提醒
#optional:如果没有被赋值,将不会被序列化。如果有默认值,则将会被序列化成默认值。具有一定的向后兼容性。
#default: 默认情况下是 req-in,opt-out即 对于write stream默认是required,对于read stream是optional
#如果一个程序分开来开发,那版本问题就是绕不过去的问题。Thrift的版本是通过“field identifiers”来实现的,每个结构由其标识,结构中的每个域有其标识,这两个标识唯一决定了一个数据域。在解码的时候,数据域的标识被检查,如果不能识别,则该数据域被抛弃.
用户自定义编号是从1开始的正整数
默认编号是从-1 开始递减。
struct Order
required i64 orderId,
required Car car,
required Consumer consumer,
比如这个,编译后会成为:
ORDER_ID((short)-1,"orderId"),
CAR((short)-2,"car"),
CONSUMER((short)-3,"consumer");
struct Order
required i64 orderId,
required Car car,
required Consumer consumer,
我们可以直接在Order中组合Car和Consumer
Android : 跟我学Binder --- 驱动情景分析
目录:
-
Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制?
-
Android : 跟我学Binder --- (2) AIDL分析及手动实现
-
Android : 跟我学Binder --- (3) C程序示例
-
Android : 跟我学Binder --- (4) 驱动情景分析
-
Android : 跟我学Binder --- (5) C++实现
-
Android : 跟我学Binder --- (6) JAVA实现
一、数据结构
首先基于之前的c程序代码再添加一个goodbye服务,引入以下几个概念:
- binder_ref
- binder_node
- binder_proc
- binder_thread
- binder_buffer
1.test_server.c中实现goodbye服务处理函数:
int goodbye_service_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply) { /* 根据txn->code知道要调用哪一个函数 * 如果需要参数, 可以从msg取出 * 如果要返回结果, 可以把结果放入reply */ /* saygoodbye * saygoodbye_to */ uint16_t *s; char name[512]; size_t len; uint32_t handle; uint32_t strict_policy; int i; // Equivalent to Parcel::enforceInterface(), reading the RPC // header with the strict mode policy mask and the interface name. // Note that we ignore the strict_policy and don\'t propagate it // further (since we do no outbound RPCs anyway). strict_policy = bio_get_uint32(msg); switch(txn->code) { case GOODBYE_SVR_CMD_SAYGOODBYE: saygoodbye(); bio_put_uint32(reply, 0); /* no exception */ return 0; case GOODBYE_SVR_CMD_SAYGOODBYE_TO: /* 从msg里取出字符串(16位转8位) */ s = bio_get_string16(msg, &len); //"IGoodbyeService" s = bio_get_string16(msg, &len); // name if (s == NULL) { return -1; } for (i = 0; i < len; i++) name[i] = s[i]; name[i] = \'\\0\'; /* 处理 */ i = saygoodbye_to(name); /* 把结果放入reply */ bio_put_uint32(reply, 0); /* no exception */ bio_put_uint32(reply, i); break; default: fprintf(stderr, "unknown code %d\\n", txn->code); return -1; } return 0; }
2.main函数中注册服务:
/* add service */ ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler); if (ret) { fprintf(stderr, "failed to publish hello service\\n"); return -1; } ret = svcmgr_publish(bs, svcmgr, "goodbye", goodbye_service_handler); if (ret) { fprintf(stderr, "failed to publish goodbye service\\n"); } ...... binder_loop(bs, test_server_handler); //通过函数test_server_handler处理消息
其中 test_server_handler 会根据binder_transaction_data中的descriptor信息调用对应服务的处理函数:
int test_server_handler(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply) { int (*handler)(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply); handler = (int (*)(struct binder_state *bs, struct binder_transaction_data *txn, struct binder_io *msg, struct binder_io *reply))txn->target.ptr; return handler(bs, txn, msg, reply); // 根据txn->target.ptr转换成对应的处理函数 }
3.test_client.c中获取服务并使用:
/* get service */ handle = svcmgr_lookup(bs, svcmgr, "goodbye"); if (!handle) { fprintf(stderr, "failed to get goodbye service\\n"); return -1; } g_goodbye_handle = handle; fprintf(stderr, "Handle for goodbye service = %d\\n", g_goodbye_handle);
/* use service */ void saygoodbye(void) { unsigned iodata[512/4]; struct binder_io msg, reply; /* 构造binder_io */ bio_init(&msg, iodata, sizeof(iodata), 4); bio_put_uint32(&msg, 0); // strict mode header bio_put_string16_x(&msg, "IGoodbyeService"); /* 放入参数 */ /* 调用binder_call */ if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE)) return ; /* 从reply中解析出返回值 */ binder_done(g_bs, &msg, &reply); }
通过分别对hello和goodbye服务的注册/获取,注册和获取打印的handle值并不对应相同,这就涉及到IPC的概念:①源(自己)、②目的(handle表示)、③数据;
例如调用binder_call:
if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE)) return ;
其原型为:
/* *@msg:提供的参数 *@reply:返回的数据 *@target:发送数据的目标(服务的引用) *@code:调用函数 */ int binder_call(struct binder_state *bs, struct binder_io *msg, struct binder_io *reply, uint32_t target, uint32_t code)
binder驱动会根据handle找到目的进程,驱动内部通过 binder_ref 管理对应的引用:
struct binder_ref { int debug_id; struct rb_node rb_node_desc; struct rb_node rb_node_node; struct hlist_node node_entry; struct binder_proc *proc; struct binder_node *node; uint32_t desc; int strong; int weak; struct binder_ref_death *death; };
binder_ref添加逻辑,如图:
struct binder_node { int debug_id; struct binder_work work; union { struct rb_node rb_node; struct hlist_node dead_node; }; struct binder_proc *proc; //对应server进程 struct hlist_head refs; int internal_strong_refs; int local_weak_refs; int local_strong_refs; void __user *ptr; void __user *cookie; unsigned has_strong_ref:1; unsigned pending_strong_ref:1; unsigned has_weak_ref:1; unsigned pending_weak_ref:1; unsigned has_async_transaction:1; unsigned accept_fds:1; unsigned min_priority:8; struct list_head async_todo; };
struct binder_proc {
struct hlist_node proc_node;// list node for global binder_procs hlist
struct rb_root threads; //红黑树保存每个申请服务对象对应的线程
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
...
};
总体流程:
①server在内核态(驱动程序中)为每个服务创建binder_node, binder_node.proc = server进程;
②server_manager创建binder_ref,引用binder_node, binder_ref.desc = 1、2、3...
在用户态创建服务链表对应上面的binder_ref(.name / .handle);
③client通过name向service_manager查询服务;
④service_manager返回handle给驱动程序;
⑤驱动程序在service_manager的binder_ref红黑树中根据handle找到binder_ref,
再根据binder_ref.node找到binder_node,最后给client创建新的binder_ref,驱动返回的desc给client即为handle;
⑥client访问server进程:驱动->handle->binder_ref->binder_node->server进程,把数据放入server进程的binder_proc.todo,
接下来server进程被唤醒,反之server同样类似此流程返回结果给client;
二、数据交互过程
- 一般方法:(需要两次拷贝)
①client:构造数据 copy_from_user ---> 驱动;
②server:驱动 ---> copy_to_user 用户态处理
- binder方法:(数据一次拷贝,数据头要两次)
①server mmp内核的xx内存,可以直接访问;
②client构造数据:驱动 ---> copy_from_user 到xx内存 (涉及binder_buffer)
从前面编写的示例程序可知,与binder驱动交互主要是通过ioctl操作:
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
传入的数据为 struct binder_write_read bwr,该结构体中的 write_buffer 指向数据本身,对应结构体如下:
struct {
uint32_t cmd; //头4个字节表示数据类型
struct binder_transaction_data txn;
} __attribute__((packed)) writebuf;
三、服务注册/获取/使用过程
1.将之前的示例代码仅保留注册hello服务,编译执行log:
./service_manager & [ 32.566620] service_manager (1362, 1362), binder_thread_write : BC_ENTER_LOOPER [ 32.566712] service_manager (1362, 1362), binder_thread_read : BR_NOOP (开始休眠,等待别的进程注册服务...)
./test_server & [ 38.320197] test_server (1363, 1363), binder_thread_write : BC_TRANSACTION [ 38.320284] binder: 1363:1363 BC_TRANSACTION 2 -> 1362 - node 1, data beca6a5c-beca6a4c size 96-4 [ 38.320383] test_server (1363, 1363), binder_transaction , print data : [ 38.320454] 0000: 00 . 00 . 00 . 00 . 1a . 00 . 00 . 00 . 61 a 00 . 6e n 00 . 64 d 00 . 72 r 00 . [ 38.329064] 0016: 6f o 00 . 69 i 00 . 64 d 00 . 2e . 00 . 6f o 00 . 73 s 00 . 2e . 00 . 49 I 00 . [ 38.337917] 0032: 53 S 00 . 65 e 00 . 72 r 00 . 76 v 00 . 69 i 00 . 63 c 00 . 65 e 00 . 4d M 00 . [ 38.346771] 0048: 61 a 00 . 6e n 00 . 61 a 00 . 67 g 00 . 65 e 00 . 72 r 00 . 00 . 00 . 00 . 00 . [ 38.355646] 0064: 05 . 00 . 00 . 00 . 68 h 00 . 65 e 00 . 6c l 00 . 6c l 00 . 6f o 00 . 00 . 00 . [ 38.364475] 0080: 85 . 2a * 62 b 73 s 7f . 01 . 00 . 00 . e0 . 88 . 00 . 00 . 00 . 00 . 00 . 00 . [ 38.373350] test_server (1363, 1363), binder_thread_read : BR_NOOP [ 38.379521] service_manager (1362, 1362), binder_thread_read : BR_TRANSACTION [ 38.386633] service_manager (1362, 1362), binder_thread_read , print data : [ 38.393567] 0000: 00 . 00 . 00 . 00 . 1a . 00 . 00 . 00 . 61 a 00 . 6e n 00 . 64 d 00 . 72 r 00 . [ 38.402410] 0016: 6f o 00 . 69 i 00 . 64 d 00 . 2e . 00 . 6f o 00 . 73 s 00 . 2e . 00 . 49 I 00 . [ 38.411263] 0032: 53 S 00 . 65 e 00 . 72 r 00 . 76 v 00 . 69 i 00 . 63 c 00 . 65 e 00 . 4d M 00 . [ 38.420127] 0048: 61 a 00 . 6e n 00 . 61 a 00 . 67 g 00 . 65 e 00 . 72 r 00 . 00 . 00 . 00 . 00 . [ 38.428971] 0064: 05 . 00 . 00 . 00 . 68 h 00 . 65 e 00 . 6c l 00 . 6c l 00 . 6f o 00 . 00 . 00 . [ 38.437824] 0080: 85 . 2a * 68 h 73 s 7f . 01 . 00 . 00 . 01 . 00 . 00 . 00 . 00 . 00 . 00 . 00 . [ 38.447188] test_server (1363, 1363), binder_thread_read : BR_INCREFS [ 38.453114] test_server (1363, 1363), binder_thread_read : BR_ACQUIRE [ 38.459748] test_server (1363, 1363), binder_thread_read : BR_TRANSACTION_COMPLETE [ 38.467270] service_manager (1362, 1362), binder_thread_write : BC_ACQUIRE [ 38.474004] test_server (1363, 1363), binder_thread_read : BR_NOOP [ 38.480122] service_manager (1362, 1362), binder_thread_write : BC_REQUEST_DEATH_NOTIFICATION [ 38.488626] service_manager (1362, 1362), binder_thread_write : BC_FREE_BUFFER [ 38.495828] service_manager (1362, 1362), binder_thread_write : BC_REPLY [ 38.502538] binder: 1362:1362 BC_REPLY 5 -> 1363:1363, data bed9fa4c-bed9fa3c size 4-0 [ 38.510404] service_manager (1362, 1362), binder_transaction , print data : [ 38.517345] 0000: 00 . 00 . 00 . 00 . [ 38.520994] test_server (1363, 1363), binder_thread_read : BR_REPLY [ 38.527250] test_server (1363, 1363), binder_thread_read , print data : [ 38.540003] 0000: 00 . 00 . 00 . 00 . [ 38.543642] service_manager (1362, 1362), binder_thread_read : BR_NOOP [ 38.550253] test_server (1363, 1363), binder_thread_write : BC_FREE_BUFFER [ 38.557063] service_manager (1362, 1362), binder_thread_read : BR_TRANSACTION_COMPLETE [ 38.566481] service_manager (1362, 1362), binder_thread_read : BR_NOOP [ 38.571459] test_server (1363, 1363), binder_thread_write : BC_ENTER_LOOPER [ 38.578368] test_server (1363, 1363), binder_thread_read : BR_NOOP svcmgr: add_service(\'hello\'), handle = 1
2.根据以上log分析源码:
service_manager.c:(调用顺序如下) |
① bs->fd = open("/dev/binder", O_RDWR); (binder_proc指向当前进程) |
② ioctl(bs->fd, BINDER_VERSION, &vers) |
③ bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); |
④ ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); |
⑤ binder_thread_write : BC_ENTER_LOOPER |
⑥ binder_thread_read : BR_NOOP |
⑦ 开始休眠,等待其他进程来注册服务...... |
⑧ binder_thread_read : BR_TRANSACTION |
⑨ binder_thread_write : BC_ACQUIRE |
⑩ binder_thread_write : BC_REQUEST_DEATH_NOTIFICATION |
⑪ binder_thread_write : BC_FREE_BUFFER |
⑫ inder_thread_write : BC_REPLY |
⑬ binder_thread_read : BR_NOOP |
⑭ binder_thread_read : BR_TRANSACTION_COMPLETE |
⑮ binder_thread_read : BR_NOOP |
test_server.c: |
① open("/dev/binder", O_RDWR); |
② ioctl(bs->fd, BINDER_VERSION, &vers) |
③ mmap |
④ binder_thread_write : BC_TRANSACTION |
⑤ binder_thread_read : BR_NOOP |
⑥ binder_thread_read : BR_INCREFS |
⑦ binder_thread_read : BR_ACQUIRE |
⑧ binder_thread_read : BR_TRANSACTION_COMPLETE |
⑨ binder_thread_read : BR_NOOP |
⑩ binder_thread_read : BR_REPLY |
⑪ binder_thread_write : BC_FREE_BUFFER |
⑫ binder_thread_write : BC_ENTER_LOOPER |
⑬ binder_thread_read : BR_NOOP |
2.1 Binder 协议
Binder协议基本格式是(命令+数据),使用ioctl(fd, cmd, arg)函数实现交互。命令由参数cmd承载,数据由参数arg承载,随cmd不同而不同。
下表列举了所有命令及其所对应的数据:
命令 | 含义 | arg |
BINDER_WRITE_READ |
该命令向Binder写入或读取数据。参数分为两段:写部分和读部分。如果write_size不为0就先将write_buffer里的数据写入Binder;如果read_size不为0再从Binder中读取数据存入read_buffer中。write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读出的数据个数。 |
struct binder_write_read{ signed long write_size; signed long write_consumed; unsigned long write_buffer; signed long read_size; signed long read_consumed; unsigned long read_buffer; }; |
BINDER_SET_MAX_THREADS |
该命令告知Binder驱动接收方(通常是Server端)线程池中最大的线程数。由于Client是并发向Server端发送请求的,Server端必须开辟线程池为这些并发请求提供服务。告知驱动线程池的最大值是为了让驱动发现线程数达到该值时不要再命令接收端启动新的线程。 |
int max_threads; |
BINDER_SET_CONTEXT_MGR | 将当前进程注册为SMgr。系统中同时只能存在一个SMgr。只要当前的SMgr没有调用close()关闭Binder驱动就不能有别的进程可以成为SMgr。 | -- |
BINDER_THREAD_EXIT |
通知Binder驱动当前线程退出了。Binder会为所有参与Binder通信的线程(包括Server线程池中的线程和Client发出请求的线程)建立相应的数据结构。这些线程在退出时必须通知驱动释放相应的数据结构。 |
-- |
BINDER_VERSION |
获得Binder驱动的版本号。 |
-- |
2.2 BINDER_WRITE_READ 之写操作:
Binder写操作的数据时格式同样也是(命令+数据)。这时候命令和数据都存放在binder_write_read 结构write_buffer域指向的内存空间里,多条命令可以连续存放。数据紧接着存放在命令后面,格式根据命令不同而不同。
下表列举了Binder写操作支持的命令:
cmd | 含义 | arg |
BC_TRANSACTION |
BC_TRANSACTION用于Client向Server发送请求数据;BC_REPLY用于Server向Client发送回复(应答)数据。其后面紧接着一个binder_transaction_data结构体表明要写入的数据。 | struct binder_transaction_data |
BC_FREE_BUFFER |
-- |
-- |
BC_FREE_BUFFER | 释放一块映射的内存。Binder接收方通过mmap()映射一块较大的内存空间,Binder驱动基于这片内存采用最佳匹配算法实现接收数据缓存的动态分配和释放,满足并发请求对接收缓存区的需求。应用程序处理完这片数据后必须尽快使用该命令释放缓存区,否则会因为缓存区耗尽而无法接收新数据。 | 指向需要释放的缓存区的指针;该指针位于收到的Binder数据包中 |
BC_INCREFS BC_ACQUIRE BC_RELEASE BC_DECREFS |
这组命令增加或减少Binder的引用计数,用以实现强指针或弱指针的功能。 | 32位Binder引用号 |
BC_INCREFS_DONE BC_ACQUIRE_DONE |
第一次增加Binder实体引用计数时,驱动向Binder实体所在的进程发送BR_INCREFS, BR_ACQUIRE消息;Binder实体所在的进程处理完毕回馈BC_INCREFS_DONE,BC_ACQUIRE_DONE |
void *ptr:Binder实体在用户空间中的指针 void *cookie:与该实体相关的附加数据 |
BC_REGISTER_LOOPER BC_ENTER_LOOPER BC_EXIT_LOOPER |
这组命令同BINDER_SET_MAX_THREADS一道实现Binder驱动对接收方线程池管理。BC_REGISTER_LOOPER通知驱动线程池中一个线程已经创建了;BC_ENTER_LOOPER通知驱动该线程已经进入主循环,可以接收数据;BC_EXIT_LOOPER通知驱动该线程退出主循环,不再接收数据。 |
-- |
BC_REQUEST_DEATH_NOTIFICATION | 获得Binder引用的进程通过该命令要求驱动在Binder实体销毁得到通知。虽说强指针可以确保只要有引用就不会销毁实体,但这毕竟是个跨进程的引用,谁也无法保证实体由于所在的Server关闭Binder驱动或异常退出而消失,引用者能做的是要求Server在此刻给出通知。 |
uint32 *ptr; 需要得到死亡通知的Binder引用 void **cookie: 与死亡通知相关的信息,驱动会在发出死亡通知时返回给发出请求的进程。 |
BC_DEAD_BINDER_DONE | 收到实体死亡通知书的进程在删除引用后用本命令告知驱动。 | void **cookie |
在这些命令中,最常用的是BC_TRANSACTION/BC_REPLY命令对,Binder请求和应答数据就是通过这对命令发送给接收方。这对命令所承载的数据包由结构体struct binder_transaction_data定义。Binder交互有同步和异步之分,利用binder_transaction_data中flag域区分。如果flag域的TF_ONE_WAY位为1则为异步交互,即Client端发送完请求交互即结束, Server端不再返回BC_REPLY数据包;否则Server会返回BC_REPLY数据包,Client端必须等待接收完该数据包方才完成一次交互。
2.3 BINDER_WRITE_READ :从Binder读出数据
从Binder里读出的数据格式和向Binder中写入的数据格式一样,采用(消息ID+数据)形式,并且多条消息可以连续存放。
下表列举了从Binder读出的命令字及其相应的参数:
消息 | 含义 | 参数 |
BR_ERROR | 发生内部错误(如内存分配失败) | -- |
BR_OK BR_NOOP |
操作完成 | -- |
BR_SPAWN_LOOPER | 该消息用于接收方线程池管理。当驱动发现接收方所有线程都处于忙碌状态且线程池里的线程总数没有超过BINDER_SET_MAX_THREADS设置的最大线程数时,向接收方发送该命令要求创建更多线程以备接收数据。 | -- |
BR_TRANSACTION BR_REPLY |
这两条消息分别对应发送方的BC_TRANSACTION和BC_REPLY,表示当前接收的数据是请求还是回复。 | binder_transaction_data |
BR_ACQUIRE_RESULT BR_ATTEMPT_ACQUIRE BR_FINISHED |
-- | -- |
BR_DEAD_REPLY | 交互过程中如果发现对方进程或线程已经死亡则返回该消息 | -- |
BR_TRANSACTION_COMPLETE | 发送方通过BC_TRANSACTION或BC_REPLY发送完一个数据包后,都能收到该消息做为成功发送的反馈。这和BR_REPLY不一样,是驱动告知发送方已经发送成功,而不是Server端返回请求数据。所以不管同步还是异步交互接收方都能获得本消息。 |
-- |
BR_INCREFS BR_ACQUIRE BR_RELEASE BR_DECREFS |
这一组消息用于管理强/弱指针的引用计数。只有提供Binder实体的进程才能收到这组消息。 |
void *ptr:Binder实体在用户空间中的指针 void *cookie:与该实体相关的附加数据 |
BR_DEAD_BINDER BR_CLEAR_DEATH_NOTIFICATION_DONE |
向获得Binder引用的进程发送Binder实体死亡通知书;收到死亡通知书的进程接下来会返回BC_DEAD_BINDER_DONE做确认。 | void **cookie:在使用BC_REQUEST_DEATH_NOTIFICATION注册死亡通知时的附加参数。 |
BR_FAILED_REPLY |
如果发送非法引用号则返回该消息 |
-- |
注:其中只有 BC_TRANSACTION、BC_REPLY、BR_TRANSACTION 、BR_REPLY 涉及两个进程,其它所有cmd只是APP和驱动的交互,用于改变或报告状态。
四、transaction_stack机制
前面大致了解到两个进程A、B通信流程如下:
1.client端发送数据给server进程时handle只表明了对应的进程,而server是多线程的,同时有多个binder_thread,所以分两种情况:
(1)发送的数据一般放在进程的binder_proc.todo列表,唤醒等待于binder_proc.wait的空闲线程。
(2)通过transaction_stack来判断为双向传输,则发送的数据放在binder_thread.todo列表,然后唤醒该线程。
2.server端回复数据时,如果无handle表明目的进程,则通过传输栈transaction_stack保存的“发送者”信息回复,而信息则是在transaction_stack结构体中 .frome 、.to_proc、.to_thread保存,然后通过同一个 binder_transaction 的 .from_parent 放入发送者的栈,通过 .to_parent 放入接收者的栈。
Binder Driver总结:
1. Binder node:
前面说过Service 其实是一个存在于某个进程里的对象,因此,进程PID 和 对象地址可以唯一的标识一个Service 对象,除此之外,因为这个对象可能被很多应用所使用,必须有引用计数来管理他的生命周期。这些工作都必须在内核里完成,Binder node 就是这样一个结构体来管理每个Service 对象。
struct binder_node {
int debug_id; //kernel内部标识node的id
struct binder_work work;
union {
struct rb_node rb_node;
struct hlist_node dead_node;
};
struct binder_proc *proc; //Service所在进程的结构体
struct hlist_head refs; //双向链表头,链表里存放一系列指针,指向引用该Service的binder_ref对象,
int internal_strong_refs; //内部强引用计数
int local_weak_refs; //弱引用计数
int local_strong_refs; //强引用计数
binder_ptr __user ptr; //Service对象地址
binder_ptr __user cookie;
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
unsigned pending_weak_ref:1;
unsigned has_async_transaction:1;
unsigned accept_fds:1;
unsigned min_priority:8;
struct list_head async_todo;
};
2. binder_ref
binder_ref 描述了每个对服务对象的引用,对应与Client端。如上图所示,每个Ref通过node指向binder_node. 一个进程所有的binder_ref通过两个红黑树(RbTree)进行管理,通过binder_get_ref() 和 binder_get_ref_for_node快速查找。
struct binder_ref {
/* Lookups needed: */
/* node + proc => ref (transaction) */
/* desc + proc => ref (transaction, inc/dec ref) */
/* node => refs + procs (proc exit) */
int debug_id;
struct rb_node rb_node_desc;
struct rb_node rb_node_node;
struct hlist_node node_entry;
struct binder_proc *proc; //应用进程
struct binder_node *node;
uint32_t desc;
int strong;
int weak;
struct binder_ref_death *death; //如果不为空,则client想获知binder的以上是关于跟我学Thrift 4:由浅入深Thrift文件的主要内容,如果未能解决你的问题,请参考以下文章