Android Binder 机制之 hal 层服务注册过程

Android Binder 机制之 hal 层服务注册过程

以 Hal 层进程作为 Binder 机制中服务进程模块讲解服务端如何通过 Binder 驱动向 ServiceManager 注册服务的。

以 Broadcastradiohal2.0 为例,Android 版本 Android 9.0

broadcastradiohal 启动

收音机的 Broadcastradiohal2.0 源码在 hardware/interfaces/broadcastradio/2.0 目录下

// hardware/interfaces/broadcastradio/2.0/default/service.cpp
int main(int /* argc */, char** /* argv */) {
    ...
    BroadcastRadio broadcastRadio(gAmFmRadio);
    auto status = broadcastRadio.registerAsService();   // radio hal 启动时注册服务

    return 1;  // joinRpcThreadpool shouldn't exit
}

struct BroadcastRadio : public IBroadcastRadio {
    ...
}

IBroadcastRadio 声明在文件 hardware/interfaces/broadcastradio/2.0/IBroadcastRadio.hal 中,hal 文件会被 Android 的 HIDL 工具展开到生成目录中,最终实现位于 BroadcastRadioAll.cpp 文件中

// out/soong/.intermediates/hardware/interfaces/broadcastradio/2.0/android.hardware.broadcastradio@2.0_genc++/gen/android/hardware/broadcastradio/2.0/BroadcastRadioAll.cpp
::android::status_t IBroadcastRadio::registerAsService(const std::string &serviceName) {
    ::android::hardware::details::onRegistration("android.hardware.broadcastradio@2.0", "IBroadcastRadio", serviceName);

    // 获取 manager::V1_0::IServiceManager 类型的句柄
    const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm
            = ::android::hardware::defaultServiceManager();
    if (sm == nullptr) {
        return ::android::INVALID_OPERATION;
    }

    // 添加到 IServiceManager 类示例中
    ::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this);
    return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;
}

注册函数中分为两步,第一步获取 SeviceManager 句柄,第二步,将自己注册到 ServiceManager 中

获取 ServiceManager 句柄

// system/libhidl/transport/ServiceManagement.cpp

sp<IServiceManager1_0> defaultServiceManager() {
    return defaultServiceManager1_1();
}
sp<IServiceManager1_1> defaultServiceManager1_1() {
    {
        AutoMutex _l(details::gDefaultServiceManagerLock);
        if (details::gDefaultServiceManager != nullptr) {
            return details::gDefaultServiceManager;
        }

        if (access("/dev/hwbinder", F_OK|R_OK|W_OK) != 0) {
            // HwBinder not available on this device or not accessible to
            // this process.
            return nullptr;
        }

        waitForHwServiceManager();

        while (details::gDefaultServiceManager == nullptr) {
            details::gDefaultServiceManager =
                    fromBinder<IServiceManager1_1, BpHwServiceManager, BnHwServiceManager>(
                        ProcessState::self()->getContextObject(nullptr));
            ...
        }
    }

    return details::gDefaultServiceManager;
}

重点1:ProcessState::self()->getContextObject(nullptr)

// system/libhwbinder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState(DEFAULT_BINDER_VM_SIZE);
    return gProcess;
}
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

// 根据 handle 值返回一个 IBinder 对象
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    // 传入的 handle 值为 0,表示找的是管理句柄
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            b = new BpHwBinder(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}

getContextObject(nullptr) 的目的就是为了创建一个 BpHwBinder 对象,而且这个对象的内部 handle = 0,这个值很特殊,因为它就是 servicemanager 的 handle 值,用来到 binder 驱动中找目标进程 binder_proc 的关键

重点2 fromBinder()

template <typename IType, typename ProxyType, ypename StubType> sp<IType> fromBinder(const sp<IBinder>& binderIface);
在此处的调用等价于
template <typename IType = IServiceManager1_1, typename ProxyType = BpHwServiceManager, typename StubType = BnHwServiceManager>
IServiceManager1_1 fromBinder(const sp<IBinder>& binderIface);
// system/libhidl/transport/include/hidl/HidlBinderSupport.h
template <typename IType, typename ProxyType, typename StubType>
sp<IType> fromBinder(const sp<IBinder>& binderIface) {
    using ::android::hidl::base::V1_0::IBase;
    using ::android::hidl::base::V1_0::BnHwBase;

    if (binderIface.get() == nullptr) {
        return nullptr;
    }
    if (binderIface->localBinder() == nullptr) {
        return new ProxyType(binderIface);
    }
    sp<IBase> base = static_cast<BnHwBase*>(binderIface.get())->getImpl();
    if (details::canCastInterface(base.get(), IType::descriptor)) {
        StubType* stub = static_cast<StubType*>(binderIface.get());
        return stub->getImpl();
    } else {
        return nullptr;
    }
}

这里的 fromBinder() 的实际含义就是 new BpHwServiceManager(new BpBinder(0)),通过 BpHwServiceManager 类型返回一个 IServiceManager 类型,因为前者的类中包含一个后者类的类。

至此,ServiceManager 句柄已经找到,下面开始将当前进程添加到 ServiceManager 类中

一个疑问

fromBinder()BnHwServiceManager 实例类型,但是参考资料都说是 BpHwServiceManager 类型,这其中的缘由是什么?

broadcastradiohal 用户空间注册流程

// add(android.hardware.broadcastradio@2.0::IBroadcastRadio, this = IBroadcastRadio)
sm->add(serviceName.c_str(), this)

