Android Binder之旅

微信扫一扫,分享到朋友圈

Android Binder之旅

由于最近想换工作,于是就打开了Android 10的源码,将Binder通信又复习了一遍,以便面试时有备无患。

aidl

通常,Android应用在实现进程间通信都会使用到aidl,编写aidl文件之后,通过sync project会帮助我们生成对应的Stub与Proxy代码,通过实现Stub类就可以作为服务端的远程对象,然后通过Service的onBind方法将对象返回,而客户端通过相同aidl文件会生成的asInterface方法,然后将ServiceConnection的回调方法onServiceConnected的IBinder参数作为asInterface的参数会得到服务端远程对象的代理对象,也就是aidl生成类Proxy的对象。 注意 :如果是相同进程,通过asInterface得到的直接是Stub实现类的对象,也就是onBind返回的对象。

transact

通过Proxy对象我们就可以无感知的调用服务端远程对象的方法,而中间其实是经由IBinder的transact方法。

@Override public void setSurface(android.view.Surface surface) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((surface!=null)) {
_data.writeInt(1);
surface.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_setSurface, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
复制代码

而客户端对应的IBinder对象是后文会介绍到的BinderProxy frameworks/base/core/java/android/os/BinderProxy.java

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
...
try {
return transactNative(code, data, reply, flags);
} finally {
...
}
}
复制代码

最终会调用到transactNative的jni方法

frameworks/base/core/jni/android_util_Binder.cpp

static const JNINativeMethod gBinderProxyMethods[] = {
/* name, signature, funcPtr */
{"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},
{"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},
{"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
{"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
{"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
{"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"getNativeFinalizer",  "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
};
复制代码
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
Parcel* data = parcelForJavaObject(env, dataObj);
...
IBinder* target = getBPNativeData(env, obj)->mObject.get();
...
status_t err = target->transact(code, *data, reply, flags);
...
if (err == NO_ERROR) {
return JNI_TRUE;
} else if (err == UNKNOWN_TRANSACTION) {
return JNI_FALSE;
}
signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
return JNI_FALSE;
}
复制代码

其中getBPNativeData获取的是java对象BinderProxy的mNativeData属性,而该属性是在构造函数中通过构造参数赋值的,BinderProxy对象的由来将在后文中介绍,mNativeData中的mObject指向的是c++对象BpBinder

frameworks/native/libs/binder/BpBinder.cpp

status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
复制代码

IPCThreadState

说到IPCThreadState,就要提到App进程的创建,Android中App进程的创建都是通过Zygote进程fork创建出来的。子进程创建后,会调用ZygoteInit.nativeZygoteInit()

frameworks/base/core/jni/AndroidRuntime.cpp

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
复制代码

frameworks/base/cmds/app_process/app_main.cpp

virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.n");
proc->startThreadPool();
}
复制代码

此时会引入另外一个对象ProcessState::self(),ProcessState::self()是一个单例对象,而在ProcessState的构造函数中,会调用open_driver关联binder驱动,并进行内存映射。

frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != nullptr) {
return gProcess;
}
gProcess = new ProcessState(kDefaultDriver);
return gProcess;
}
复制代码
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver))
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(nullptr)
, mBinderContextUserData(nullptr)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
...
}
}
复制代码
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
...
}
return fd;
}
复制代码

因为在注册binder设备驱动的时候,对应的file_operations已经注册好了,所以调用open打开binder设备时,最终将进入内核调用到函数binder_open

static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
复制代码

因为binder驱动属于内核模块,所以下面关于binder的代码来源于kernel_3.18 drivers/staging/android/binder.c

static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
...
return 0;
}
复制代码

