上一篇《我理解的Binder通信机制(一)——Binder通信通道的建立》【2】(标注一下,本文后面的篇幅中会经常提到上一篇的内容,这里标注为【2】)中介绍了Binder通道的建立过程。通道建立以后,就可以在其中进行数据传输了,所以,这一篇接着说基于这个通道的数据发送与数据获取过程,这里说的数据发送是指server进程(作为client)向servermanager进程(作为server)注册系统服务;数据获取是指client进程(作为client)向servermanager进程(作为server)获取系统服务,属于系统级的数据通信。
0 前言
刚开始研究Binder机制的时候,主要看一些关于framework的书籍。其中,讲解到Binder机制时,都是以具体的系统服务的注册及获取过程来说明。心中一直存在一个疑问:为什么要以系统服务来讲解Binder机制,服务和Binder之间有什么关系吗?直到看到addService方法中变量service的类型IBinder,才反应过来,其实,系统服务本身就是Binder类型,当然可以以系统注册、获取过程来作为切入点研究Binder通信机制。OK,闲话扯完,进入主题。
一、数据发送之注册服务
1 进入内核前的处理
还是以具体的系统服务来研究这一过程的细节。先来看一下addService方法。
/**
* @param name 服务名称
* @param service 具体的服务
*/
@UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
try {
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
getIServiceManager方法还是一个IPC的过程。整个Binder机制是由上到下,由Java到Native,层层调用,本文略去Java层的调用细节,直接定位Native层BpServiceManager的addService方法
class IServiceManager.cpp::BpServiceManager
------------------
virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated) {
//Parcel是数据通信包
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
//remote()指向的是BpBinder对象
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
1.1 Parcel#writeStrongBinder
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
1.1.1 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) {
//本地Binder不为空
IBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0;
obj.handle = handle;
obj.cookie = 0;
} else { //进入该分支
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
...
}
return finish_flatten_binder(binder, obj, out);
}
flatten_binder函数的作用主要是将IBinder类型的对象转化为flat_binder_object类型的对象。所以,binder是以flat_binder_object的形式在进程间传递。从函数名称上可以推断出来,该函数将binder flat了一下。这是个什么效果呢?可以想象一下,在球场的大叔大妈捡到易拉罐的第一个动作是什么?没错,啪,给一脚,踩扁,就是flat了一下。易拉罐还是易拉罐,只是外形发生了变化,放到binder这里也是一样的道理。
1.2 BpBinder::transact
在transact之前,先看一下remote()函数,
class BpRefBase : public virtual RefBase
{
protected:
explicit BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
...
inline IBinder* remote() { return mRemote; }
inline IBinder* remote() const { return mRemote; }
private:
IBinder* const mRemote;
...
};
【2】最后的4.4.2小节可知,BpRefBase中mRemote变量存储的是BpBinder对象。
remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
这样就相当于
new BpBinder->transact(ADD_SERVICE_TRANSACTION, data, &reply);
来看一下该方法
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
1.2.1 IPCThreadState::self
IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS.load(std::memory_order_acquire)) {
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
//初始IPCThreadState
return new IPCThreadState;
}
// Racey, heuristic test for simultaneous shutdown.
if (gShutdown.load(std::memory_order_relaxed)) {
return nullptr;
}
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS.load(std::memory_order_relaxed)) {
//创建线程的TLS
int key_create_value = pthread_key_create(&gTLS, threadDestructor);
if (key_create_value != 0) {
pthread_mutex_unlock(&gTLSMutex);
return nullptr;
}
gHaveTLS.store(true, std::memory_order_release);
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}
IPCThreadState构造方法中的逻辑有些不懂,直接引用gityuan.com/2015/11/14/…的一段话。
TLS是指Thread local storage(线程本地储存空间),每个线程都拥有自己的TLS,并且是私有空间,线程之间不会共享。通过pthread_getspecific / pthread_setspecific函数可以获取、设置这些空间中的内容。从线程本地存储空间中获得保存在其中的IPCThreadState对象。
1.2.2 IPCThreadState::transact
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err;
flags |= TF_ACCEPT_FDS;
//此时,code为ADD_SERVICE_TRANSACTION
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
...
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
...
} else {
err = waitForResponse(nullptr, nullptr);
}
return err;
}
该方法中主要做了两部分工作:writeTransactionData、waitForResponse。从方法名也可以知道,writeTransactionData在写入数据,继续往下看,
1.3 writeTransactionData
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;
//填充binder_transaction_data
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
//检查数据
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
//填充binder_transaction_data
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
//在binder_transaction_data数据包中存储binder(实体或引用)。
//可能存多个binder,所以,offsets_size表示binder数组的大小
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
//binder在binder_transaction_data数据包中的偏移量
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
//cmd为BC_TRANSACTION,写入parcel mOut中
mOut.writeInt32(cmd);
//数据包写入parcel mOut中
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
writeTransactionData方法也很好理解,简单的说,就是在填充传输的数据包binder_transaction_data。其中,可以包含数据、binder,相当于在flat_binder_object外面又包了一层。参数offsets_size和data.ptr.offsets标识出了binder(实体或引用)在数据包中的大小、位置,这样在进程间传输中,目标进程可以根据这两个变量,从中提取出binder,完成binder的进程间传递。最后,把Binder命令BC_TRANSACTION和binder_transaction_data结构体写入到parcel类型的变量mOut中。这里注意一下,数据包写入mOut后会在被用到时取出来。
1.4 waitForResponse
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_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 = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
...
case BR_DEAD_REPLY:
...
case BR_FAILED_REPLY:
...
case BR_ACQUIRE_RESULT:
...
case BR_REPLY:
...
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
...
return err;
}
waitForResponse方法刚开始就进入一个while的无限循环,其中,第一个if判断talkWithDriver,
1.5 talkWithDriver
status_t IPCThreadState::talkWithDriver(bool doReceive) {
...
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
/* 要么读,要么写 */
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
//调用栈 IPCThreadState::transact -> writeTransactionData
//还记得在writeTransactionData函数中binder_transaction_data写入了mOut吗?
//将mOut.data封装进binder_write_read
bwr.write_buffer = (uintptr_t) mOut.data();
//需要读数据
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t) mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
...
// 既不用读,也不用写,直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
//调用ioctl函数同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);
return err;
}
还记得在1.3小节writeTransactionData方法中binder_transaction_data写入了mOut中吗?talkWithDriver方法中将mOut.data封装进binder_write_read中,然后调用ioctl函数同binder驱动进行数据交互。
截至目前,我们看一下binder在从应用层到binder驱动传输过程中发生了哪些变化:IBinder -> flat_binder_object -> binder_transaction_data -> parcel.mData -> binder_write_read。
2 调用ioctl函数进入Binder驱动
Binder驱动和应用程序之间定义了一套接口协议,主要功能由ioctl()接口实现,不提供read(),write()接口,因为ioctl()灵活方便,且能够一次调用实现先写后读以满足同步交互,而不必分别调用write()和read()。
ioctl函数调用进入内核,调用binder_ioctl,
2.1 binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
...
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break
...
}
ret = 0;
...
return ret;
}
binder_ioctl走分支BINDER_WRITE_READ,调用binder_ioctl_write_read
2.2 binder_ioctl_write_read
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread) {
int ret = 0;
//当前情形下,binder_proc表示smgr进程
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void
__user
* ubuf = (void
__user *)arg;
struct binder_write_read bwr;
...
//从用户空间拷贝数据到内核缓冲区
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
//bwr.write_size大于0表示向内核缓冲区写入数据
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
//bwr.read_size大于0表示从内核缓冲区读取数据
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);
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 out;
}
}
// 从内核缓冲区拷贝数据到用户空间
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
先来看一下copy_from_user和copy_to_user函数
2.2.1 copy_from_user & copy_to_user
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
该函数是从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0。函数参数如下,
- void *to 内核地址
- const void __user *from 用户空间地址
- unsigned long n 数据大小
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
该函数是从内核空间拷贝数据到用户空间,失败返回没有拷贝成功的数据字节数,成功返回0。函数参数如下,
- void __user *to 用户空间地址
- const void *from 内核地址
- long n 数据大小
binder_ioctl_wrtie_read函数会从用户空间拷贝数据到内核,数据存放在bwr,然后根据bwr中的write_size、read_size来判断向内核缓冲区写入数据,还是从内核缓冲区中读取数据。当前情形下,向内核写入数据,所以调用binder_thread_write。
2.3 binder_thread_write
static 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 __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
//拷贝用户空间的cmd命令,此时为BC_TRANSACTION
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
//拷贝用户空间的binder_transaction_data
if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
...
}
*consumed = ptr - buffer;
}
return 0;
}
2.4 binder_transaction
/**
*
* @param proc binder所在的进程
* @param thread binder所在线程
* @param tr binder_transaction_data 数据包
* @param reply 是否需要reply
*/
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_min;
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) {
...
} else {
//tr->target.handle非0
if (tr->target.handle) {
...
}
//当前在注册服务,target.handle为0。
//进入else分支
else {
//目标binder为servicemanager实体
target_node = binder_context_mgr_node;
...
}
//目标为servicemanager进程
target_proc = target_node->proc;
...
}
if (target_thread) {
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;
t = kzalloc(sizeof(*t), GFP_KERNEL);
...
//binder_work类型
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
...
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
else
t->from = NULL;
t->sender_euid = task_euid(proc->tsk);
t->to_proc = target_proc;
t->to_thread = target_thread;
t->code = tr->code; //code为ADD_SERVICE_TRANSACTION
t->flags = tr->flags;
t->priority = task_nice(current);
trace_binder_transaction(reply, t, target_node);
//从servicemanager进程中分配buffer
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
t->buffer->allow_user_free = 0;
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
trace_binder_transaction_alloc_buf(t->buffer);
if (target_node)
binder_inc_node(target_node, 1, 0, NULL);
offp = (binder_size_t * )(t->buffer->data +
ALIGN(tr->data_size, sizeof(void *)));
//拷贝用户空间的binder_transaction_data中ptr.buffer到内核
if (copy_from_user(t->buffer->data,(const void __user
*)(uintptr_t)
tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("%d:%d got transaction with invalid data ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
//goto err_copy_data_failed;
}
//拷贝用户空间的binder_transaction_data中ptr.offsets到内核
if (copy_from_user(offp,(const void __user
*)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size)) {
binder_user_error("%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(binder_size_t))) {
binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n",
proc->pid, thread->pid, (u64) tr->offsets_size);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
off_end = (void *) offp + tr->offsets_size;
off_min = 0;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
if (*offp > t->buffer->data_size - sizeof(*fp) ||
*offp < off_min ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(u32))) {
binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n",
proc->pid, thread->pid, (u64) * offp,
(u64) off_min,
(u64)(t->buffer->data_size -
sizeof(*fp)));
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
/* 解析数据binder_transaction_data中可能携带的binder,
* flat_binder_object是binder在进程间传输形式 */
fp = (struct flat_binder_object *) (t->buffer->data + *offp);
off_min = *offp + sizeof(struct flat_binder_object);
/*
*判断数据中的binder的类型
*/
switch (fp->type) {
//binder_node是binder实体在binder驱动中的存在形式
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
//binder驱动中维护的binder_node红黑树中是否包含该binder实体
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("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
proc->pid, thread->pid,
(u64) fp->binder, node->debug_id,
(u64) fp->cookie, (u64) node->cookie);
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
//查找该binder实体对应的binder引用
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;
//binder引用次数+1
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
trace_binder_transaction_node_to_ref(t, node, ref);
}
break;
//类型为binder引用
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
//维护binder引用对应的红黑树中查找该binder引用
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
if (ref == NULL) {
binder_user_error("%d:%d got transaction with invalid handle, %d\n",
proc->pid,
thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
//判断binder引用的对应实体所在的进程是否是目标进程,
//如果为binder所属的进程,则将flat_binder_object的类型设置为binder实体节点
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
else
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie;
//计数+1
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
trace_binder_transaction_ref_to_node(t, ref);
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> node %d u%016llx\n",
ref->debug_id, ref->desc, ref->node->debug_id,
(u64) ref->node->ptr);
}
//进程号不匹配,则还是使用binder引用
else {
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;
//binder引用计数+1
binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
trace_binder_transaction_ref_to_ref(t, ref, new_ref);
}
}
break;
case BINDER_TYPE_FD: {
...
default:
binder_user_error("%d:%d got transaction with invalid object type, %x\n",
proc->pid, thread->pid, fp->type);
return_error = BR_FAILED_REPLY;
goto err_bad_object_type;
}
}
if (reply) {
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
} else {
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo;
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
}
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)
wake_up_interruptible(target_wait);
return;
}
binder_transaction函数内容比较多,首要工作就是要确定目标进程的信息,诸如target_node、target_proc等。然后,在目标进程中分配缓冲区,用来接收传递的数据。注意到有copy_from_user函数的调用,将用户空间中与binder有关的offsets, offsets_size拷贝到内核中,为要添加的flat_binder_object做准备。根据flat_binder_object的类型来确定传递的binder是实体节点还是引用。最后,向servicemanager的binder_proc->todo添加BINDER_WORK_TRANSACTION事务。
2.4.1 binder_get_node
static struct binder_node *binder_get_node(struct binder_proc *proc,
binder_uintptr_t ptr)
{
struct rb_node *n = proc->nodes.rb_node;
struct binder_node *node;
//红黑树中查找ptr为索引的binder节点,找到返回;没找到返回NULL;
while (n) {
node = rb_entry(n, struct binder_node, rb_node);
if (ptr < node->ptr)
n = n->rb_left;
else if (ptr > node->ptr)
n = n->rb_right;
else
return node;
}
return NULL;
}
binder_get_node会从server进程中维护的binder_node类型的红黑树中查找以ptr为索引的binder节点,ptr为binder在用户空间的指针。如果没找到就创建一个新节点添加到树中。此时,会调用binder_new_node函数,
2.4.2 binder_new_node
static struct binder_node *binder_new_node(struct binder_proc *proc,
binder_uintptr_t ptr,
binder_uintptr_t cookie)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
//先在红黑树位置查找,找不到则创建
while (*p) {
parent = *p;
node = rb_entry(parent, struct binder_node, rb_node);
if (ptr < node->ptr)
p = &(*p)->rb_left;
else if (ptr > node->ptr)
p = &(*p)->rb_right;
else
return NULL;
}
//分配空间
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (node == NULL)
return NULL;
binder_stats_created(BINDER_STAT_NODE);
//将新建的node链接到红黑树
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
//node信息设置
node->debug_id = ++binder_last_id;
node->proc = proc;
node->ptr = ptr;
node->cookie = cookie;
node->work.type = BINDER_WORK_NODE;
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
return node;
}
2.4.3 binder_get_ref_for_node
//获取binder实体节点对应的binder引用
static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
struct binder_node *node)
{
struct rb_node *n;
struct rb_node **p = &proc->refs_by_node.rb_node;
struct rb_node *parent = NULL;
struct binder_ref *ref, *new_ref;
//在红黑树rb_node_node中查找binder_node对应的binder_ref
while (*p) {
parent = *p;
ref = rb_entry(parent, struct binder_ref, rb_node_node);
if (node < ref->node)
p = &(*p)->rb_left;
else if (node > ref->node)
p = &(*p)->rb_right;
else
return ref;
}
//为新创建的binder_ref分配空间
new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
if (new_ref == NULL)
return NULL;
//新建binder_ref
binder_stats_created(BINDER_STAT_REF);
new_ref->debug_id = ++binder_last_id;
new_ref->proc = proc;
new_ref->node = node;
//链接到rb_node_node红黑树中
rb_link_node(&new_ref->rb_node_node, parent, p);
rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
//新建的binder引用如果对应servicemanager,其desc变量为0,否则为1。
new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1;
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
ref = rb_entry(n, struct binder_ref, rb_node_desc);
if (ref->desc > new_ref->desc)
break;
new_ref->desc = ref->desc + 1;
}
p = &proc->refs_by_desc.rb_node;
//rb_node_desc同样是一个红黑树,
//以binder_ref的desc域为索引维护的一个binder_ref红黑树
while (*p) {
parent = *p;
ref = rb_entry(parent, struct binder_ref, rb_node_desc);
if (new_ref->desc < ref->desc)
p = &(*p)->rb_left;
else if (new_ref->desc > ref->desc)
p = &(*p)->rb_right;
else
BUG();
}
//链接到rb_node_desc红黑树中
rb_link_node(&new_ref->rb_node_desc, parent, p);
rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc);
if (node) {
hlist_add_head(&new_ref->node_entry, &node->refs);
}
return new_ref;
}
binder_get_ref_for_node函数主要工作就是获取binder实体节点对应的binder引用。研究其逻辑可以知道,进程中维护着两个红黑树 rb_node_node、rb_node_desc。两个都是维护着binder引用的红黑树,不同的是,rb_node_node是以binder节点在驱动中的地址为索引;rb_node_desc是以引用号(即结构的desc域)为索引。
binder_transaction正确执行后,我们接着看binder_thread_write的逻辑,之后跳出switch,binder_thread_write函数返回0,表示操作成功。binder_ioctl_write_read接到返回值后,就会将操作后的数据从内核拷贝回用户空间,并返回0。
binder_ioctl_write_read函数
// 从内核缓冲区拷贝数据到用户空间
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
上层函数talkWithDriver中,
do {
//调用ioctl函数同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);
ioctl函数返回值 == 0,err被赋值为NO_ERROR,接着返回err给上层调用函数。这样一次单向的数据传输完成,至于需不需要reply,看上层调用。
3 servicemanager处理IPC请求
在【2】中3.3小节中提到,servicemanager作为一个server进程,为了应对来自client进程的请求,servicemanager在binder_loop会进入一个无限循环等待处理client进程的IPC请求。但是进入无限循环中没有继续研究细节,现在来看一下。
在for循环中,调用ioctl函数与binder驱动交互,结果就是从binder驱动中读取IPC请求数据。当ioctl返回后,便通过binder_parse方法解析返回数据。binder驱动可以返回多种BR指令给servicemanager,其中BR_TRANSACTION指令用于注册和获取服务。
3.1 binder_parse
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func) {
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;
while (ptr < end) {
//读取BR命令
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
switch (cmd) {
...
case BR_TRANSACTION: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
if ((end - ptr) < sizeof(*txn)) {
ALOGE("parse: txn too small!\n");
return -1;
}
binder_dump_txn(txn);
if (func) {
unsigned rdata[256 / 4];
//binder驱动发送给当前进程的IPC数据
struct binder_io msg;
//要写入Binder驱动的IPC数据
struct binder_io reply;
int res;
//初始化IPC数据
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
//调用func处理BC_TRANSACTION指令,处理结果保存在reply中
res = func(bs, txn, &msg, &reply);
//oneway
if (txn->flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn->data.ptr.buffer);
}
//需要reply,将处理结果返回给binder驱动程序
else {
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
}
ptr += sizeof(*txn);
break;
}
...
default:
ALOGE("parse: OOPS %d\n", cmd);
return -1;
}
}
return r;
}
func实参由binder_loop传入,
binder_loop(bs, svcmgr_handler);
binder驱动发送给servicemanager的BR_TRANSACTION指令便由该函数处理,看一下
3.2 svcmgr_handler
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
struct svcinfo *si;
uint16_t *s;
size_t len;
uint32_t handle;
uint32_t strict_policy;
int allow_isolated;
uint32_t dumpsys_priority;
strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);
...
switch(txn->code) {
//获取service
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
//注册服务
case SVC_MGR_ADD_SERVICE:
//服务名称
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
dumpsys_priority = bio_get_uint32(msg);
if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, txn->sender_pid))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {
uint32_t n = bio_get_uint32(msg);
uint32_t req_dumpsys_priority = bio_get_uint32(msg);
if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",txn->sender_euid);
return -1;
}
si = svclist;
// walk through the list of services n times skipping services that do not support the requested priority
while (si) {
if (si->dumpsys_priority & req_dumpsys_priority) {
if (n == 0) break;
n--;
}
si = si->next;
}
if (si) {
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
default:
ALOGE("unknown code %d\n", txn->code);
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
在SVC_MGR_GET_SERVICE、SVC_MGR_ADD_SERVICE分支下分别调用do_find_service、do_add_service函数,这是在获取服务、注册服务过程中会调用的函数。这一部分研究服务注册,那就先看do_add_service
3.3 do_add_service
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
struct svcinfo *si;
if (!handle || (len == 0) || (len > 127))
return -1;
//是否有权限被注册为service
if (!svc_can_register(s, len, spid, uid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);
return -1;
}
//在servicelist中查找s是否已被注册
si = find_svc(s, len);
if (si) {
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
si->handle = handle;
}
//服务注册
else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
str8(s, len), handle, uid);
return -1;
}
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->dumpsys_priority = dumpsys_priority;
//系统服务以链表的形式保存
si->next = svclist;
svclist = si;
}
binder_acquire(bs, handle);
binder_link_to_death(bs, handle, &si->death);
return 0;
}
do_add_service函数的逻辑不难理解,值得注意的是,系统服务是以链表的形式保存。 顺便看一下do_find_service,
3.4 do_find_service
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
//从servicelist中查找s
struct svcinfo *si = find_svc(s, len);
...
return si->handle;
}
3.5 find_svc
struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
struct svcinfo *si;
for (si = svclist; si; si = si->next) {
if ((len == si->len) &&
!memcmp(s16, si->name, len * sizeof(uint16_t))) {
return si;
}
}
return NULL;
}
逻辑也比较简单,就不展开说了。
二、数据获取之系统服务获取
我们还是从IServiceManger::BpServiceManager的getService函数开始看起,
virtual sp<IBinder> getService(const String16& name) const{
static bool gSystemBootCompleted = false;
//检索已有服务
sp<IBinder> svc = checkService(name);
if (svc != nullptr) return svc;
const long timeout = uptimeMillis() + 5000;
...
const long sleepTime = gSystemBootCompleted ? 1000 : 100;
int n = 0;
//等待该服务启动5s
while (uptimeMillis() < timeout) {
n++;
usleep(1000*sleepTime);
sp<IBinder> svc = checkService(name);
if (svc != nullptr) return svc;
}
//该服务仍未启动,返回nullptr
return nullptr;
}
getService函数会先从已有服务中去检索要获取的服务,检索到直接返回,否则,会等待5s,这5s期间会不断去检索,检索到就返回。如果5s后,服务仍旧未启动,则返回nullptr。接下来重点就是checkService函数。
函数里面的内容就相对熟悉一些,下面我们不再对已在上面讲过的方法进行讲解,但还是列出调用顺序。
BpBinder::transact
IPCThreadState::self
IPCThreadState::transact
writeTransactionData
waitForResponse
talkWithDriver
ioctl
binder_ioctl
binder_ioctl_write_read
老实说,获取服务的过程中还有一些东西没理清,所以这里先搁置一下,等后续补充。
接下来,看一下parcel::readStrongBinder
1.1 readStrongBinder
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
readNullableStrongBinder(&val);
return val;
}
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
return unflattenBinder(val);
}
1.2 unflattenBinder
status_t Parcel::unflattenBinder(sp<IBinder>* out) const{
//从parcel中取出flat_binder_object,也就是binder,
//至于是binder实体还是binder引用,需要接着判断
const flat_binder_object* flat = readObject(false);
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER: {
sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
return finishUnflattenBinder(binder, out);
}
case BINDER_TYPE_HANDLE: {
sp<IBinder> binder =
ProcessState::self()->getStrongProxyForHandle(flat->handle);
return finishUnflattenBinder(binder, out);
}
}
}
return BAD_TYPE;
}
unflattenBinder对应上一篇的flattenBinder,还记得球场上大妈捡易拉罐的那个例子吗,unflattenBinder则是从parcel中提取flat_binder_object,也就是binder。然后,判断flat_binder_object是binder实体还是binder引用。现在,在以client进程的角度获取系统服务,而binder在client进程中的表述为binder引用,所以,进入BINDER_TYPE_HANDLE分支,调用getStrongProxyForHandle,这个函数在【2】中已经见过了,返回的是BpBinder的对象。ProcessState维护着一个元素类型为handle_entry的容器mHandleToObject。这样根据服务名称,获得了服务的代理对象,服务代理本来就继承了功能接口(IxxxInterface),调用相应了的函数即可,这样完成数据的跨进程通信。
三、再谈Binder通信模型
这一篇完结后,想了想还是把这个话题从上一篇放到这儿吧,也许更合适一些。截至目前,【1】中提到的Binder通信模型的四个组成部分:server进程、client进程、binder驱动、servicemanager进程都已悉数亮相。这时,我们再回过头来回味一下这个概念会不会有些更深一些的理解呢。包括【1】对binder在各部分中表述的总结,我会发现这就是一篇Binder通信机制纲领性的博文(请允许我再吹一波吧),作者的功力可见一斑。吾心向往之。
说明
这两篇的文章在方法调用的小标题标号时没有遵循严格的方法调用,比如1.1,1.2不是并列关系,而是调用与被调用关系,这块参考了gityuan博客中的写法,因为,如果按照严格的平行、调用关系去编号,方法调用栈可能会比较深,可能平行的编号不存在几个,都是诸如1.1.2.3这样的形式,甚至可能存在五、六级标题编号,所以,为了目录更好看,使用了以上的编号方法,特此说明。
Binder机制通信暂且告一段落,但是两篇内容不足以包含Binder的方方面面,很多细节我现在还没弄明白,所以这是一个需要长期复习再理解的过程。文章内容有误的地方欢迎指出,也欢迎评论,在探讨中共同进步。
参考资料
aosp.tuna.tsinghua.edu.cn/platform/fr…(git clone)
《Android的设计与实现 卷一》杨云君。
《深入理解Android 卷一》邓凡平。