sm 是 BpHwServiceManager,serviceName = "android.hardware.broadcastradio@2.0::IBroadcastRadio", this 是 IBroadcastRadio 类实例

// out/soong/.intermediates/system/libhidl/transport/manager/1.0/android.hidl.manager@1.0_genc++/gen/android/hidl/manager/1.0/ServiceManagerAll.cpp
::android::hardware::Return<bool> BpHwServiceManager::add(const ::android::hardware::hidl_string& name, const ::android::sp<::android::hidl::base::V1_0::IBase>& service){
    ::android::hardware::Return<bool>  _hidl_out = ::android::hidl::manager::V1_0::BpHwServiceManager::_hidl_add(this, this, name, service);

    return _hidl_out;
}

::android::hardware::Return<bool> BpHwServiceManager::_hidl_add(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, const ::android::hardware::hidl_string& name, const ::android::sp<::android::hidl::base::V1_0::IBase>& service) {
    ...
    ::android::hardware::Parcel _hidl_data;
    ::android::hardware::Parcel _hidl_reply;
    ...
    _hidl_err = _hidl_data.writeInterfaceToken(BpHwServiceManager::descriptor); // 将特定标识符写入到 token 中
    ...
    _hidl_err = _hidl_data.writeBuffer(&name, sizeof(name), &_hidl_name_parent);    // 将 service 的 name 写入 _hidl_data中
    ...
    _hidl_err = ::android::hardware::writeEmbeddedToParcel(
            name,
            &_hidl_data,
            _hidl_name_parent,
            0 /* parentOffset */);          // 将 _hidl_data 序列化,以便于嵌入式数据在 IPC 过程中传递
    ...
    if (service == nullptr) {
        _hidl_err = _hidl_data.writeStrongBinder(nullptr);
    } else {
        ::android::sp<::android::hardware::IBinder> _hidl_binder = ::android::hardware::toBinder<
                ::android::hidl::base::V1_0::IBase>(service);
        if (_hidl_binder.get() != nullptr) {
            _hidl_err = _hidl_data.writeStrongBinder(_hidl_binder);             // 将 service 句柄写入 _hidl_data 中
        } else {
            _hidl_err = ::android::UNKNOWN_ERROR;
        }
    }
    ...
    _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(2 /* add */, _hidl_data, &_hidl_reply);     // 将 _hidl_data 发送到 Binder 内核中
    ...
}
  • Parcel 是一个包裹类,里面封装了很多传递数据的方法,如 32bit int,Binder 对象,Obejct 对象等,都可以序列化成 data,然后用来传递到 binder 驱动层
  • asBinder() 将传入参数参数转化成 BpHwBinder,即在第一步中获得 ServiceManager 句柄,BpHwServiceManager 实例
// system/libhwbinder/IInterface.cpp
sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)
{
    if (iface == NULL) return NULL;
    return iface->onAsBinder();
}

// system/libhwbinder/include/hwbinder/IInterface.h
template<typename INTERFACE>
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
    return remote();
}

// system/libhwbinder/include/hwbinder/Binder.h
inline  IBinder*        remote() const          { return mRemote; }

于是就调用了 BpHwBinder 的 transact() 函数

// system/libhwbinder/BpHwBinder.cpp
status_t BpHwBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags, TransactCallback /*callback*/)
{
    // 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 类的 transact() 函数

// system/libhwbinder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err;

    flags |= TF_ACCEPT_FDS;

    ...
    // 设置 BC_TRANSACTION_SG 指令,构建 binder_transaction_data 数据,写入到 mOut 中
    err = writeTransactionData(BC_TRANSACTION_SG, flags, handle, code, data, NULL);
    ...
    // 确定是否设置了 TF_ONE_WAY 标志,默认没有
    if ((flags & TF_ONE_WAY) == 0) {
        ...
        // reply 表示是否需要获取传回来的数据
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        ...
    } else {
        err = waitForResponse(NULL, NULL);
    }
}

// 将要传输的数据整理好,保存到 mOut 中
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_sg tr_sg;
    /* Don't pass uninitialized stack data to a remote process */
    tr_sg.transaction_data.target.ptr = 0;
    tr_sg.transaction_data.target.handle = handle;  // 就是 new BpBinder(0) 时,将 0 给 mHanlder 传到此处的
    tr_sg.transaction_data.code = code;             // 2,也即是 add
    tr_sg.transaction_data.flags = binderFlags;
    tr_sg.transaction_data.cookie = 0;
    tr_sg.transaction_data.sender_pid = 0;
    tr_sg.transaction_data.sender_euid = 0;
    
    ...

    if (err == NO_ERROR) {
        // data 的数据就是在 BpHwServiceManager::_hidl_add() 函数中赋值的那部分数据
        tr_sg.transaction_data.data_size = data.ipcDataSize();      // 非 IBinder 数据大小
        tr_sg.transaction_data.data.ptr.buffer = data.ipcData();       // 指向data 中非 IBinder 数据,如 int,string 等
        tr_sg.transaction_data.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); // Binder 数组大小
        tr_sg.transaction_data.data.ptr.offsets = data.ipcObjects();    // data 中保存的 IBinder 对象数组的指针
        tr_sg.buffers_size = data.ipcBufferSize();
    } else if (statusBuffer) {
        tr_sg.transaction_data.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr_sg.transaction_data.data_size = sizeof(status_t);
        tr_sg.transaction_data.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr_sg.transaction_data.offsets_size = 0;
        tr_sg.transaction_data.data.ptr.offsets = 0;
        tr_sg.buffers_size = 0;
    } else {
        return (mLastError = err);
    }

    mOut.writeInt32(cmd);               // cmd 就是 BC_TRANSACTION_SG
    mOut.write(&tr_sg, sizeof(tr_sg));

    return NO_ERROR;
}