而ProcessState构造函数中调用的mmap函数最终将进入内核调用到函数binder_mmap,Binder机制中mmap的最大特点是一次拷贝即可完成进程间通信。

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
struct vm_struct *area;
struct binder_proc *proc = filp->private_data;
const char *failure_string;
struct binder_buffer *buffer;
if (proc->tsk != current)
return -EINVAL;
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;
if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
ret = -EPERM;
failure_string = "bad vm_flags";
goto err_bad_arg;
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
mutex_lock(&binder_mmap_lock);
if (proc->buffer) {
ret = -EBUSY;
failure_string = "already mapped";
goto err_already_mapped;
}
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
if (area == NULL) {
ret = -ENOMEM;
failure_string = "get_vm_area";
goto err_get_vm_area_failed;
}
proc->buffer = area->addr;
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
mutex_unlock(&binder_mmap_lock);
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
if (proc->pages == NULL) {
ret = -ENOMEM;
failure_string = "alloc page array";
goto err_alloc_pages_failed;
}
proc->buffer_size = vma->vm_end - vma->vm_start;
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
//binder_update_page_range主要做了三件事:1)分配指定个数的物理页;2)将物理页映射到内核地址空间area中;3)同时将物理页映射到用户地址空间的vma中
if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {
ret = -ENOMEM;
failure_string = "alloc small buf";
goto err_alloc_small_buf_failed;
}
buffer = proc->buffer;
INIT_LIST_HEAD(&proc->buffers);
list_add(&buffer->entry, &proc->buffers);
buffer->free = 1;
binder_insert_free_buffer(proc, buffer);
proc->free_async_space = proc->buffer_size / 2;
barrier();
proc->files = get_files_struct(current);
proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
return 0;
}
复制代码

Linux内存分为用户空间和内核空间,同时页表也分为两类,用户空间页表和内核空间页表,每个进程都有一个用户空间页表,但是系统只有一个内核空间页表。而binder_mmap关键是:更新用户空间对应页表的同时也同步映射内核页表,让两个页表都指向同一块内存,这样一来,数据只需要从A进程的用户空间,直接拷贝到B进程所对应的内核空间,而B对应的内核空间在B进程的用户空间也有相应的映射,这样就无需从内核拷贝到用户空间了。

回到onZygoteInit(),通过ProcessState::self()得到proc对象之后,紧接着就调用了startThreadPool(),而startThreadPool()会创建一个PoolThread线程对象,而PoolThread的threadLoop()里会调用IPCThreadState::self()的joinThreadPool(),此时就提到了上文transact中最终的调用对象IPCThreadState::self() frameworks/native/libs/binder/IPCThreadState.cpp

IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0),
mCallRestriction(mProcess->mCallRestriction)
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
mIPCThreadStateBase = IPCThreadStateBase::self();
}
复制代码
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
...
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
复制代码

joinThreadPool()的主要工作就是循环执行getAndExecuteCommand(),从mIn中取出数据,然后根据取出的cmd做相应的处理。getAndExecuteCommand()将在下文中详细分析,此时回到IPCThreadState::self()->transact()

IPCThreadState::self()->transact()

transact中调用writeTransactionData将Parcel中的信息封装到结构体binder_transaction_data中并写入mOut,然后在函数waitForResponse中将mOut中数据写入binder设备中

status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err;
...
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
if ((flags & TF_ONE_WAY) == 0) {
...
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
...
} else {
err = waitForResponse(nullptr, nullptr);
}
return err;
}
复制代码
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.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) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
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);
}
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
复制代码

其中mOut是IPCThreadState对象的Parcel类型的私有属性,而code参数是java层通过Proxy对象调用函数时对应函数的code,data参数是对应函数的参数数据,所以binder_transaction_data的data.ptr.buffer指向的是java层Proxy对象调用函数时的参数数据。

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:
if (!reply && !acquireResult) goto finish;
break;
...
case BR_REPLY:
...
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
...
return err;
}
复制代码
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:
if (!reply && !acquireResult) goto finish;
break;
...
case BR_REPLY:
...
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
...
return err;
}
复制代码

waitForResponse()会调用talkWithDriver(),在talkWithDriver()中会创建binder_write_read对象,并调用ioctl陷入内核。

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
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_consumed = 0;
bwr.read_consumed = 0;
do {
...
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
...
} while (err == -EINTR);
return err;
}
复制代码

在调用ioctl中会将binder_write_read对象bwr的地址传入

因为最终ioctl会进入内核调用binder_ioctl,所以此时我们回到内核binder的代码中

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;
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:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
case BINDER_SET_MAX_THREADS:
...
case BINDER_SET_CONTEXT_MGR:
...
case BINDER_THREAD_EXIT:
...
case BINDER_VERSION: {
...
default:
ret = -EINVAL;
goto err;
}
...
trace_binder_ioctl_done(ret);
return ret;
}
复制代码

因为调用ioctl时传入的参数是BINDER_WRITE_READ,所以最后将调用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;
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;
}
...
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
...
}
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 (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
return ret;
}
复制代码

