Binder IPC机制
BpBinder是Native层的Binder代理,最后会由javaObjectForIBinder转化为Java层的BinderProxy,其构造函数:
/* \Android4.4\frameworks\native\libs\binder\BpBinder.cpp*/
BpBinder::BpBinder(int32_t handle) : mHandle(handle)à如果是ServiceManager,handle为0 , mAlive(1) , mObitsSent(0) , mObituaries(NULL) { ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK); IPCThreadState::self()->incWeakHandle(handle); } |
在/* \Android4.4\frameworks\native\libs\binder\BpBinder.h*/中有如下定义:
class BpBinder : public IBinder
BpBinder继承自IBinder,而
/* \Android4.4\frameworks\native\include\binder\IBinder.h*/中
class IBinder : public virtual RefBase |
可见BpBinder所使用的引用计数基类是RefBase。
在RefBase中,可以通过extendObjectLifetime来设置lifetime,有三种lifetime:
default(0),强引用和弱引用的默认行为,不管弱应用计数的值为多少,只要强引用计数的值为0,就释放对象
OBJECT_LIFETIME_WEAK,在这种状态下,如果强引用为0时,对象不会被释放,只有在弱引用计数为0的情况下,对象才会被释放
OBJECT_LIFETIME_WEAK | OBJECT_LIFETIME_FOREVER,在这种状态下,对象永不会释放
进入到IPCThreadState的分析:
/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/
static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;à 静态初始化互斥锁 static bool gHaveTLS = false;à初始值为false static pthread_key_t gTLS = 0; static bool gShutdown = false; IPCThreadState* IPCThreadState::self() { if (gHaveTLS) { restart: const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; return new IPCThreadState; }
if (gShutdown) return NULL;
pthread_mutex_lock(&gTLSMutex); if (!gHaveTLS) { if (pthread_key_create(&gTLS, threadDestructor) != 0) { pthread_mutex_unlock(&gTLSMutex); return NULL; } gHaveTLS = true; } pthread_mutex_unlock(&gTLSMutex); goto restart; } |
同一进程中的全局变量是可以在多个线程中访问到的,但线程中访问这些变量需要用到同步机制,在一定程度上降低了执行效率,有些变量只希望在本线程中是全局的,TLS(Thead Local Storage)保证某个变量仅在自己线程内访问有效,而其他线程中得到的是这个变量的独立复本。
在self函数中,当第一次被调用时,gHaveTLS为false,因此不会进入第一个if判断中,也不会创建IPCThreadState,但会进入第二个if判断启动TLS,然后返回restart处新建一个IPCThreadState。当以后再被调用,gHaveTLS为true:如果本线程已经创建过IPCThreadState,那么pthread_getspecific不为空;否则返回一个新建的IPCThreadState。从而有效保证了线程单实例的目的。
/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/
IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()),àProcessState整个进程只有一个 mMyThreadId(androidGetTid()),à当前线程id mStrictModePolicy(0), mLastTransactionBinderFlags(0) { pthread_setspecific(gTLS, this); clearCaller(); mIn.setDataCapacity(256);àmIn是个Parcel,用于接收Binder发过来的数据,最大容量为256 mOut.setDataCapacity(256);àmOut也是个Parcel,用于存储发给Binder的数据,最大容量256 } |
在BpBinder构造函数中,调用了IPCThreadState的incWeakHandle用于增加Binder Service的弱引用计数值,实际上是向Binder驱动发送了一个BC_INCREFS命令。
/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/
void IPCThreadState::incWeakHandle(int32_t handle) { LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle); mOut.writeInt32(BC_INCREFS); mOut.writeInt32(handle); } |
还有decWeakHandle、incStrongHandle、decStrongHandle与Binder协议中的指令对应。
IPCThreadState负责与Binder驱动进行具体的命令交互,ProcessState负责打开Binder节点并做mmap。
IPCThreadState中的transact函数是非常重要的。前面一直以ServiceManager中的getService()方法来追踪代码,流程如下:
getService@ServiceManagerProxyàtransact@BinderProxyàtransact@BpBinderàtransact@IPCThreadState
/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/
status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { … } |
针对getService,transact函数参数如下:
handle为0
code为GET_SERVICE_TRANSACTION
data为一个Parcel包含要查找的服务名
flag为0
/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/
status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { status_t err = data.errorCheck();à检查data是否有效
flags |= TF_ACCEPT_FDS;à有四种flag,分别为: enum transaction_flags { TF_ONE_WAY = 0x01,表示当前业务为异步 TF_ROOT_OBJECT = 0x04,所包含的内容是根对象 TF_STATUS_CODE = 0x08,所包含内容是32bit状态值 TF_ACCEPT_FDS = 0x10,容许回复中包含文件描述符 }; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand " << handle << " / code " << TypeCode(code) << ": " << indent << data << dedent << endl; }
if (err == NO_ERROR) { LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(), (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY"); err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);à writeTransactionData函数整理data,打包为Binder驱动协议规定格式,并把结果写在mout中 }
if (err != NO_ERROR) { if (reply) reply->setError(err); return (mLastError = err); }
if ((flags & TF_ONE_WAY) == 0) { #if 0 if (code == 4) { // relayout ALOGI(">>>>>> CALLING transaction 4"); } else { ALOGI(">>>>>> CALLING transaction %d", code); } #endif if (reply) { err = waitForResponse(reply);à waitForResponse函数要实现三个功能:
} else { Parcel fakeReply; err = waitForResponse(&fakeReply); } #if 0 if (code == 4) { // relayout ALOGI("<<<<<< RETURNING transaction 4"); } else { ALOGI("<<<<<< RETURNING transaction %d", code); } #endif
IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand " << handle << ": "; if (reply) alog << indent << *reply << dedent << endl; else alog << "(none requested)" << endl; } } else { err = waitForResponse(NULL, NULL); }
return err;} |
/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { int32_t cmd; int32_t err;
while (1) { if ((err=talkWithDriver()) < NO_ERROR) break; err = mIn.errorCheck(); if (err < NO_ERROR) break; if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32(); … } |
由此可见IPCThreadState中与Binder驱动真正进行通信的就在talkWithDriver中。
/* \Android4.4\frameworks\native\libs\binder\IPCThreadState.cpp*/
status_t IPCThreadState::talkWithDriver(bool doReceive) { if (mProcess->mDriverFD <= 0) { return -EBADF; } … do { IF_LOG_COMMANDS() { alog << "About to read/write, write size = " << mOut.dataSize() << endl; } #if defined(HAVE_ANDROID_OS) if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)à写入指令 err = NO_ERROR; else err = -errno; #else err = INVALID_OPERATION; #endif … |
通过ioctl来与Binder驱动进行交互,再次分析Binder驱动部分的代码:
/* \linux-3.5\drivers\staging\android\binder.c*/
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; struct binder_proc *proc = filp->private_data; à从filp中取出proc变量,即binder_open中动态创建的实例 struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd);à命令的大小 void __user *ubuf = (void __user *)arg;
/*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
trace_binder_ioctl(cmd, arg);à注释已解释,打印相关信息
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) goto err_unlocked;
(此处中断一下,解析wait_event_interruptible函数)
|
Binder的阻塞(或同步操作)就是让调用者进程暂时挂起,直到目标进程返回结果后,Binder再唤醒等待的进程,就是通过wait_event_interruptible完成的。
wait_event_interruptible首先将当前进程的状态设置成TASK_INTERRUPTIBLE,即可中断挂起状态,然后进入schedule调度,由于进程已不是处于可运行状态,所以将不再分配CPU时间,直到被唤醒,醒来后先检查condition是否满足,否则再次中断挂起。
/* \linux-3.5\drivers\staging\android\binder.c*/
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { (…) binder_lock(__func__); thread = binder_get_thread(proc);à binder_get_thread首先想proc中的threads链表查询是否已经添加了当前线程节点,如果没有则插入一个表示当前线程的新节点。threads链表中是按照pid大小排序的,加快了查询速度 if (thread == NULL) { ret = -ENOMEM; goto err; }
switch (cmd) { case BINDER_WRITE_READ: {à读写操作,可以用此向binder中读写数据 struct binder_write_read bwr; if (size != sizeof(struct binder_write_read)) {à判断buff大小是否合适 ret = -EINVAL; goto err; } if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {à从用户空间复制数据 ret = -EFAULT; goto err; } binder_debug(BINDER_DEBUG_READ_WRITE, "binder: %d:%d write %ld at %08lx, read %ld at %08lx\n", proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer);
if (bwr.write_size > 0) {à有数据需要写 ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); trace_binder_write_done(ret); if (ret < 0) {à成功返回0,负数表示有错 bwr.read_consumed = 0;à读取的数据大小为0 if (copy_to_user(ubuf, &bwr, sizeof(bwr)))à复制数据到用户空间 ret = -EFAULT; goto err; } } if (bwr.read_size > 0) {à有数据需要读 ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);à读取用户需要的数据 trace_binder_read_done(ret); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); if (ret < 0) { if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT; goto err; } } binder_debug(BINDER_DEBUG_READ_WRITE, "binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n", proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size); if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto err; } break; } (后面略…)
}
|
由此可见,Binder驱动主要起到中间人的作用,真正处理请求还是Binder Client和Binder Server通信双方。
/* \linux-3.5\drivers\staging\android\binder.c*/
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
针对getService()场景,主要参数如下:
proc:调用者的进程
thread:调用者线程
buffer:即bwr.write_buffer = (long unsigned int)mOut.data();因而就是writeTransactionData中对mOut写入的数据,主要包含两部分
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
cmd就是BC_TRANSACTION,tr是一个binder_transcation_data数据结构的变量
size:即bwr.write_size
consumed:即bwr.write_consumed
/* \linux-3.5\drivers\staging\android\binder.c*/
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed) { … case BC_TRANSACTION: case BC_REPLY: { struct binder_transaction_data tr;
if (copy_from_user(&tr, ptr, sizeof(tr)))à从用户空间取得tr结构 return -EFAULT; ptr += sizeof(tr); binder_transaction(proc, thread, &tr, cmd == BC_REPLY);à具体执行指令 break; } … } |
/* \linux-3.5\drivers\staging\android\binder.c*/
static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply) { struct binder_transaction *t;à表示一个transaction操作 struct binder_work *tcomplete;à表示一个未完的操作。因为一个transaction通常涉及两个进程A和B,当A向B发送请求后,B需要一段时间来执行;此时相对于A就是一个未完的操作,直到B返回结果后,Binder驱动才会再次启动A来继续执行。 size_t *offp, *off_end; struct binder_proc *target_proc;à目标进程 struct binder_thread *target_thread = NULL;à目标线程 struct binder_node *target_node = NULL; struct list_head *target_list; wait_queue_head_t *target_wait; struct binder_transaction *in_reply_to = NULL; struct binder_transaction_log_entry *e; uint32_t return_error; … if (reply) { …àBC_REPLY指令代码省略 } else {à针对BC_TRANSACTION指令代码 if (tr-> target.handle) {à获取目标对象所对应的target_node struct binder_ref *ref; ref = binder_get_ref(proc, tr->target.handle); if (ref == NULL) { binder_user_error("binder: %d:%d got " "transaction to invalid handle\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_invalid_target_handle; } target_node = ref->node; } else {à如果target.handle为0,表示target为ServiceManager,可以直接使用binder_context_mgr_node这全局变量;否则调用binder_get_ref来查找是否存在一个符合handle要求的node target_node = binder_context_mgr_node; if (target_node == NULL) { return_error = BR_DEAD_REPLY; goto err_no_context_mgr_node; } } e->to_node = target_node->debug_id; target_proc = target_node->proc;à目标进程,找到target_proc if (target_proc == NULL) { return_error = BR_DEAD_REPLY; goto err_dead_binder; } if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { struct binder_transaction *tmp; tmp = thread->transaction_stack; if (tmp->to_thread != thread) { binder_user_error("binder: %d:%d got new " "transaction with bad transaction stack" ", transaction %d has target %d:%d\n", proc->pid, thread->pid, tmp->debug_id, tmp->to_proc ? tmp->to_proc->pid : 0, tmp->to_thread ? tmp->to_thread->pid : 0); return_error = BR_FAILED_REPLY; goto err_bad_call_stack; } while (tmp) { if (tmp->from && tmp->from->proc == target_proc) target_thread = tmp->from;à找到target_thread tmp = tmp->from_parent; } } } if (target_thread) {à得到target_list和target_wait分别表示todo和towait e->to_thread = target_thread->pid; target_list = &target_thread->todo; target_wait = &target_thread->wait; } else { target_list = &target_proc->todo; target_wait = &target_proc->wait; } e->to_proc = target_proc->pid;
/* TODO: reuse incoming transaction for reply */ t = kzalloc(sizeof(*t), GFP_KERNEL);à生成一个binder_transaction变量(即t)用于描述本次要进行的transaction(最后将其加入到target_thread->todo中)。这样当目标对象被唤醒时,它可以从这个队列中取出需要做的工作。 if (t == NULL) { return_error = BR_FAILED_REPLY; goto err_alloc_t_failed; } binder_stats_created(BINDER_STAT_TRANSACTION);
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);à生成一个binder_work变量(即tcomplete)用于说明当前调用者线程有一个未完成的transaction … if (!reply && !(tr->flags & TF_ONE_WAY))à以下填写binder_transaction数据 t->from = thread; else t->from = NULL; t->sender_euid = proc->tsk->cred->euid; t->to_proc = target_proc; t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; t->priority = task_nice(current); t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY)); if (t->buffer == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_alloc_buf_failed; } t->buffer->allow_user_free = 0; t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; if (target_node) binder_inc_node(target_node, 1, 0, NULL);
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));à申请到t->buffer内存后,从用户空间把数据复制过来。因为t->buffer所指向的内存空间和目标对象对象空间是共享的,所以只需复制一次就把数据从Binder Client复制到Binder Server中了
if (copy_from_user(t->buffer->data, tr->dataNaNr.buffer, tr->data_size)) { binder_user_error("binder: %d:%d got transaction with invalid " "data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } if (copy_from_user(offp, tr->dataNaNr.offsets, tr->offsets_size)) { binder_user_error("binder: %d:%d got transaction with invalid " "offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { binder_user_error("binder: %d:%d got transaction with " "invalid offsets size, %zd\n", proc->pid, thread->pid, tr->offsets_size); return_error = BR_FAILED_REPLY; goto err_bad_offset; } off_end = (void *)offp + tr->offsets_size;
for (; offp < off_end; offp++) { à很长的一个for循环,用来处理数据中的binder_object对象 } … t->work.type = BINDER_WORK_TRANSACTION; list_add_tail(&t->work.entry, target_list); tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; list_add_tail(&tcomplete->entry, &thread->todo); if (target_wait)à前面提到t最终会加入到对方todo队列中,tcomplete被加入到调用者自己的todo队列中,然后唤醒目标对象。 wake_up_interruptible(target_wait); return; … |