然后就是 waitForResponse(reply)

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    ...
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
    }
}

// talkWithDriver():  将数据通过 ioctl 写入到驱动中
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    binder_write_read bwr;

    // mIn 刚开始是空的,也就是说 needRead = true
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();  // 写给驱动的数据指向的是 mOut 类中的 data

    // This is what we'll read.
    // doReceive 在函数声明处默认为 true,needRead 设置为 true。该次调用需要读,读的数据放到 mIn.data 中
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }

    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;

    ...
    if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)   // 进入 iotcl 系统调用,指令是 BINDER_WRITE_READ
        err = NO_ERROR;
    else
        err = -errno;
    ...
}

(ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) 中,该进程陷入系统调用中

Binder 内核处理

进入到内核空间,指令是 BINDER_WRITE_READ,数据是 BC_TRANSACTION_SG + binder_transaction_data_sg

// device/renesas/kernel/drivers/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    ...
	switch (cmd) {
	case BINDER_WRITE_READ:
		ret = binder_ioctl_write_read(filp, cmd, arg, thread);
		if (ret)
			goto err;
		break;
    ...
    }   
}

static int binder_ioctl_write_read(struct file *filp,
				unsigned int cmd, unsigned long arg,
				struct binder_thread *thread)
{
    ...
    // 将数据从用户空间拷贝到内核空间
	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);
		trace_binder_write_done(ret);
		if (ret < 0) {
			bwr.read_consumed = 0;
			if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
				ret = -EFAULT;
			goto out;
		}
	}
    // 也触发读
    if (bwr.read_size > 0) {
		ret = binder_thread_read(proc, thread, bwr.read_buffer,
					 bwr.read_size,
					 &bwr.read_consumed,
					 filp->f_flags & O_NONBLOCK);
		trace_binder_read_done(ret);
		binder_inner_proc_lock(proc);
		if (!binder_worklist_empty_ilocked(&proc->todo))
			binder_wakeup_proc_ilocked(proc);
		binder_inner_proc_unlock(proc);
		if (ret < 0) {
			if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
				ret = -EFAULT;
			goto out;
		}
	}
}

接下来看写和读的处理函数中做了什么事?

在写处理函数中

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;
	struct binder_context *context = proc->context;
    // buffer 指向用户写入的数据
	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.cmd == BR_OK) {
        // 取出 cmd, 也就是前面的 BC_TRANSACTION_SG 指令
        if (get_user(cmd, (uint32_t __user *)ptr))
			return -EFAULT;
        ...
        switch (cmd) {
        case BC_TRANSACTION_SG:
		case BC_REPLY_SG: {
			struct binder_transaction_data_sg tr;

            // 将用户空间的数据拷贝到 tr 中
			if (copy_from_user(&tr, ptr, sizeof(tr)))
				return -EFAULT;
			ptr += sizeof(tr);
            // 处理数据
			binder_transaction(proc, thread, &tr.transaction_data,
					   cmd == BC_REPLY_SG, tr.buffers_size);
			break;
		}
        }
    }
}

binder_transaction() 处理完数据后,退出 binder_thread_write(),返回 binder_ioctl_write_read() 函数,进入 binder_thread_read() 函数,然后阻塞到 binder_wait_for_work() 函数处,等待其他进程的唤醒。