通过copy_from_user将binder_write_read对象从用户空间复制到内核空间,之后将调用binder_thread_write读取bwr.write_buffer中的数据。

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) {
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
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)]++;
}
switch (cmd) {
...
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
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;
}
复制代码

因为在上文writeTransactionData中,向mOut写入了BC_TRANSACTION的cmd和binder_transaction_data对象tr,所以get_user(cmd, (uint32_t __user *)ptr)将取出BC_TRANSACTION,然后进入对应的switch分支,通过copy_from_user将用户空间的binder_transaction_data对象复制到内核空间的tr对象上,最终调用binder_transaction()

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;
e = binder_transaction_log_add(&binder_transaction_log);
e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
e->from_proc = proc->pid;
e->from_thread = thread->pid;
e->target_handle = tr->target.handle;
e->data_size = tr->data_size;
e->offsets_size = tr->offsets_size;
if (reply) {
in_reply_to = thread->transaction_stack;
...
thread->transaction_stack = in_reply_to->to_parent;
target_thread = in_reply_to->from;
...
target_proc = target_thread->proc;
} else {
if (tr->target.handle) {
struct binder_ref *ref;
ref = binder_get_ref(proc, tr->target.handle);
...
target_node = ref->node;
} else {
...
}
e->to_node = target_node->debug_id;
target_proc = target_node->proc;
...
}
if (target_thread) {
e->to_thread = target_thread->pid;
target_list = ⌖_thread->todo;
target_wait = ⌖_thread->wait;
} else {
target_list = ⌖_proc->todo;
target_wait = ⌖_proc->wait;
}
e->to_proc = target_proc->pid;
t = kzalloc(sizeof(*t), GFP_KERNEL);
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);
if (tcomplete == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_tcomplete_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
...
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;
t->flags = tr->flags;
t->priority = task_nice(current);
trace_binder_transaction(reply, t, target_node);
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;
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 *)));
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size)) {
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (copy_from_user(offp, (const void __user *)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size)) {
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
...
off_end = (void *)offp + tr->offsets_size;
off_min = 0;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
...
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
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);
}
...
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_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
...
} break;
...
}
}
if (reply) {
BUG_ON(t->buffer->async_transaction != 0);
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
if (target_node->has_async_transaction) {
target_list = ⌖_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()是IPC最关键的一步,reply参数用于判断是否是服务端回复,因为此时是客户端调用,所以binder_thread_write()调用此函数时此参数是false,所以此时会调用binder_get_ref()通过target.handle来获取对应的binder_ref,binder_ref的由来就要回到bindService说起,所以我们放到后文中介绍,此时我们只需知道这个binder_ref是在ActivityManagerService回调IServiceConnection对象时,插入到当前进程的proc->refs_by_desc中。当前进程每次与服务端进程通信的时候就可以通过desc在proc->refs_by_desc中找到对应的binder_ref, 根据binder_ref可以找到对应的binder_node,然后可以根据binder_node->cookie找到binder实体在服务端进程中的地址。此处的proc是binder_proc,也就是在binder_open时创建的指针,用来管理进程中binder通信在内核中的所有事务。接下来就介绍一下几个主要数据结构之间的关系:

struct binder_proc {
struct hlist_node proc_node;
struct rb_root threads;//用于管理进程中所有binder_thread的红黑树
struct rb_root nodes;//进程中的所有binder实体都会创建一个binder_node,并插入到该红黑树
/*进程访问过的所有binder server都会创建一个引用结构binder_ref, 该结构会同时插入下面两个红黑树。 红黑树refs_by_desc的key为desc, 红黑树refs_by_node的key为node(binder在进程中的地址)*/
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
int pid;
struct vm_area_struct *vma;
struct mm_struct *vma_vm_mm;
...
struct list_head todo;
wait_queue_head_t wait;
};
复制代码

线程在发起binder通信的时候会创建一个结构体binder_thread管理线程自己binder通信相关的信息

struct binder_thread {
struct binder_proc *proc;//线程所属的binder_proc
struct rb_node rb_node;//用于插入proc->threads
int pid;
int looper;
struct binder_transaction *transaction_stack;//线程传输数据管理结构t链表
struct list_head todo;//传输数据添加到target_proc->todo中之后会添加一个tcomplete到这里
...
wait_queue_head_t wait;
struct binder_stats stats;
};
复制代码

Binder实体在内核中由一个结构体binder_node来管理

struct binder_node {
...
struct binder_proc *proc;//binder实体所属进程的proc
struct hlist_head refs;//引用该binder实体都会添加一个binder_ref到该哈希表
int internal_strong_refs;//binder实体引用计数
int local_weak_refs;
int local_strong_refs;
binder_uintptr_t ptr;//binder实体在进程应用空间的引用
binder_uintptr_t cookie;//binder实体在应用空间的地址
...
};
复制代码

客户端进程每关联一个服务端binder对象就会创建一个binder_ref,插入到当前进程的proc->refs_by_desc中,当前进程每次与服务进程通信的时候就可以通过desc在proc->refs_by_desc中找到对应的binder_ref, 根据binder_ref可以找到对应的binder_node,然后可以根据binder_node->cookie找到binder实体在服务进程中的地址。

struct binder_ref {
int debug_id;
struct rb_node rb_node_desc;//用于插入红黑树proc->refs_by_desc
struct rb_node rb_node_node;//用于插入红黑树proc->refs_by_node
struct hlist_node node_entry;//用于插入哈希表binder_node->refs
struct binder_proc *proc;//引用所属进程的proc
struct binder_node *node;
uint32_t desc;//binder实体引用在当前进程proc中的编号
int strong;
int weak;
struct binder_ref_death *death;
};
复制代码

介绍完几个主要结构体后,我们接着binder_transaction()继续分析,通过binder_get_ref得到binder_ref之后,就能得到对应的binder_node对象target_node,通过target_node又能得到binder实体所属进程的target_proc,因为reply为false,所以target_thread为NULL,target_list指向target_proc->todo,target_wait指向target_proc->wait,随后会调用binder_alloc_buf()在目标进程申请一块内存用来存放java层Proxy对象调用方法时将方法参数打包在Pracel中的数据,接着就调用copy_from_user()将Pracel中的数据从用户空间复制到刚刚申请的内核地址t->buffer->data,在binder_mmap中我们有介绍到,申请到的内存在内核空间和用户空间指向的是同一块物理内存,所以后面服务进程处理IPC调用时,无需再将数据从内核空间复制到用户空间。如果方法参数中有Binder对象时,将被打包在Parcel的ipcObjects()中,所以第二次copy_from_user()中 tr->data.ptr.offsets的地址是和Binder对象相关的flat_binder_object。复制完成之后,会遍历这些flat_binder_object,通过binder_get_node从当前进程的proc->nodes.rb_node红黑树中查找对应的binder_node,如果没有查找到,则会调用binder_new_node创建一个新的binder_node,并将自身的rb_node插入到proc->nodes.rb_node的红黑树中。接着会调用binder_get_ref_for_node,这是很关键的一步,函数首先会在目标进程的proc->refs_by_node查找对应的node_ref,如果查找到则直接返回,如果未查找到,则会创建一个新的node_ref对象new_ref,然后会遍历proc->refs_by_node红黑树,查找最大的desc,然后在最大的desc上+1赋值给new_ref->desc,desc相当于binder对象在目标进程中编号,也是上文中提到的c++对象BpBinder的构造参数handle,所以在BpBinder调用transact()时传入的mHandle参数就是node_ref的desc。最后,将new_ref插入到目标进程的proc->refs_by_node红黑树中。至此,binder_get_ref_for_node()的过程结束了。

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;
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;
}
new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
if (new_ref == NULL)
return NULL;
binder_stats_created(BINDER_STAT_REF);
new_ref->debug_id = ++binder_last_id;
new_ref->proc = proc;
new_ref->node = node;
rb_link_node(&new_ref->rb_node_node, parent, p);
rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
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;
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_link_node(&new_ref->rb_node_desc, parent, p);
rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc);}
return new_ref;
}
复制代码

