- 注册 native 服务到 service_manager。
以 SurfaceFlinger 服务为例。
//main_surfaceflinger.cpp
int main(int, char**){
ProcessState::self( )->setThreadPoolMaxThreadCount(4);
sp<ProcessState> ps(ProcessState::self);
ps->startThreadPool( );
sp<SurfaceFinger> flinger = new SurfaceFlinger( );
setPriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
flinger->init( );
sp<IServiceManager> sm(defaultServiceManager( ));
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, flase);
flinger.run( );
return 0;
}
首先来看 defaultServiceManager( )是个什么东西,参见defaultServiceManager( )。
于是
gDefaultServiceManager() = new BpServiceManager(new BpBinder(0));
这时候调用 addService( )方法
//IServiceManager.cpp
virtual status_t addService(const String16$ name, const sp<IBinder>& service, bool allowIsolated){
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor( ));
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote( )->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err = NO_ERROR ? reply.readExceptiomCode( ): err;
}
先来关注一波 Parce的 writeStrongBinder(service)等方法Parcel 写入 SurfaceFlinger 服务本地对象; 此时 SurfaceFlinger 变被转换成了 flat_binder_object 对象存储在 Parcel 中,flat_binder_object ->type = BINDER_TYPE_BINDER, flat_binder_object ->binder 字段保存了 SurfaceFlinger 服务本地对象的弱引用计数对象,flat_binder_object->cookie 保存了 SurfaceFlinger 服务本地对象的指针。
关于 flat_binder_object 的描述在 Binder 的数据结构介绍中也有介绍
然后来关注 remote( )->transact(ADD_SERVICE_TRANSACTION, data, &reply);
我们知道整理的 remote( )是一个 BpBinder 对象,其 mHandle 为 0。
//BpBinder.cpp
status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
//不传递 flags 的时候,flags 为 0
status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
}
IPCThreadState是一个线程单例, IPCThreadState::self()返回该线程的一个代表。
//IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
//此时 flags 为 0
error = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
if(reply){
error =waitForResponse(reply);
}else{
Parcel fakeReply;
error = waitForResponse(&fakeReply);
}
}
从上面看出,先用 writeTransactionData( )打包请求数据,再用 waitForResponse( )发送请求。
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer){
binder_transaction_data tr;
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
if(err == NO_ERROR) {
//将 Pacel 中的数据转移到 binder_transaction_data 中
tr.data_size = data.ipcDataSize( ); //数据大小
tr.data.ptr.buffer = data.ipcData( ) //数据保存的内存地址
tr.offsets_size = data.ipcObjectsCount( )*sizeof(binder_size_t); //Binder 对象在 Parcel 中以 flag_binder_object 存在
tr.data.ptr.offsets=data.ipcObjects( );
}else if(statusBuffer){
//本例中 statusBuffer 为 NULL,不分析
}
//此处的 cmd 为BC_TRANSACTION,表示向 Binder 驱动发送请求调用
// mOut 是 Parcel 类
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
}
此处的 binder_transaction_data 在 Binder 的数据结构介绍已经介绍过了。此处 handle = 0,代表目标 Binder 是代理,此处代表 BpServiceManager。code = ADD_SERVICE_TRANSACTION, ServiceManager 进程收到请求后,根据这个 code 判断具体需要调用的方法。
![](https://img.haomeiwen.com/i3012162/c14bbf78ecb7d148.png)
可以看到现在在 mOut 中写入了一个 cmd 为 BC_TRANSACTION表示此次是 Client 向 Binder发送请求调用。写入了一个包裹了请求数据的 binder_transaction_data;改包封装了向 Server 请求调用的具体参数(包括以 flat_binder_object 包裹的 IBinder 对象)
status_t IPCThread::waitForResponse(Parcel *reply, status_t *acquireResult) {
//acquireResult 默认为 NULL,此处就为 NULL,
uint32_t cmd;
int32_t err;
while(1) {
if((err = talkWithDriver() ) < NO_ERROR) break;
...
}
}
taklWithDriver( )是真正和 Binder Driver 通信的的方法,下面的方法是处理通信结果的。
statis_t IPCThreadState::talkWithDriver(bool doReceiver){
//doReceiver 默认为 true,此次便取默认值 true
binder_write_read bwr;
const bool needRead = mIn.dataPosition( ) >= mIn.dataSize();
const size_t outAvail = (!doReceiver || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
//指向实际的参数的内存地址
bwr.write_buffer = (uintptr_t)mOut.data( );
if(doReceiver && needRead){
bwr.read_size = mIn.dataCapacity( );
bwr.read_buffer = (uintptr_t)mIn.data( );
}else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
...
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);
}
//binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
thread = binder_get_thread(proc);
switch(cmd){
case BINDER_WRITE_READ:
struct binder_write_read bwr;
//内核空间无法使用用户空间的虚拟地址,因此需要经过 copy_from_user 才可以使用
copy_from_user(&bwr, ubuf, sizeof(bwr));
if(bwr.write_size >0){
//此时,可以认为内核空间的 binder_write_read bwr 和用户空间的 binder_write_read 等价
ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
}
...
}
}
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed){
uint32_t cmd;
void __user *buffer = (void __usr *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed; //此处认为刚开始处理,因此 ptr 就是开始
void __user *end = buffer + size;
while(ptr < end && thread->return_error = BR_OK){
//前面说过,这里的 buffer 内的数据是 cmd + content的形式存在的
get_user(cmd, (uint32_t __user *)ptr); //先获取 cmd
ptr += sizeof(uint32_t);
if(_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
//统计工作
binder_stats.bc[_IOC_NR(cmd))]++;
proc->stats.bc[_IOC_NR(cmd))]++;
thread->Stats.bc[_IOC_NR(cmd))]++;
swicth(cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr:
//BC_TRANSACTION 为 cmd 下,数据内容为 binder_transaction_data;
//同理,内核空间需要 copy_from_user( )才可以使用
copy_from_user(&tr, ptr, sizeof(tr));
ptr += sizeof(tr);
binder_transacaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
}
}
}
}
binder_transaction( )内部非常复杂,有必要单独拎出来
//binder_proc * proc 代表 SurfaceFlinger进程
//binder_thread *thread 代表SurfaceFlinger 进程中发起本次 IPC 的进程
//binder_transaction_data *tr 代表 SurfaceFlinger 传递给 service_manager 的参数
//int reply 在此处为 false
static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply){
struct binder_transaction *t;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end;
binder_size_t off_minl
struct binder_proc *target_proc;//目标进程,在这里代表 service_manager 进程
struct binder_thread *target_thread=NULL;//目标线程
struct binder_node *target_node =NULL; //目标 Binder 对应的 binder 实体
struct list_head *target_list; //目标 todo 任务队列
wait_queue_head_t *target_wait; //目标 wait 队列
struct binder_transaction *in_reply_to =NULL;
struct binder_transaction_log_entry *e; //日志相关,可以忽略
uint32_t return_error;
if(reply){
//这里是 false,分析
...
}else{
if(tr->target.handle){
//在本例中,target.handle = 0,不进入
...
}else{
//在 service_manager 进行 setContextManager的时候创建
target_node = binder_contet_mgr_node;
}
//从 target_node 找到目标进程
target_proc = target_node->proc;
...
//一些额外的校验,还有 from_parent 和 to_parent 的依赖判断
}
//指定了线程,则使用指定线程的 todo 和 wait,否则使用目标进程的 todo 和 wait
if(target_thread){
//如果指定了线程
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
}else{
//未指定目标线程
target_list = &target_proc->todo;
target_wait = &target_proc_wait;
}
//为 binder_transaction 分配内存,表示一个事务
t = kzalloc(sizeof(*t), GFP_KERNEL);
binder_stats_created(BINDER_STAT_TRANSACTION);
//为 binder_work 分配内存,表示一个待处理的工作项
tcomplect = kzalloc(sizeof(*tcomplete), GFP_KENER);
binder_stats_create(BINDER_START_TRANSACTION_COMPLETE);
if(!reply &!(tr->falsg & TF_ONE_WAY))
t->from = thread;
else
t->from = NULL;
t->send_euid = proc->tsk->cred->euid;
t->to_proc = target_proc;//service_manager进程
t->to_thread = target_thread;
t->code = tr->code;//ADD_SERVICE
t->flags - tr->flags;
t->priority = task_nice(current);
//从 target_proc 中的 buffer 中选取合适的内存块
t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr_offset_size, !reply &&(t->falses & TF_ONE_WAY));
t->buffer->allow_user_free = 0;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
if(target_node)
//增加强引用计数
binder_inc_node(target_node, 1, 0, NULL);
//--开始分析传输的数据中的 IBinder 对象
//如果是 binder 实体,在红黑树添加节点
//我们知道,binder 对象在 data 后面
offp = (binder_size_t *)(t->buffer-data + ALIGN(tr->data_size, sizeof(void *)));uintptr_t
copy_from_user(t->buffer->data, (const void __user *) tr->data.ptr.buffer, tr->data_size));
copy_from_user(offp, (const void __user *)(uintptr_t)tr->data.ptr.offsets, tr->offsets_size)
//此时 offp 边是传输的 IBinder对象首,off_end 是传输的 Ibinder 对象未
off_end = (void *) offp + tr->offsets_size;
off_min = 0
for(; off < off_end; offp++){
//遍历处理传输的 IBinder 对象,这里传输的对象的 SurfaceFlinger 的 Binder 实体
fp = (struct flag_binder_object *)(t->buffer->data + *offp);
off_min = *off +sizeof(struct flat_binder_object);
switch(fp->type){
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER:{
//只分析此分支
struct binder_ref *ref;
//查看当前进程是否已经有改 Binder 实体的 binder_node结构,当然是从进程的 proc->nodes 红黑树查询
struct binder_node *node = binder_get_node(proc, fp->binder);
if(node == NULL){
//表示该 SurfaceFlinger Binder 实体是第一次穿越 Binder 驱动,则创建 binder_node 对应 SurfaceFlinger
node = binder_new_node(proc, fp->binder, fp->cookie);
node -> min_priority = fp>flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
//为目标进程创建一个 Binder 实体对应的 Binder 引用 binder_ref,并且保存到目标进程的管理 binder_ref 的红黑树中(如果目标进程没有改 Binder 实体对应的 Binder引用)
ref = binder_get_ref_for_node(target_proc, node);
//传输给目标进程的时候传输的是代理而非实体
if(fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;
}
}
}
}
t->work.type = BINDER_WORK_TRANSACTION;
//将该事务插入到 target_list,即 Todo 队列
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete-entry, &thread->todo);
if(target_wait)
wake_up_interruptible(target_wait);
return;
}
- 通过 defaultManagerService( )获得 service_manager 在本地的代理 BpServiceManager(BpBinder(0))
- 打包参数到 Parcel,其中 IBinder 对象封装为 binder_flat_object 对象
- 通过 IPCThreadState 与 Binder 驱动通信
- 将 Parcel 中的参数转到 binder_transaction_data中,在其中写入 Parce 的数据大小,数据内存地址,IBinder 对象大小,IBinder 对象偏移。
- 然后将 binder_transaction_data 写入 IPCThreadState 的 Parcel mOut中,cmd 为 BC_TRANSACTION 表示此次是希望 Binder 驱动转发请求。此时这个 mOut 在内存分布上是:
Code = BC_TRANSACTION | Content of Code = binder_transaction_data |
---|
- 将 mOut 中的数据内存地址,即 code+content 保存到 binder_write_data。随后 ioctl( )与 Binder Driver 通信。ioctl( )层的 cmd 为 BINDER_WRITE_READ
上面的通讯过程有一种网络分层的感觉。在 SurfaceFlinger 和 service_manager 的服务层的 code 就是希望调用的方法代码:ADD_SERVICE。在 IPCThread 层代码是 BC_TRANSACTION/BR_TRANSACTION/BC_REPLY/BR_REPLY。在 Binder 驱动层的 cmd 就是 BINDER_WRITE_READ/BINDER_SET_CONTEXT_MGR等。
SurfaceFlinger/service_manager 层用 Parce 封装数据写入该层的 cmd。在 IPCThread 层用 binder_transaction_data 封装 Parcel 数据,同时写入该层的 cmd。在请求 Binder 驱动时,将cmd 与binder_transaction_data 与用 binder_write_read 封装
网友评论