binder_transaction() 函数是 binder 通信的核心方法,里面涉及了 transaction 和 reply 两个状态的处理。我们下面着重说明。

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply,
			       binder_size_t extra_buffers_size)
{
    // 通信的结构体,存储请求进程、目标进程信息,通信数据,状态
    struct binder_transaction *t;
    // 本次通信的操作状态结构体
    struct binder_work *tcomplete;
    // 存储目标进程信息
    struct binder_proc *target_proc = NULL;

    // 全局唯一的结构体,上下文信息,包含了 servicemanager 的 binder_node
    struct binder_context *context = proc->context;

    if (reply) {
        // 如果需要回复信息,先省略
    } else {
        if (tr->target.handle) {
            // 如果 handle 不为 0 的分支
            // 一般是描述一个客户端获取到服务端的进程后走的分支
            // 后续再描述
        } else {
            // 客户端或者服务端与 servicemanager 通讯的分支
			target_node = context->binder_context_mgr_node;     // 获取 servicemanager binder_node
			// binder_node 中存储的有所属进程的 binder_proc 信息
            // binder_get_node_refs_for_txn() 可以直接从 target_proc 直接获取到目标进程的 binder_proc 信息
            if (target_node)
				target_node = binder_get_node_refs_for_txn(
						target_node, &target_proc,
						&return_error);
			else
				return_error = BR_DEAD_REPLY;
            ...           
        }
        ...
    }
    ...
    if (!reply && !(tr->flags & TF_ONE_WAY))
		t->from = thread;   // 记录当前进程的 binder_thread,用于 servicemanager 返回结果的时候唤醒请求进程
	else
		t->from = NULL;
    
	t->sender_euid = task_euid(proc->tsk);
	t->to_proc = target_proc;       // 目标进程的 binder_proc
	t->to_thread = target_thread;   // 目前为 null
	t->code = tr->code;             // 记录对应的操作,当前是 ADD_SERVICE_TRANSACTION
	t->flags = tr->flags;
    ...
    /*
        这部分比较重要,涉及到如何将上层服务的注册数据如何传递给 servicemanager
        具体来说就是使用之间 mmap 映射好的用户虚拟空间区间到 bidner_alloc 里面分配的 pages 物理页面的映射关系
        然后将上层的 Parcel 中的数据,拷贝到 pages 物理内存,再把数据分配的对应的用户空间的起始地址传递给 sericemanager
    */
	t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
		tr->offsets_size, extra_buffers_size,
		!reply && (t->flags & TF_ONE_WAY));
    ...
    // 将 Parcel 里面的 data 和 binder 服务对象的数据拷贝到对应的物理内存中
    if (binder_alloc_copy_user_to_buffer(
            &target_proc->alloc,
            t->buffer, 0,
            (const void __user *)
                (uintptr_t)tr->data.ptr.buffer,
            tr->data_size)) {
            ...
    }
    if (binder_alloc_copy_user_to_buffer(
            &target_proc->alloc,
            t->buffer,
            ALIGN(tr->data_size, sizeof(void *)),
            (const void __user *)
                (uintptr_t)tr->data.ptr.offsets,
            tr->offsets_size)) {
            ...
    }
    for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
	     buffer_offset += sizeof(binder_size_t)) {
        /* 循环取出 binder 服务,根据本地 binder 对象或代理对象做相应的处理
            会为 Binder 服务创建一个 binder_node 并且为服务对象分配一个合适的 desc 作为 handle
            然后以 binder_node 和 desc 值插入目标进程的 servicemanager 的 binder_proc 中 refs_by_node 和 refs_by_desc 红黑树
        */
        ...
		struct binder_object_header *hdr;
        ...
		hdr = &object.hdr;
		switch (hdr->type) {
		case BINDER_TYPE_BINDER:
		case BINDER_TYPE_WEAK_BINDER: {
			struct flat_binder_object *fp;

			fp = to_flat_binder_object(hdr);
			ret = binder_translate_binder(fp, t, thread);   // 在此处,将 BINDER_TYPE_BINDER 状态修改为 BINDER_TYPE_HANDLE
			if (ret < 0) {
				return_error = BR_FAILED_REPLY;
				return_error_param = ret;
				return_error_line = __LINE__;
				goto err_translate_failed;
			}
			binder_alloc_copy_to_buffer(&target_proc->alloc,
						    t->buffer, object_offset,
						    fp, sizeof(*fp));
		} break;
        ...        
    }
    // 回复给上层服务使用
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // 给 servicemanager 处理的
	t->work.type = BINDER_WORK_TRANSACTION;

    if (reply) {
        // reply 时再研究
        ...
    } else if (!(t->flags & TF_ONE_WAY)) {
        /*
         * 推迟 TRANSACTION_COMPLETE,不需要立刻返回用户空间
         * 允许目标进程立刻开始处理转换,减少延迟。会在目标回复的时候返回 TRANSACTION_COMPLETE
         */
        // 将 binder_work 存在当前进程的 binder_thread 的 todo 列表中
        // servicemanager 唤醒后会执行 work 这个任务
		binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete);
		
        // transaction_stack 当前为空,from_parent 存的上一个任务,后续任务完成后,再从任务队列中取一个任务执行
		t->from_parent = thread->transaction_stack;

        // 将当前创建的 binder_transaction 记录在当前进程的 binder_thread 中的 transaction_stack
		thread->transaction_stack = t;
		binder_inner_proc_unlock(proc);
		if (!binder_proc_transaction(t, target_proc, target_thread)) {  // 该函数下方详解
            ...
		}
	} else {
        ...
    }
}
// 发送一个 transaction 到一个线程,并且唤醒这个线程
static bool binder_proc_transaction(struct binder_transaction *t,
				    struct binder_proc *proc,
				    struct binder_thread *thread)
{
	struct binder_node *node = t->buffer->target_node;
    ...
    // 传入目标进程的 binder_thread,thread 为空,pending_async 为 false
    // 所以在目标进程的 binder_proc 的 waiting_threads 链表中取出一个空闲的 binder 线程
	if (!thread && !pending_async)
		thread = binder_select_thread_ilocked(proc);

    // 本次通信事务的 binder_work 记录在 binder_thread 的 todo 链表中
    // 如果 binder_thread 为空,就记录在 binder_proc 的 todo 链表中
	if (thread) {
		binder_transaction_priority(thread->task, t, node_prio,
					    node->inherit_rt);
		binder_enqueue_thread_work_ilocked(thread, &t->work);
	} else if (!pending_async) {
		binder_enqueue_work_ilocked(&t->work, &proc->todo);
	} else {
		binder_enqueue_work_ilocked(&t->work, &node->async_todo);
	}

	if (!pending_async)
		binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);     // 唤醒目标进程 servicemanager
}

到此,一次通信事务过程的创建已经完成,该过程主要是构建了 binder_transaction 结构体,然后记录本次通信事务的目标进程信息,当前进程信息,操作类型,状态等。然后根据记录唤醒目标进程。

在构建 transaction 的时候,还有两个函数需要详细解释一下

// device/renesas/kernel/drivers/android/binder_alloc.c
struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
					   size_t data_size,
					   size_t offsets_size,
					   size_t extra_buffers_size,
					   int is_async)
{
	buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size,
					     extra_buffers_size, is_async);    
}