随后我们将看到fp->handle = ref->desc,这也刚刚所说的desc就是BpBinder的构造参数handle的原因。接下来就是通过list_add_tail将BINDER_WORK_TRANSACTION放到target_list(也就是之前所说的target_proc->todo)上,然后通过wake_up_interruptible将目标进程唤醒。至此,客户端的流程就暂时结束了。

IPCThreadState::getAndExecuteCommand()

在上文中曾介绍过App启动时会执行onZygoteInit(),在此过程中会启动名为PoolThread的binder线程,此线程会无限循环执行getAndExecuteCommand(),所以此线程就是专门用来处理客户端进程发来IPC调用

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
...
result = executeCommand(cmd);
...
}
return result;
}
复制代码

这时调用了上文曾讲解过的talkWithDriver(),talkWithDriver()会调用ioctl陷入内核,最终会调用binder_ioctl(),而binder_ioctl()会调用binder_ioctl_write_read(),不过这次关注重点不再是binder_thread_write(),而是binder_thread_read(),接下来就具体分析一下binder_thread_read()

drivers/staging/android/binder.c

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;
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work,
entry);
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
w = list_first_entry(&proc->todo, struct binder_work,
entry);
} else {
/* no data added */
if (ptr - buffer == 4 &&
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}
if (end - ptr < sizeof(tr) + 4)
break;
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work);
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
...
} break;
case BINDER_WORK_NODE: {
...
} break;
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
...
} break;
}
if (!t)
continue;
BUG_ON(t->buffer == NULL);
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node;
tr.target.ptr = target_node->ptr;
tr.cookie =  target_node->cookie;
t->saved_priority = task_nice(current);
if (t->priority < target_node->min_priority &&
!(t->flags & TF_ONE_WAY))
binder_set_nice(t->priority);
else if (!(t->flags & TF_ONE_WAY) ||
t->saved_priority > target_node->min_priority)
binder_set_nice(target_node->min_priority);
cmd = BR_TRANSACTION;
} else {
tr.target.ptr = 0;
tr.cookie = 0;
cmd = BR_REPLY;
}
tr.code = t->code;
tr.flags = t->flags;
tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
if (t->from) {
struct task_struct *sender = t->from->proc->tsk;
tr.sender_pid = task_tgid_nr_ns(sender,
task_active_pid_ns(current));
} else {
tr.sender_pid = 0;
}
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (binder_uintptr_t)(
(uintptr_t)t->buffer->data +
proc->user_buffer_offset);
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
trace_binder_transaction_received(t);
binder_stat_br(proc, thread, cmd);
list_del(&t->work.entry);
t->buffer->allow_user_free = 1;
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;
} else {
t->buffer->transaction = NULL;
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
break;
}
...
return 0;
}
复制代码

