Android Binder之旅

1,159 阅读23分钟

由于最近想换工作,于是就打开了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 = &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);
	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 = &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()是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 = &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);
	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 = &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;
	    ...   
}

与上次不同的是,这次是通过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对象。