static struct binder_buffer *binder_alloc_new_buf_locked(
				struct binder_alloc *alloc,
				size_t data_size,
				size_t offsets_size,
				size_t extra_buffers_size,
				int is_async)
{
    ...
	data_offsets_size = ALIGN(data_size, sizeof(void *)) +
		ALIGN(offsets_size, sizeof(void *));
    ...
    // 之前 mmap 映射的时候已经创建了一个 binder_buffer,大小和 binder_alloca 的 datasize 一样打
    // 存在 free_buffers 红黑树里,下面是查找红黑树,如果有和 size 一致就结束,有大于 size 的节点就先存起来
    while (n) {
        ...
    }

    // bset_fit 为 null,说明没有找到足够的内存分配,直接返回
    if (best_fit == NULL) {
        // 记录 free_buffers 和 allocate_buffers 调试信息
        ...
    }
    // 根据 size 遍历完红黑树,用 bset_fit 得到大小最合适的 binder_buffer
    if (n == NULL) {
		buffer = rb_entry(best_fit, struct binder_buffer, rb_node);
		buffer_size = binder_alloc_buffer_size(alloc, buffer);
	}

    /*
     * 之前 mmap 生成了一个占据整块映射空间的内存区间 binder_buffer(start~end)
     * 假如当前是第一次对 servicemanager 做 addservice 操作,那么目前就生成了第二块 binder_buffer,范围是 start+size~end
     * 如果还有第二次 addservice 操作,那么 buffer_size 还可以继续划分,范围是 start+size+current_size~end
     */
	end_page_addr =
		(void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data + size);
	if (end_page_addr > has_page_addr)
		end_page_addr = has_page_addr;
	ret = binder_update_page_range(alloc, 1, (void __user *)
		PAGE_ALIGN((uintptr_t)buffer->user_data), end_page_addr);

    // 如果 buffer_size 不等于 size,说明分配过大了,重新创建分配地址空间
	if (buffer_size != size) {
		struct binder_buffer *new_buffer;

        // 重新创建一个 binder_buffer
		new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
        // 新的 binder_buffer 指向当前 binder_buffer 存储数据的开始地址 + size
		new_buffer->user_data = (u8 __user *)buffer->user_data + size;
		list_add(&new_buffer->entry, &buffer->entry);
        // 将 new_buffer 加入到 binder_alloc 中的 free_buffer 红黑树中
		binder_insert_free_buffer(alloc, new_buffer);
	}

    // 把当前的 binder_buffer 从 free_buffers 红黑树中移除,并加入到 allocated_buffer 红黑树中
    rb_erase(best_fit, &alloc->free_buffers);
    binder_insert_allocated_buffer_locked(alloc, buffer); 
}

// allocate = 1 是分配,= 0 是释放
static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
				    void __user *start, void __user *end)
{
    ...
    // 检查从 strat 到 end 范围的物理是否为空,为空则映射
	for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
		page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
		if (!page->page_ptr) {
			need_mm = true;
			break;
		}
	}
    ...
    /*
     * 遍历 alloc,检查该区域是否进行物理非陪和虚拟地址映射
     * 下面版本可以看出,最新版本已经不再建立内核区间和用户内存区间到物理内存区间的映射
     * 只是建立yoghurt内存区间到物理内存区间的映射
     */
    for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
		int ret;
		bool on_lru;
		size_t index;

		index = (page_addr - alloc->buffer) / PAGE_SIZE;
		page = &alloc->pages[index];

        // 已经分配的内存,就不再进行内存分配和地址映射操作
		if (page->page_ptr) {
			trace_binder_alloc_lru_start(alloc, index);

			on_lru = list_lru_del(&binder_alloc_lru, &page->lru);
			WARN_ON(!on_lru);

			trace_binder_alloc_lru_end(alloc, index);
			continue;
		}
        ...
        // 没有分配物理内存,只执行了内存分配
		page->page_ptr = alloc_page(GFP_KERNEL |
					    __GFP_HIGHMEM |
					    __GFP_ZERO);
        ...
		page->alloc = alloc;
		INIT_LIST_HEAD(&page->lru);

		user_page_addr = (uintptr_t)page_addr;

        // 建立虚拟内存区间到物理内存区间的映射
        ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr);
    }
}

进程通信数据总结

  1. 使用系统调用的 mmap 把一段连续的用户空间虚拟地址和内核空间分配的物理地址映射起来
  2. 把客户端传递的数据拷贝到分配的这段物理内存地址,等唤醒目标进程 servicemanager 后,把数据分配对应的用户空间虚拟地址的起始地址传递给 servicemanager
  3. 回到 servicemanager 用户空间后,通过上方地址访问和还原对应的结构体,从而通过一次数据拷贝就完成了数据传递。
  4. 数据传递到映射的虚拟地址是 Parcel 里面的 data 数据和 Binder 对象数组数据,code,flag 等,通过 copy_to_user() 拷贝 binder_transaction+data 给到服务端,本地添加服务到 servicemanager,那么服务端就是 servicemanager

servicemanager 服务处理

servicemanager 在收到 binder 通知有任务需要执行后,走了哪些流程

在 ServiceManager 启动的一文中,我们介绍过,servicemanager 的 binder 线程会阻塞到 binder_wait_for_work() 函数中等待任务到来

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)
{
    ...
	if (non_block) {
		if (!binder_has_work(thread, wait_for_proc_work))
			ret = -EAGAIN;
	} else {
		ret = binder_wait_for_work(thread, wait_for_proc_work);
	}
    ...    
}