在上文binder_transaction()中的最后,list_add_tail将BINDER_WORK_TRANSACTION放到target_proc->todo上,此时通过list_first_entry()从proc->todo上取出BINDER_WORK_TRANSACTION对应的work.entry,然后container_of()通过work.entry得到binder_transaction。binder_transaction就是上文binder_transaction()中创建的对象,得到binder_transaction之后,将binder_transaction上的各个属性赋值给binder_transaction_data对象tr,给tr.data.ptr.buffer赋值时,会将对应的值加上proc->user_buffer_offset,因为在上文binder_transaction()中复制数据时,是从客户端的用户空间复制到了内核空间,而上文也说过binder_mmap会申请一块内存将用户空间和内核空间映射到同一块物理内存上,而proc->user_buffer_offset就是用户空间相对于内核空间的偏移量,因为tr最终会通过copy_to_user复制到用户空间,所以tr.data.ptr.buffer 应该指向用户空间的地址。因为ptr指向的是binder_write_read的read_buffer,而read_buffer就是talkWithDriver()时的mIn.data(),执行完binder_thread_read()就可以回到用户态的IPCThreadState::getAndExecuteCommand()中去了。在上文getAndExecuteCommand()中,我们可以看到,talkWithDriver()之后,会从mIn中取出取出cmd,也就是BR_TRANSACTION,并将其作为参数调用executeCommand()

executeCommand

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
...
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
binder_transaction_data_secctx tr_secctx;
binder_transaction_data& tr = tr_secctx.transaction_data;
if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
result = mIn.read(&tr_secctx, sizeof(tr_secctx));
} else {
result = mIn.read(&tr, sizeof(tr));
tr_secctx.secctx = 0;
}
...
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
...
Parcel reply;
status_t error;
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
// safely acquire a strong reference before doing anything else with it.
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
mIPCThreadStateBase->popCurrentState();
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
...
}
break;
...
return result;
}
复制代码

