Android Binder驱动分析三 addservice源码分析
接着上网我们分析了如下的代码:
- 将事务添加到
servicemanager
,然后将其唤醒 - 添加一个
binder_work
事务给mediaplayserice
我们这里分析mediaplayservice
提交事务后会做什么
//drivers/staging/android/binder.c
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
//从用户空间的arg的地址处拷贝到内核
//ubuf = arg
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
//因为有数据传入所以不为0
if (bwr.write_size > 0) {
// 1. 将事务添加到`servicemanager`,然后将其唤醒
// 2. 添加一个`binder_work`事务给`mediaplayserice`
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
}
//这里不为空,表示想接收binder驱动的信息
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
//如果还有未处理的任务唤醒线程,但是这里没有没有其他事务所以不会进入下面的代码
if (!binder_worklist_empty_ilocked(&proc->todo))
binder_wakeup_proc_ilocked(proc);
goto out;
}
}
//binder驱动将修改过后的bwr传回用户空间(mediaplayservice)
//可见内存共享仅针对于服务端来说,客户端的读写还是要拷贝滴
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
//ret = binder_thread_read(proc, thread, bwr.read_buffer,
// bwr.read_size,
// &bwr.read_consumed,
// filp->f_flags & O_NONBLOCK);
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
//这里是0所以放入BR_NOOP
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
//失败处理
return -EFAULT;
//指针偏移
ptr += sizeof(uint32_t);
}
while (1) {
uint32_t cmd;
struct binder_transaction_data_secctx tr;
struct binder_transaction_data *trd = &tr.transaction_data;
struct binder_work *w = NULL;
struct list_head *list = NULL;
struct binder_transaction *t = NULL;
struct binder_thread *t_from;
size_t trsize = sizeof(*trd);
//一个程序的待处理任务会在线程或进程todo列表中
//这里是取出列表对象
if (!binder_worklist_empty_ilocked(&thread->todo))
list = &thread->todo;
else if (!binder_worklist_empty_ilocked(&proc->todo) &&
wait_for_proc_work)
list = &proc->todo;
//是否还有数据要读取
if (end - ptr < sizeof(tr) + 4) {
break;
}
//取出列表对象,这里就是上篇文章的的内容tcomplete
w = binder_dequeue_work_head_ilocked(list);
switch (w->type) {
case BINDER_WORK_TRANSACTION_COMPLETE: {
cmd = BR_TRANSACTION_COMPLETE;
//放入一个命令BR_TRANSACTION_COMPLETE
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
//指针后移
ptr += sizeof(uint32_t);
kfree(w);
} break;
}
}
done:
//注意consume变成写入的数值大小
//比如buffer是100 写入64
//ptr初始值=100 写入64为164.和原始地址先减去可以到写入的字节大小
*consumed = ptr - buffer;
//这里用于让用户空间新生成一个线程,这里我们先无视,就当没有写入
if (proc->requested_threads == 0 &&
list_empty(&thread->proc->waiting_threads) &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
proc->requested_threads++;
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
}
return 0;
}
可见binder驱动给mediaplayservice
提交了两个主要命令BR_NOOP
和BR_TRANSACTION_COMPLETE
就返回用户空间
也就是以下代码:
// frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive=true)
{
//略
do {
//将我们的内容发送给binder驱动,这时从驱动返回
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
} while (err == -EINTR);
//binder驱动会修改bwr
if (err >= NO_ERROR) {
//运行到这时候binder驱动会消费我们传入bwr.write_buffer,具体消费了多个字节就是write_consumed
if (bwr.write_consumed > 0) {
//将这个重置后继续下次使用
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
//binder驱动会顺带返回信息,返回的信息的大小是read_consumed
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
没有太特殊继续向上层函数返回
以下函数首先读取BR_NOOP
后再进入循环调用talkWithDriver()
后在读取信息,等返回后在处理BR_TRANSACTION_COMPLETE
// frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
//返回到这继续向下走
if ((err=talkWithDriver()) < NO_ERROR) break;
//如果没有返回信息那么继续循环读取binder驱动
if (mIn.dataAvail() == 0) continue;
//读取binder驱动返回的前4字节,这四个字节表示binder驱动是什么消息类型
cmd = (uint32_t)mIn.readInt32();
//根据返回的binder返回的命令做出操作
//首先读取BR_NOOP
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
//这里reply不为空,acquireResult为NULL
//所以!reply && !acquireResult 为false,因此继续循环进入talkWithDriver等
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY:
//..略
case BR_FAILED_REPLY:
//..略
case BR_ACQUIRE_RESULT:
//..略
case BR_REPLY:
//..略
default:
//BR_NOOP在内部什么都不做,继续循环进入talkWithDriver
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
}
}
return err;
}
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch (cmd) {
//略
case BR_NOOP:
break;
}
return result;
}
第一次读取BR_NOOP
没有太多特殊的情况于是乎继续进入talkWithDriver()
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
//因为dataPosition还有4字节没有读取,
//假设dataSize为8字节,分别存放`BR_NOOP` 和`BR_TRANSACTION_COMPLETE`
//读取`BR_NOOP`后dataPosition为4
//因此这里为false
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
//outAvail 自然为0
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
//needRead false
//doReceive true
//这里走到false
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
// bwr.write_size == 0为true
// bwr.read_size == 0 为true
// 那么整个表达式为true。因此直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} while (err == -EINTR);
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
talkWithDriver()
返回继续读取下一个命令BR_TRANSACTION_COMPLETE
这里由于这个命令也没有特殊的地方,所以会重新再次进入talkWithDriver
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
//数据读取完`BR_TRANSACTION_COMPLETE` dataPosition会等于dataSize
//因此这里为true
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
//outAvail dataSize
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
//needRead true
//doReceive true
//这里走到true
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
//这里直接为false
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
//这里在进入binder驱动中
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} while (err == -EINTR);
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
最后再次进入binder
驱动的binder_thread_read
函数.
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
//这里返回false. binder_available_for_proc_work_ilocked如果有事务就返回true,没有就返回false
wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
//这里为
if (non_block) {
//;略
} else {
//阻塞由于wait_for_proc_work为fakse
//所以mediaplayservice被阻塞在这
ret = binder_wait_for_work(thread, wait_for_proc_work);
}
//略
return 0;
}