那么此刻,service 添加请求到来,而且被唤醒,那么该线程可以继续往下走下去


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)
{
    ...
    while (1) {
		uint32_t cmd;
		struct binder_transaction_data_secctx tr;
		struct binder_transaction_data *trd = &tr.transaction_data;
		struct binder_work *w = NULL;
		struct list_head *list = NULL;
		struct binder_transaction *t = NULL;
		struct binder_thread *t_from;

        // 获取 todo 链表,即需要处理的 binder_work
		if (!binder_worklist_empty_ilocked(&thread->todo))
			list = &thread->todo;
		else if (!binder_worklist_empty_ilocked(&proc->todo) &&
			   wait_for_proc_work)
			list = &proc->todo;
		else {
            ...
        } 

		w = binder_dequeue_work_head_ilocked(list);
        switch (w->type) {              // 在创建 transaction 时可知,这个值是 BINDER_WORK_TRANSACTION
		case BINDER_WORK_TRANSACTION: {
			binder_inner_proc_unlock(proc);
			t = container_of(w, struct binder_transaction, work);   // 从 binder_work 类型获取 binder_transaction 类型
		} break;
        }
        ...
		if (t->buffer->target_node) {
			struct binder_node *target_node = t->buffer->target_node;
			struct binder_priority node_prio;

			trd->target.ptr = target_node->ptr;
			trd->cookie =  target_node->cookie;
			node_prio.sched_policy = target_node->sched_policy;
			node_prio.prio = target_node->min_priority;
			binder_transaction_priority(current, t, node_prio,
						    target_node->inherit_rt);
			cmd = BR_TRANSACTION;
		}
		trd->code = t->code;            // t->code 是 ADD_SERVICE_TRANSACTION
		trd->flags = t->flags;
		trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid);
        /*
         * t->buffer->user_data 是拷贝到 servicemanager 映射地址 + data
         * 该数据就是对应的 Binder 服务数组的数据,将 trd 数据传递给 servicemanager
         */
		trd->data_size = t->buffer->data_size;
		trd->offsets_size = t->buffer->offsets_size;
		trd->data.ptr.buffer = (uintptr_t)t->buffer->user_data;
		trd->data.ptr.offsets = trd->data.ptr.buffer +
					ALIGN(t->buffer->data_size,
					    sizeof(void *));
        
        // 将指令 BR_TRANSACTION 拷贝到用户空概念
        if (put_user(cmd, (uint32_t __user *)ptr)) {
			if (t_from)
				binder_thread_dec_tmpref(t_from);

			binder_cleanup_transaction(t, "put_user failed",
						   BR_FAILED_REPLY);

			return -EFAULT;
		}
		ptr += sizeof(uint32_t);
        // 将 binder_transaction_data_secctx 数据拷贝到用户数组
		if (copy_to_user(ptr, &tr, trsize)) {
			if (t_from)
				binder_thread_dec_tmpref(t_from);

			binder_cleanup_transaction(t, "copy_to_user failed",
						   BR_FAILED_REPLY);

			return -EFAULT;
		}
        ...
    }
done:
    // 在 if 满足的条件下, 需要再申请一个 binder 线程,设置 BR_SPAWN_LOOPER 属性
	if (proc->requested_threads == 0 &&
	    list_empty(&thread->proc->waiting_threads) &&
	    proc->requested_threads_started < proc->max_threads &&
	    (thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
	     BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
	     /*spawn a new thread if we leave this out */) {
		proc->requested_threads++;
		binder_inner_proc_unlock(proc);
		binder_debug(BINDER_DEBUG_THREADS,
			     "%d:%d BR_SPAWN_LOOPER\n",
			     proc->pid, thread->pid);
		if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
			return -EFAULT;
		binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
	}
    return 0;
}

binder_thread_read() 结束后,会回到 binder_ioctl_write_read() 函数,然后紧接着,该函数也会走到 return 处。然后本次系统调用就可以返回了。

返回的地方就是 native 层的 servicemanager 进程的 loop 处

// frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
    ...
    for (;;) {
        ...
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ...
    }
}

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    ...
    // 循环取出指令,此处是 BR_TRANSACTION
    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        switch(cmd) {
        ...
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            // func 是外部传入的 svcmgr_handler() 
            if (func) {
                ...
                // 从 txn 取出 data 数据,即 service 注册的内容
                bio_init_from_txn(&msg, txn);
                // 即 svcmgr_handler(bs, txn, &msg, &reply)
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    // 执行完添加操作后,从该处返回
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }            
        }
        }
    }
}

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    ...
    switch(txn->code) {
    case SVC_MGR_ADD_SERVICE:
        // 取第一个参数,是一个字符串表示的服务名,
        // 在此处是 "android.hardware.broadcastradio@2.0::IBroadcastRadio"
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }

        // hal 层服务进程句柄本质也是一个 uint 型数据
        handle = bio_get_ref(msg);  // 取出 binder 对象数组
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        dumpsys_priority = bio_get_uint32(msg);
        // 添加服务
        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
                           txn->sender_pid))
            return -1;
        break;
       
    }
}