在executeCommand()中,会从mIn中读出binder_transaction_data,然后将tr.data.ptr.buffer和tr.data.ptr.offsets设置给buffer,所以buffer就是打包在Parcel里的函数参数,而tr.code就是aidl生成类中对应函数的code,通过tr.cookie获得BBinder对象的地址,然后调用对应的transact(),而transact()会调用onTransact(),onTransact是一个虚函数会调用到其子类JavaBBinder的onTransact,JavaBBinder的由来和上文中提到的BpBinder会在下文中介绍,接下来就看一下JavaBBinder的onTransact()

frameworks/base/core/jni/android_util_Binder.cpp

status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
JNIEnv* env = javavm_to_jnienv(mVM);
IPCThreadState* thread_state = IPCThreadState::self();
const int32_t strict_policy_before = thread_state->getStrictModePolicy();
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
...
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
复制代码
static int int_register_android_os_Binder(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, kBinderPathName);
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
gBinderOffsets.mGetInterfaceDescriptor = GetMethodIDOrDie(env, clazz, "getInterfaceDescriptor",
"()Ljava/lang/String;");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
return RegisterMethodsOrDie(
env, kBinderPathName,
gBinderMethods, NELEM(gBinderMethods));
}
复制代码

gBinderOffsets.mExecTransact指向的是java层execTransact方法,而mObject就是aidl文件生成类Stub的实现类,所以最终调用的就是我们在服务端onBind()方法中返回的Binder对象的execTransact方法。

frameworks/base/core/java/android/os/Binder.java

private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
// At that point, the parcel request headers haven't been parsed so we do not know what
// WorkSource the caller has set. Use calling uid as the default.
final int callingUid = Binder.getCallingUid();
final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid);
try {
return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
}
}
复制代码
private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
int callingUid) {
...
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
...
try {
...
res = onTransact(code, data, reply, flags);
} catch (RemoteException|RuntimeException e) {
...
} finally {
...
}
reply.recycle();
data.recycle();
...
return res;
}
复制代码

所以最终会调用到Stub类的onTransact()方法,而onTransact()会根据code调用不同的方法,而这些方法就是我们在Stub实现类中重写的方法。至此,就调用到了服务端中的方法,而客户端还在上文中waitForResponse处等待服务端执行结果。回到上文executeCommand中,执行完transact(),也就是执行完服务端对应方法后,会调用sendReply(),接下来就分析一下sendReply()

sendReply

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
status_t err;
status_t statusBuffer;
err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
if (err < NO_ERROR) return err;
return waitForResponse(nullptr, nullptr);
}
复制代码

sendReply和上文中客户端调用IPCThreadState::transact()很相似,都是调用了writeTransactionData和waitForResponse,不同的是writeTransactionData的cmd参数是BC_REPLY,接下来就和上文中的执行流程基本相似,通过writeTransactionData将binder_transaction_data写入mOut,然后ioctl陷入内核,最终执行到binder_transaction

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;
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;
e = binder_transaction_log_add(&binder_transaction_log);
e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
e->from_proc = proc->pid;
e->from_thread = thread->pid;
e->target_handle = tr->target.handle;
e->data_size = tr->data_size;
e->offsets_size = tr->offsets_size;
if (reply) {
in_reply_to = thread->transaction_stack;
...
thread->transaction_stack = in_reply_to->to_parent;
target_thread = in_reply_to->from;
...
target_proc = target_thread->proc;
} else {
...
}
if (target_thread) {
e->to_thread = target_thread->pid;
target_list = ⌖_thread->todo;
target_wait = ⌖_thread->wait;
} else {
target_list = ⌖_proc->todo;
target_wait = ⌖_proc->wait;
}
e->to_proc = target_proc->pid;
t = kzalloc(sizeof(*t), GFP_KERNEL);
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);
if (tcomplete == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_tcomplete_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
...
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;
t->flags = tr->flags;
t->priority = task_nice(current);
trace_binder_transaction(reply, t, target_node);
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;
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 *)));
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size)) {
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (copy_from_user(offp, (const void __user *)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size)) {
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
...
if (reply) {
BUG_ON(t->buffer->async_transaction != 0);
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
if (target_node->has_async_transaction) {
target_list = ⌖_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;
...
}
复制代码

与上次不同的是,这次是通过in_reply_to获取到客户端等待结果的线程target_thread,target_list不再指向target_proc->todo,而是指向target_thread->todo,接下来就是通过copy_from_user将数据写入客户端进程,最终通过list_add_tail将BINDER_WORK_TRANSACTION放到target_thread->todo上,将BINDER_WORK_TRANSACTION_COMPLETE放到当前binder线程的thread->todo上,后续两端都会随着binder_thread_read的结束回到waitForResponse()

waitForResponse

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;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
...
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
...
return err;
}
复制代码

因为服务端binder线程的waitForResponse读取出cmd是BR_TRANSACTION_COMPLETE,所以最后会执行goto finish,结束waitForResponse,重新回到getAndExecuteCommand()循环,等待客户端IPC调用。而客户端会进入BR_REPLY分支,将binder_transaction_data的tr.data.ptr.buffer和tr.data.ptr.offsets设置给当前进程的reply,也就是客户端BinderProxy发起调用时函数参数中Parcel类型的reply对象,最终通过goto finish结束waitForResponse后,就回到了我们最开始的地方

@Override public void setSurface(android.view.Surface surface) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((surface!=null)) {
_data.writeInt(1);
surface.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_setSurface, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
复制代码

至此,一次IPC调用就结束了。

关于BPBinder和JavaBBinder

在IPC调用的参数中可能包含Binder对象,就例如bindService,ActivityManagerService 会调用目标进程ApplicationThread这个Binder对象的scheduleBindService()去绑定对应服务,然后通过Handler最终会执行到ActivityThread的handleBindService()

frameworks/base/core/java/android/app/ActivityThread.java

private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
...
}
}
}
复制代码