int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
    struct svcinfo *si;

    // 先根据 selinux 权限查看是否能注册
    if (!svc_can_register(s, len, spid, uid)) {
        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
             str8(s, len), handle, uid);
        return -1;
    }

    // 根据服务名查看链表中有没有服务,如果有则更新,没有则新增
    si = find_svc(s, len);
    if (si) {
        if (si->handle) {
            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
                 str8(s, len), handle, uid);
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } else {
        // 分配类型,记录相关信息,并头插入到 svclist 链表中
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {
            ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
                 str8(s, len), handle, uid);
            return -1;
        }
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->dumpsys_priority = dumpsys_priority;
        si->next = svclist;
        svclist = si;
    }
    binder_acquire(bs, handle);
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

Binder 服务对象在 Parcel 如何存储的?

在 Parcel.cpp 文件中

// system/libhwbinder/Parcel.cpp
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    // binder 不空时
    if (binder != NULL) {
        // localBinder 默认返回是空
        BHwBinder *local = binder->localBinder();
        if (!local) {
            // 如果是代理对象,记录 handle 值,设置类型为 BINDER_TYPE_HANDLE
            BpHwBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.hdr.type = BINDER_TYPE_HANDLE;
            obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
            // 如果是本地对象, binder 存该对象的弱引用,cookie 存该对象的地址值
            // 本地对象的 handle 值,该值在 binder 驱动中算出来
            int policy = local->getMinSchedulingPolicy();
            int priority = local->getMinSchedulingPriority();

            obj.flags = priority & FLAT_BINDER_FLAG_PRIORITY_MASK;
            obj.flags |= FLAT_BINDER_FLAG_ACCEPTS_FDS | FLAT_BINDER_FLAG_INHERIT_RT;
            obj.flags |= (policy & 3) << FLAT_BINDER_FLAG_SCHEDPOLICY_SHIFT;
            if (local->isRequestingSid()) {
                obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
            }
            obj.hdr.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        obj.hdr.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }
}

举个例子说明代理对象和本地的对象的区别,如果我要添加一个 hal 层服务到 servicemanager 中,那么传过去的是 Binder 本地对象;而如果一个客户端来拿 hal 层服务,那么拿到的就是 hal 层进程的代理句柄 BpBinder,这个代理对象会被加入到 Parcel 类中

Binder 对象使用 flat_binder_object 结构体保存,使用 bio_get_ref() 函数取出来

// frameworks/native/cmds/servicemanager/binder.c
uint32_t bio_get_ref(struct binder_io *bio)
{
    struct flat_binder_object *obj;

    obj = _bio_get_obj(bio);
    if (!obj)
        return 0;

    // 此处的 type 已经被 binder_transaction() 转换成 BINDER_TYPE_HANDLE
    // 具体的转换函数在 binder_translate_binder()
    if (obj->hdr.type == BINDER_TYPE_HANDLE)
        return obj->handle;

    return 0;
}

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply,
			       binder_size_t extra_buffers_size)
{
    ...
    ret = binder_translate_binder(fp, t, thread);
    ...
}

static int binder_translate_binder(struct flat_binder_object *fp,
				   struct binder_transaction *t,
				   struct binder_thread *thread)
{
    ...
    if (fp->hdr.type == BINDER_TYPE_BINDER)
		fp->hdr.type = BINDER_TYPE_HANDLE;
	else
		fp->hdr.type = BINDER_TYPE_WEAK_HANDLE;
    ...
}

到此,Hal 层的 broadcastradiohao@2.0 进程已经注册到 servicemanager 中了,那么接下来就是回复了。

注册返回

ServiceManager 返回

在 binder_parse() 函数中,执行完函数后,调用 binder_send_reply() 返回

void binder_send_reply(struct binder_state *bs,
                       struct binder_io *reply,
                       binder_uintptr_t buffer_to_free,
                       int status)
{
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;
    // 构建两个返回指令,一个是释放指令,回收刚才分配的 binder_buffer 内存
    // 一个是回复指令,看这个回复的以后的逻辑操作
    data.cmd_free = BC_FREE_BUFFER;
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY;
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    // 因为 addservice 不用返回数据,所以直接走 else 逻辑
    // 如果是 getservice 的话,status 就是 true
    if (status) {
        data.txn.flags = TF_STATUS_CODE;
        data.txn.data_size = sizeof(int);
        data.txn.offsets_size = 0;
        data.txn.data.ptr.buffer = (uintptr_t)&status;
        data.txn.data.ptr.offsets = 0;
    } else {
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }

    // 调用 iotcl,只由 write_size
    binder_write(bs, &data, sizeof(data)); 
}

binder_write() 函数已经做了介绍,就是将传入的数据使用 BINDER_WRITE_READ 指令通过 iotcl 调用到 binder 内核中的 binder_ioctl 中

Binder 内核返回

进入系统调用后,就进入 binder_ioctl() -> binder_ioctl_write_read() ->binder_thread_write()