在handleBindService()中,Service onBind()返回的IBinder对象会通过publishService()传递给ActivityManagerService,而publishService()就是一次IPC调用,其中参数就包含Binder对象。在上文中,进行IPC调用会将函数参数打包到Parcel中,接下来就看下Binder对象是如何打包到Parcel中去的。

frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
复制代码

frameworks/base/core/jni/android_util_Binder.cpp

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
// Instance of Binder?
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh->get(env, obj);
}
// Instance of BinderProxy?
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return getBPNativeData(env, obj)->mObject;
}
return NULL;
}
复制代码
class JavaBBinderHolder
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
mBinder = b;
}
return b;
}
...
};
复制代码

这就是JavaBBinder对象的由来,在binder_transaction()中创建binder_node时,会将该对象的地址赋值给binder_node->cookie,所以上文executeCommand()中tr->cookie就是JavaBBinder对象的地址。接下来就介绍一下BPBinder的由来,在服务端进程将Binder对象传给ActivityManagerService后,ActivityManagerService会回调IServiceConnection将服务端的Binder对象传给客户端进程,这样客户端就可以对服务端进行IPC调用了。因为IServiceConnection回调也是一次IPC调用,客户端在响应IPC调用时,需要从Parcel中取出函数参数,所以Binder对象是从Parcel中取出的,接下来就看一下Binder对象是如何从Parcel中取出的。

frameworks/base/core/jni/android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
复制代码

framework/native/libs/binder/Parcel.cpp

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
return unflatten_binder(ProcessState::self(), *this, val);
}
复制代码
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(nullptr, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
复制代码

这就是BPBinder的由来,接下来我们再看一下javaObjectForIBinder()

frameworks/base/core/jni/android_util_Binder.cpp

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
...
BinderProxyNativeData* nativeData = new BinderProxyNativeData();
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
...
return object;
}
复制代码
const char* const kBinderProxyPathName = "android/os/BinderProxy";
static int int_register_android_os_BinderProxy(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, "java/lang/Error");
gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
clazz = FindClassOrDie(env, kBinderProxyPathName);
gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance",
"(JJ)Landroid/os/BinderProxy;");
gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
"(Landroid/os/IBinder$DeathRecipient;)V");
gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
clazz = FindClassOrDie(env, "java/lang/Class");
gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
return RegisterMethodsOrDie(
env, kBinderProxyPathName,
gBinderProxyMethods, NELEM(gBinderProxyMethods));
}
复制代码

看到这里是不是就明白了为什么我们一开始要用BinderProxy去分析transact,因为javaObjectForIBinde()会调用BinderProxy的getInstance()获取一个BinderProxy对象,而它就是最终从Parcel中取出的IBinder对象。

使用Webpack等搭建一个适用于React项目的脚手架(3 - Eslint、Jest)

上一篇

CI/CD with Cloud-Native Applications

下一篇

你也可能喜欢

Android Binder之旅

长按储存图像,分享给朋友