static int binder_thread_write(struct binder_proc *proc,
			struct binder_thread *thread,
			binder_uintptr_t binder_buffer, size_t size,
			binder_size_t *consumed)
{
    ...
    	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, 0);
			break;
		}
}

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply,
			       binder_size_t extra_buffers_size)
{
    ...
    {
    	if (reply) {
            binder_inner_proc_lock(proc);
            in_reply_to = thread->transaction_stack;    // transaction_stack 保存了本次通信的 binder_transaction 事务
            ...
            // 取出下一次事务的信息
            thread->transaction_stack = in_reply_to->to_parent;
            // 取出本次通信事务的具体信息,通过 binder_thread 获的目标进程的 binder_proc
            target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
            ...
            target_proc = target_thread->proc;
            target_proc->tmp_ref++;
        }
	}
    ...
    // to->from 置空,本次事务完成,不需要再唤醒其他进程
    if (!reply && !(tr->flags & TF_ONE_WAY))
		t->from = thread;
	else
		t->from = NULL;
    ...
	tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
	t->work.type = BINDER_WORK_TRANSACTION;
	if (reply) {
        // 将 tcomplete 这个 binder_work 进程存到 binder_thread todo list 中
		binder_enqueue_thread_work(thread, tcomplete);
		binder_inner_proc_lock(target_proc);

        // 获取上一个事务数据
        binder_pop_transaction_ilocked(target_thread, in_reply_to);

        // 使用尾插入将当前事务通信加入到目标进程,也即是 hal 层调用到 binder 内核的那个进程
		binder_enqueue_thread_work_ilocked(target_thread, &t->work);
		binder_inner_proc_unlock(target_proc);

        // 唤醒目标进程
		wake_up_interruptible_sync(&target_thread->wait);
	}
}

以上操作完成后,本次 binder_ioctl 操作也就结束了,系统调用返回,servicemanager 进程会继续在函数 binder_loop() 中继续执行到 ioctl,然后 binder 内核这边继续阻塞到 binder_thread_read() 中的 binder_wait_for_work() 中,等带下一次的唤醒

然后唤醒的上层 broadcastradiohal 在 binder 中的任务进程。

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)
{
    ...
	if (non_block) {
		if (!binder_has_work(thread, wait_for_proc_work))
			ret = -EAGAIN;
	} else {
		ret = binder_wait_for_work(thread, wait_for_proc_work); // 从这里开始继续执行
	}

    while (1) {
        ...
        switch (w->type) {
        ...
        // 这次走的是 BINDER_WORK_TRANSACTION_COMPLETE 分支
        // 因为在 servicemanager 回来时,构造了一个 tcomplete 的 binder_work 放入到当前进程的 todo 链表中
		case BINDER_WORK_TRANSACTION_COMPLETE: {
            // 设置 BR_TRANSACTION_COMPLETE 状态放入到用户共享空间中
			cmd = BR_TRANSACTION_COMPLETE;
			if (put_user(cmd, (uint32_t __user *)ptr))
				return -EFAULT;
			ptr += sizeof(uint32_t);

		} break;
        }
		if (t->buffer->target_node) {
            // 只有 binder_transaction 才会拿到 target_node
		} else {
			trd->target.ptr = 0;
			trd->cookie = 0;
			cmd = BR_REPLY;
		}
    }
}

如上所示:在 reply 的时候,Binder 内核在 read_buffer 中写了 BR_TRANSACTION_COMPLETE + BR_REPLY + binder_transaction_data_secctx(这个数据什么时候拷贝的,没理解)

Hal 层进程用户空间的 reply

上述流程走完,就回到 hal 层进程的用户空间,也就是

// system/libhwbinder/IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    do {
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;

    }
}

该函数会在用户进程回来后,返回到 waitForResponse()

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;   // 回来后没有 error ,继续往下走
        cmd = (uint32_t)mIn.readInt32();    // cmd 就是 binder 内核写在返回数据里的

        // 两条指令,一个 BR_TRANSACTION_COMPLETE 一个 BR_REPLY
        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            // 如果设置了 oneway,那么下面两个参数就是空,直接返回
            // 因为当前走的流程不是 oneway,所以继续往下走
            if (!reply && !acquireResult) goto finish;
            break;
        case BR_REPLY:      // 处理 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;

                // reply 不为空,关注以下逻辑
                if (reply) {
                    // tr.flags 来自 servicemanager 中 binder_send_reply() 中,flags = 0
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        // 从 servicemanger 传回来的数据都会放到 Parcel reply 中
                        // 本地是没有存放,但是其他类型请求可能会有
                        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(NULL,
                            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(NULL,
                        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;
                }
            }        
        }
    }
}

剩下的都是任务执行结束后的函数返回过程了,这里就不再赘述。

总结

  1. 初始化过程:ProcessState 初始化,调用 open 打开系统节点,然后调用 mmap 映射一块用户空间虚拟地址到内核
  2. 通信线程等待:调用 startThreadPool(),IPCThreadState 初始化,进入循环等待
  3. 客户端获得服务端代理:使用 ProcessState::self()->getContextObject(nullptr) 方法获取 servicemanager 的对立对象
  4. 调用代理对象的添加函数:调用代理对象的 addservice() 函数进入 IPCThreadState 的 talkWithDriver() 进入 binder
    内核中
  5. Binder 内核处理:Binder 内核创建一次进程通信事务,将上层传递过来的数据拷贝到 servicemanager 映射的用户空间虚拟地址对应的物理内存中,然后唤醒 servicemanager 进程,然后客户端调用进程挂起
  6. 服务端内核处理:servicemanager 进程唤醒,取出刚才的通信事务,将刚才内核拷贝过来的数据拷贝到 read_buffer 中,然后回来 servicemanager 用户空间,执行上层代码
  7. 服务端用户态处理:servicemanager 将传递过来的 Binder 服务添加到 svclist 链表中,完成任务,然后回复,返回 binder 内核,创建一个进程通信服务,将操作的结果数据写入,接着唤醒对应的调用进程,继续陷入阻塞
  8. 客户端返回:hal 层进程回到用户空间,将返回的数据保存,然后本次调用结束。
posted @ 2024-06-14 13:36  王清河  阅读(58)  评论(0编辑  收藏  举报