Android IPC机制—Binder的工作机制

Android——Binder机制 1.简介 Android系统中,涉及到多进程间的通信底层都是依赖于Binder IPC机制。 例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于Binder IPC。不仅于 此,整个Android系统架构中,大量采用了Binder机制作为IPC(进程间通信,Interprocess Communication)方案。 也存在部分其他的IPC方式,如管道、SystemV、Socket等 为什么使用Binder: 性能方面: Binder相对于传统的Socket方式,更加高效 阅读详情

Binder是一种进程间通信机制

Binder架构

  • Binder通信机制采用C/S架构


  • Binder框架中主要涉及到4个角色Client、Server、Service Manager及Binder驱动,其中Client、Server、Service Manager运行在用户空间,Binder驱动运行在内核空间
  • Client代表客户端进程,Server代表客户端进程提供各种服务,如音视频等
  • Service Manager用来管理各种系统服务
  • Binder驱动提供进程间通信的能力
  • 用户空间的Client、Server、ServiceManager通过open、mmap和ioctl等标准文件操作(详见Unix环境编程)来访问/dev/binder,进而实现进程间通信

基础数据结构


Binder驱动

/kernel/drivers/staging/android/binder.c
device_initcall(binder_init);

设备初始化时候会调用binder_init进行binder驱动初始化

/kernel/drivers/staging/android/binder.c
//绑定binder驱动操作函数
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,
};

//创建misc类型的驱动
static struct miscdevice binder_miscdev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "binder",
    .fops = &binder_fops//绑定binder驱动操作函数
};

//binder驱动初始化
static int __init binder_init(void)
{
    int ret;

    binder_deferred_workqueue = create_singlethread_workqueue("binder");
    if (!binder_deferred_workqueue)
        return -ENOMEM;

    //创建目录/binder
    binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
    if (binder_debugfs_dir_entry_root)
        //创建目录/binder/proc
        binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
                         binder_debugfs_dir_entry_root);
    //注册binder驱动
    ret = misc_register(&binder_miscdev);
    //创建其他文件
    if (binder_debugfs_dir_entry_root) {
        //创建文件/binder/proc/state
        debugfs_create_file("state",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    NULL,
                    &binder_state_fops);
        //创建文件/binder/proc/stats
        debugfs_create_file("stats",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    NULL,
                    &binder_stats_fops);
        //创建文件/binder/proc/transactions
        debugfs_create_file("transactions",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    NULL,
                    &binder_transactions_fops);
        //创建文件/binder/proc/transaction_log
        debugfs_create_file("transaction_log",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    &binder_transaction_log,
                    &binder_transaction_log_fops);
        //创建文件/binder/proc/failed_transaction_log
        debugfs_create_file("failed_transaction_log",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    &binder_transaction_log_failed,
                    &binder_transaction_log_fops);
    }
    return ret;
}

初始化主要做了两件事情

  • 初始化存储binder存储信息的目录
  • 创建binder设备,并绑定操作函数如binder_open、binder_mmap、binder_ioctl等
  • 设备启动时候,会调用binder_init,主要做两件事情
  • 1.创建/binder/proc目录,之后在这个目录下创建state、stats、transactions、transaction_log、failed_transaction_log文件夹,分别存储进程通信的各种数据
  • 2.注册驱动,并绑定文件操作函数binder_open、binder_mmap、binder_ioctl等,之后就可以通过RPC机制去访问binder驱动

Native层级的Binder结构


Binder通信机制

Binder进程与线程

ServiceManager启动

预备知识补充

ServiceManager启动流程主要分为三个流程
1.以系统服务形式启动service_manager,之后通过在binder_open函数打开驱动设备,驱动层相应的就会创建service_manager对应的binder_proc,并且这是个特殊的service
2.调用binder_become_context_manager通过ioctl调用内核中的binder_ioctl,经过一系列处理后,binder驱动会将这个特殊的binder_node存到静态指针binder_context_mgr_node

static struct binder_node *binder_context_mgr_node;
...
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
    ...
    //注意这里后续两个参数都是0
    binder_context_mgr_node = binder_new_node(proc, 0, 0);
    ...
}
...

3.调用binder_loop进入循环解析的过程

int main(int argc, char** argv){
    ...
    //进入循环,等待或处理Client进程的通信请求
    binder_loop(bs, svcmgr_handler);
    ...
}

这里指定循环处理函数为svcmgr_handler,后续再仔细分析这个函数,先看binder_loop实现

void binder_loop(struct binder_state *bs, binder_handler func)
{
    ...
    //通信数据
    struct binder_write_read bwr;
    
     bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(uint32_t));
    
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
        
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        ...
        //解析
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ...
    }
    
}

int binder_write(struct binder_state *bs, void *data, size_t len)
{
    struct binder_write_read bwr;
    int res;

    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    ...
    return res;
}
  • 首先创建一个binder_write_read结构体,然后通过binder_write向Binder驱动写入命令协议BC_ENTER_LOOPER,注意这个理输出缓冲区是没有数据的,binder驱动经过一系列处理进入循环状态,之后通过一个死循环来不断的从Binder驱动读取数据,之后交由binder_parse去解析各种协议数据,后续再分析细节
  • Binder驱动是如何处理交互细节的,我们来看下binder_ioctl_write_read的实现
static int binder_ioctl_write_read(struct file *filp,
                unsigned int cmd, unsigned long arg,
                struct binder_thread *thread)
{
    ...
    //从文件句柄取出进程信息
    struct binder_proc *proc = filp->private_data;
    //命令协议
    unsigned int size = _IOC_SIZE(cmd);
    ...
    struct binder_write_read bwr;
    //取出bwr进程通信协议载体
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ...
    }
    //如果有写入数据,就交由binder_thread_write去处理,之后
    //通过copy_to_user将数据返还给用户空间
    if (bwr.write_size > 0) {
        ret = binder_thread_write(proc, thread,
                      bwr.write_buffer,
                      bwr.write_size,
                      &bwr.write_consumed);
        ...
        if (ret < 0) {
            bwr.read_consumed = 0;
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ...
            goto out;
        }
    }
    
    //如果有输出数据,则调用binder_thread_read解析,
    //之后判断进程的事务队里是否为空,如果不为空就等待执行
    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 (!list_empty(&proc->todo))
            wake_up_interruptible(&proc->wait);
        if (ret < 0) {
            //将写出数据返还给用户空间
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ...
            goto out;
        }
    }
    ...
out:
    return ret;
}
  • 至于binder_thread_write与binder_thread_read则是处理命令协(binder_driver_command_protocol)与返回协议(binder_driver_return_protocol )详见/drivers/staging/android/binder.h

ServiceManager注册服务

  • service的注册流程如上图,这里以media_server的注册为例子去看代码
/frameworks/av/services/mediadrm/mediadrmserver.rc
service mediadrm /system/bin/mediadrmserver
    class main
    user media
    group mediadrm drmrpc
    ioprio rt 4
    writepid /dev/cpuset/foreground/tasks
  • 可以看到以用户权限启动mediadrm服务,文件位于/system/bin/mediadrmserver
  • 接下来看main_mediadrmserver.cpp
/frameworks/av/services/mediadrm/mediadrmserver.cpp
int main()
{
    ...
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    ...
    MediaDrmService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}
  • main()中主要做了两件事情:
    1.初始化MediaDrmService
    2.线程池初始化
    先看第一个
/frameworks/av/services/mediadrm/MediaDrmService.cpp
...
void MediaDrmService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.drm"), new MediaDrmService());
}
...
  • 这里面主要通过defaultServiceManager()获取一个BpServiceManager指针然后调用addService,注意这里传入的两个参数“media.drm”和一个MediaDrmService对象
ServiceManager代理对象的获取
  • 先来看defaultServiceManager()调用
/frameworks/native/libs/binder/Static.cpp
...
sp<IServiceManager> gDefaultServiceManager;
...

/frameworks/native/libs/binder/ISerivceManager.cpp
...
sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) 
        return gDefaultServiceManager;
    {
        ...
        while (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
                ...
        }
    }

    return gDefaultServiceManager;
}
...
  • gDefaultServiceManager就是一个IServiceManger的指针
  • 首次获取时候一定是通过interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL))这一系列method调用获取的,一步步分析
  • 先看ProcessState::self()
/frameworks/native/libs/binder/ProcessState
...
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    //注意这里的文件name
    gProcess = new ProcessState("/dev/binder");
    return gProcess;
}
...
  • 这个类构造一定持有打开/dev/binder的句柄,不信你看构造声明
//这里是cpp构造函数形式,就是成员变量赋值
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(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        //注意这里分配的BINDER_VM_SIZE为1016kb,具体见宏定义处
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            ...
            close(mDriverFD);
            mDriverFD = -1;
            mDriverName.clear();
        }
    }
    ...
}
  • 再来看getContextObject
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    //注意这里传入的值为0
    return getStrongProxyForHandle(0);
}

...
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    ...
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        ...
        b = BpBinder::create(handle);
        e->binder = b;
        if (b) e->refs = b->getWeakRefs();
        result = b;
    }else{
        ...
    }
    return result;
}
  • getContextObject()内部是调用getStrongProxyForHandle(0)来获取一个IBinder指针(这里0其实就是为了后续查找之前ServiceManager启动注册那个特殊的Service组件),可以看到其实这里创建的是一个BpBinder对象,并且他的句柄值是0
  • 我们来看BpBinder的相关调用
frameworks/native/libs/binder/BpBinder.cpp
//handle句柄值 与binder驱动中的binder引用对象进行关联
BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
    //注意这里传入的是0
    : mHandle(handle)
    //注意这个值为1
    , mAlive(1)
    , mObitsSent(0)
    , mObituaries(NULL)
    , mTrackedUid(trackedUid)
{
    ...
    IPCThreadState::self()->incWeakHandle(handle, this);
}

BpBinder* BpBinder::create(int32_t handle) {
    ...
    return new BpBinder(handle, trackedUid);
}
  • 回到defaultServiceManager(),最后interface_cast<IServiceManager>(BpBinder(0))实际上转换成了这个,这个在哪里定义呢?
/frameworks/native/include/binder/IInterface.h
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
  • 发现他是个内联模板函数,实际上调用的是IServiceManager::asInterface(BpBinder(0)),那么IServiceManager::asInterface在哪里定义呢?
/frameworks/native/libs/binder/IServiceManager.cpp
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

看上面这个宏定义,实际定义在
/frameworks/native/include/binder/IInterface.h

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       
    const ::android::String16 I##INTERFACE::descriptor(NAME);           
    const ::android::String16&                                          
        I##INTERFACE::getInterfaceDescriptor() const {              
        return I##INTERFACE::descriptor;                                
    }                                                                   
    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              
            const ::android::sp<::android::IBinder>& obj)               
    {                                                                   
        ::android::sp<I##INTERFACE> intr;                               
        if (obj != NULL) {                                              
            intr = static_cast<I##INTERFACE*>(                          
                obj->queryLocalInterface(                               
                        I##INTERFACE::descriptor).get());               
            if (intr == NULL) {                                         
                intr = new Bp##INTERFACE(obj);                          
            }                                                           
        }                                                               
        return intr;                                                    
    }  
  • 带入转换下,发现我们拿到的其实就是一个BpServiceManager
  • 接下来我们来看后续的调用
BpServiceManager#addService
virtual status_t addService(const String16& name, const sp<IBinder>& service,bool allowIsolated, int dumpsysPriority) {
        //这里data表示要写入的数据,reply表示返回的数据
        Parcel data, reply;
        //存储描述符"android.os.IServiceManager"    
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        //存储服务名字"media.drm"     
        data.writeString16(name);
        //存储服务MediaDrmService
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        data.writeInt32(dumpsysPriority);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
  • 这里实际上把上一步传入的数据通过Parcel存起来,然后调用remote()获取一个BpBinder然后调用其transact,传入的code为ADD_SERVICE_TRANSACTION,经过包装后data中的数据长这样子
  • 记下来我们去看BpBinder#transact
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.
    //构造中mAlive=1,所以这里会走进if
    if (mAlive) {
        //这里调用的是IPCThreadState#transact
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}
  • 前面ServiceManager代理对象获取BpBinder时候,mHandle为0,code为ADD_SERVICE_TRANSACTION,data存储binder信息,reply存储要返回的信息,flags查看method定义默认参数为0
  • 接下来分析IPCThreadState#transact
    /frameworks/native/libs/binder/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通信请求
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    ...
    //同步or异步,这里是同步调用
    if ((flags & TF_ONE_WAY) == 0) {
        ...
        if (reply) {
            //向Binder驱动发起BC_TRANSACTION
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
            ...
        }
        ...
    }else{
        err = waitForResponse(NULL, NULL);
    }
    return err;
}
  • 上面首先将flags与TF_ACCEPT_FDS做或操作,表示接收文件描述符
  • 之后调用writeTransactionData将数据封装成一个BC_TRANSACTION命令协议,这里是同步调用切需要返回,所以执行到的是waitForResponse(reply),接下来分别来看writeTransactionData、waitForResponse的实现
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
    {
    //对应内核中要求io携带binder_transaction_data结构体
    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;
}
  • 这里主要是创建一个binder_transaction_data,初其始化后将要传输的数据写入到mOut缓冲区中,最终整个数据长这样子
  • 数据封装完成以后,我们来看waitForResponse的实现
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
        //从输出缓冲区取出返回协议命令
        cmd = (uint32_t)mIn.readInt32();
        ...
    }
    ...
    return err;
}
  • 这里可以是一个死循环,不断的通过talkWithDriver去跟binder驱动通信,然后从输出缓冲区中取出返回协议然后处理返回协议,这里先不看具体的协议处理,先来看talkWithDriver的实现
//默认doReceive = true
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    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;
    }
    ...
    // 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;
    status_t err;
    do{
        ...
        //这里通过io想驱动写入一个binder_write_read结构体
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
    } while (err == -EINTR);
    
    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else {
                mOut.setDataSize(0);
                processPostWriteDerefs();
            }
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        ...
        return NO_ERROR;
    }

    return err;
}
  • 这里主要通过io控制命令向Binder驱动写入一个type为BINDER_WRITE_READ,data为binder_write_read,其输出缓冲区为前面mOut中写入的数据
  • 接下来的操作就转到Binder驱动中进行了,需要记住,Clinet进程此时执行到的位置
/platform/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);
    ...
    //这里根据进程找到对应的thread,如果没找到就创建一个
    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;
    ...
}
  • Binder驱动中对应的binder_ioctl()会调用,之后会处理cmd为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;
    //cmd信息
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    //cmd校验
    if (size != sizeof(struct binder_write_read)) {
        ret = -EINVAL;
        goto out;
    }
    //从用户空间中取出binder_write_read结构体
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    ...
    //输出缓冲区有数据就处理输出缓冲区
    if (bwr.write_size > 0) {
        //这里是真正处理输出缓冲数据的func
        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) {
        //这里是真正处理输出缓冲数据的func
        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);
        //如果进程todo队里不为空,说明有事务正在处理,需要等待处理
        if (!list_empty(&proc->todo))
            wake_up_interruptible(&proc->wait);
        if (ret < 0) {
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    ...
    //将数据copy回用户空间
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
out:
    return ret;
}
  • 前面调用可知,输出缓冲区是有数据,输入缓冲区是没有数据的,所以上面方法执行流程应该是,先调用binder_thread_write去处理输出缓冲区
static int binder_thread_write(struct binder_proc *proc,
            struct binder_thread *thread,
            binder_uintptr_t binder_buffer, size_t size,
            binder_size_t *consumed)
{
    uint32_t cmd;
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;
    
    while (ptr < end && thread->return_error == BR_OK) {
        //根据cmd取出消费的数据偏移地址
        if (get_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
        ...
        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;   
}   
  • 这里是取出cmd,然后处理BC_TRANSACTION时候,再讲binder_transaction_data取出,之后交由binder_transaction去处理
  • binder_transaction比较长,其实主要分为三个部分
  • 1.初始化目标线程进程
  • 2.封装返回数据binder_transaction_data
  • 3.为binder_transaction_data分配合适的线程or进程
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;
    ...
    uint32_t return_error;
    ...
    //如果是reply走if分支,否则走else分支,这里走else
    if (reply) {
        ...
    }else{
        //根据句柄找对应的binder_ref、binder_node
        if (tr->target.handle) {
            struct binder_ref *ref;
            ref = binder_get_ref(proc, tr->target.handle);
            ...
        else{
            //handle=0,则需要找指向service_manager的binder_node
            target_node = binder_context_mgr_node;
            ...
        }
        ...
        //根据binder_node找到对应的进程binder_proc,这里也就是service_manager
        target_proc = target_node->proc;
        ...
        //如果是同步请求,尝试寻找一个在等待其他事物执行的线程,tips优化调度
        if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
            struct binder_transaction *tmp;
            tmp = thread->transaction_stack;
            ...
            //找到一个等待别的事务完成的依赖线程
            while (tmp) {
                if (tmp->from && tmp->from->proc == target_proc)
                    target_thread = tmp->from;
                tmp = tmp->from_parent;
            }
        }
    }
    //有空闲线程就是用空闲线程的等待队列,否则使用进程的事物队列
    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;
    }
    ...
    //创建binder_transaction结构体,BINDER_WORK_TRANSACTION
    //用于向目标进程发送数据
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    ...
    binder_stats_created(BINDER_STAT_TRANSACTION);
    ...
    //创建binder_work结构体,BINDER_STAT_TRANSACTION_COMPLETE
    //便于向源进程返回数据处理结果
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    ...
    binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
    ...
    //初始化t
    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;
    //code ADD_SERVICE_TRANSACTION
    t->code = tr->code;
    //flag = TF_ACCEPT_FLAGS
    t->flags = tr->flags;
    //优先级
    t->priority = task_nice(current);
    ...
    //缓冲区
    t->buffer = binder_alloc_buf(target_proc, tr->data_size,
        tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    ...
    t->buffer->allow_user_free = 0;
    t->buffer->debug_id = t->debug_id;
    t->buffer->transaction = t;
    t->buffer->target_node = target_node;
    ...
    //为t分配内核缓冲区
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);
    
    offp = (binder_size_t *)(t->buffer->data +
                 ALIGN(tr->data_size, sizeof(void *)));
     //数据copy
    if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
               tr->data.ptr.buffer, tr->data_size)) {
        ...
        goto err_copy_data_failed;
    }
    if (copy_from_user(offp, (const void __user *)(uintptr_t)
               tr->data.ptr.offsets, tr->offsets_size)) {
        ...
        goto err_copy_data_failed;
    }
    ...
    
    //处理Binder请求,内核中很多都是地址起止位置操作
    off_end = (void *)offp + tr->offsets_size;
    off_min = 0;
    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;
        ...
        //前面存储的MediaDrmService信息
        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);
                //如果是首次就创建新的binder_node
                if (node == NULL) {
                node = binder_new_node(proc, fp->binder, fp->cookie);
                ...
                //设定线程优先级
                node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
                //设置是否接收文件描述符
                node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
                }
                ...
                //如果是首次就创建对应的binder_ref对象
                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;
                }
                //修改flat_binder_objec.type
                if (fp->type == BINDER_TYPE_BINDER)
                    fp->type = BINDER_TYPE_HANDLE;
                else
                    fp->type = BINDER_TYPE_WEAK_HANDLE;
                //设置句柄
                fp->handle = ref->desc;
                //增加binder_ref的引用计数
                binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                           &thread->todo);
               ...
            }break;
            ...
        }
    }
    
    //分配事务t的要进入那个栈
    if (reply) {
        ...
        binder_pop_transaction(target_thread, in_reply_to);
    } else if (!(t->flags & TF_ONE_WAY)) {
        ...
        t->need_reply = 1;
        t->from_parent = thread->transaction_stack;
        thread->transaction_stack = t;
    } else {
        ...
        if (target_node->has_async_transaction) {
            target_list = &target_node->async_todo;
            target_wait = NULL;
        } else
            target_node->has_async_transaction = 1;
    }
    //将binder_transaction_data指针t的类型修改为BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    //添加到target_list队列尾部
    list_add_tail(&t->work.entry, target_list);
    //将binder_work指针tcomplete.type置为BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    list_add_tail(&tcomplete->entry, &thread->todo);
    //这里有两个执行分支
    //1.处理类型为BINDER_WORK_TRANSACTION的binder_transaction_data
    //2.处理类型为BINDER_WORK_TRANSACTION_COMPLETE的binder_work
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;
    ...
}
  • 经过上面func以后,binder驱动中就会为MediaDrmService创建对应的binder_node并加入到整个Binder实体对象的红黑树中,接着会分别向Client进程、ServiceManager发送一个BINDER_WORK_TRANSACTION_COMPLETE的binder_work及BINDER_WORK_TRANSACTION的binder_transaction
  • 至此,源线程thread、target_proc或者target_thread会并发的去执行各自todo队列中的任务
  • 先来看源线程,回到binder_ioctl_write_read中,接下来要处理输入缓冲区,对应的调用binder_thread_read
static int binder_thread_read(struct binder_proc *proc,
                  struct binder_thread *thread,
                  binder_uintptr_t binder_buffer, size_t size,
                  binder_size_t *consumed, int non_block)
{
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;

    int ret = 0;
    int wait_for_proc_work;
    ...
    //线程唤醒
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        //检查工作队列,并将待处理项赋值给w
        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;
        }
        switch (w->type) {
            ...
            case BINDER_WORK_TRANSACTION_COMPLETE: {
                cmd = BR_TRANSACTION_COMPLETE;
                if (put_user(cmd, (uint32_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(uint32_t);
    
                binder_stat_br(proc, thread, cmd);
                ...
                //删除binder_work,并释放资源
                list_del(&w->entry);
                kfree(w);
                binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
            } break;
        }
done:
    *consumed = ptr - buffer;
    ...
    return 0;
}
  • 这里返回一个BR_TRANSACTION_COMPLETE协议,之后会经过一些列调用会回到IPCThreadState#waitForResponse中
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    ...
    uint32_t cmd;
    int32_t err;

    while (1) {
        ...
        cmd = (uint32_t)mIn.readInt32();
        ...
        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;
        }
        ...
    }
finish:
    ...
    return error;
}
  • IPCThreadState::waitForResponse对于BR_TRANSACTION_COMPLETE处理比较简单,就直接返回了
  • 我们来看下target_proc即ServiceManager是怎么接收处理BINDER_WORK_TRANSACTION类型的binder_transaction的,假设ServiceManager之前没有通信,那么他就在Binder驱动中一直等待事务的到来,现在有事务了那么对应的就会调用binder_read_thread
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;

        //检查工作队列,并将待处理项赋值给w
        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;
        }
        ...
        switch (w->type) {
        case BINDER_WORK_TRANSACTION: {
            t = container_of(w, struct binder_transaction, work);
        } break;
        ...
        }
    //返回协议的处理,现在target_node指向的是binder_context_mgr_node
        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);
            //修改binder驱动中对应proc的线程优先级(模拟Client进程的线程优先级)
            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 {
            ...
        }
        //拷贝code与flags,
        //注册服务过程中这里是ADD_SERVICE_TRANSACTION、TF_ACCEPT_FDS
        tr.code = t->code;
        tr.flags = t->flags;
        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 {
            ...
        }
        //Binder驱动程序分配给进程的内核缓冲区同时,
        //映射了用户的内核地址、用户空间地址
        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);
        //直接操作offsets
        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);
        ...
        list_del(&t->work.entry);
        t->buffer->allow_user_free = 1;
        //cmd = BR_TRANSACTION && 不是正在处理异步通信请求
        //就需要等待该同步进程通信完以后再进行下一步的操作
        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
}       
  • 这里实际上是返回一个BR_TRANSACTION协议,并且将之前通过binder_transaction传输的数据封装到binder_transaction_data中,由于在service_manager启动中,进入binder_loop时候指定的函数引用为svcmgr_handler,binder_loop中会循环通过ioctl控制命令去与内核交互数据,binder_parse用于解析数据
platform/frameworks/native/cmds/servicemanager/binder.c
int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;
    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        ...
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = 
                (struct binder_transaction_data *) ptr;
            ...
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
                bio_init(&reply, rdata, sizeof(rdata), 4);
                bio_init_from_txn(&msg, txn);
                //调用svcmgr_handler去处理
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    //返回注册的结果给binder驱动
                    binder_send_reply(bs, &reply, 
                            txn->data.ptr.buffer, res);
                }
            }
            break;
        }   
}
  • 这其中有三个结构体binder_io主要存储数据传输,定义如下:
struct binder_io
{
    char *data;            /* pointer to read/write from */
    binder_size_t *offs;   /* array of offsets */
    size_t data_avail;     /* bytes available in data buffer */
    size_t offs_avail;     /* entries available in offsets array */

    char *data0;           /* start of data buffer */
    binder_size_t *offs0;  /* start of offsets buffer */
    uint32_t flags;
    uint32_t unused;
};
  • binder_parse中先通过bio_init去初始化reply,然后通过bio_init_from_txn去初始化msg,就是数据对齐的过程及flag设置,这里不再细述
  • 我们重点关注func,也就是svcmgr_handler,先来回顾前面数据那张图


  • 接下来再来看svvmgr_handler的实现
  • uint16_t svcmgr_id[] = {
        'a','n','d','r','o','i','d','.','o','s','.',
        'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r'
    };
    ...
    int svcmgr_handler(struct binder_state *bs,
                       struct binder_transaction_data *txn,
                       struct binder_io *msg,
                       struct binder_io *reply)
    {
        struct svcinfo *si;
        uint16_t *s;
        size_t len;
        uint32_t handle;
        uint32_t strict_policy;
        int allow_isolated;
        ...
        strict_policy = bio_get_uint32(msg);
        s = bio_get_string16(msg, &len);
        ...
        //svcmgr_id校验,是否为“android.os.IServiceManager”
        if ((len != (sizeof(svcmgr_id) / 2)) ||
            memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
            fprintf(stderr,"invalid id %s\n", str8(s, len));
            return -1;
        }
        ...
        switch(txn->code) {
            ...
            //枚举值对应ADD_SERVICE_TRANSACTION
            case SVC_MGR_ADD_SERVICE:
            s = bio_get_string16(msg, &len);
            if (s == NULL) {
                return -1;
            }
            //取出binder_引用对象的句柄值
            handle = bio_get_ref(msg);
            allow_isolated = bio_get_uint32(msg) ? 1 : 0;
            dumpsys_priority = bio_get_uint32(msg);
            if (do_add_service(bs, s, len, handle, 
                txn->sender_euid, allow_isolated, dumpsys_priority,
                               txn->sender_pid))
                return -1;
            break;
       }
       ...
       bio_put_uint32(reply, 0);
       return 0; 
    }
    
    • 从msg中取出对应的Service的handle、name,然后调用do_add__service去执行后续的操作
    • 看do_add_service之前我们先来看一个结构体svcinfo
    struct svcinfo
    {
        //指向下一个引用
        struct svcinfo *next;
        //句柄值
        uint32_t handle;
        //死亡代理通知
        struct binder_death death;
        int allow_isolated;
        uint32_t dumpsys_priority;
        size_t len;
        //服务名称
        uint16_t name[0];
    };
    
    • 在ServiceManager中每一个服务对应一个svcinfo结构体
    • 接下来我们看do_add_service的实现
    int do_add_service(struct binder_state *bs, const uint16_t *s, 
        size_t len, uint32_t handle, uid_t uid, int allow_isolated, 
        uint32_t dumpsys_priority, pid_t spid) {
        //存储要注册的服务信息
        struct svcinfo *si;
        ...
        //检查权限
        if (!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) {
                ...
                svcinfo_death(bs, si);
            }
            si->handle = handle;
        } else {
            //注册服务
            si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
            ...
            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;
            //绑定到svclist中
            si->next = svclist;
            svclist = si;
        }
    
        //增加引用,避免被销毁
        binder_acquire(bs, handle);
        //绑定死亡通知
        binder_link_to_death(bs, handle, &si->death);
        return 0;
    }
    
    • 这里先检查Service是否有注册权限(不同版本内核加固调用不同,感兴趣可以查看selinux),然后先去尝试查找这个服务存在不,如果不存在就分配一个新的struct svcinfo,并将其挂到svclist中,由此可见在service_manager中是维护这一个所有Service组件信息的svclist的
    • 回到binder_parse中,接下来会调用binder_send_reply向Binder驱动发送一个BC_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;
    
        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;
        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;
        }
        //向Binder驱动写入数据
        binder_write(bs, &data, sizeof(data));
    }
    
    • 这里会将进程通信结果写入到匿名struct data中,然后调用binder_write去向内核写入BC_FREE_BUFFER\BC_REPLY命令协议
    int binder_write(struct binder_state *bs, void *data, size_t len)
    {
        struct binder_write_read bwr;
        int res;
    
        bwr.write_size = len;
        bwr.write_consumed = 0;
        bwr.write_buffer = (uintptr_t) data;
        bwr.read_size = 0;
        bwr.read_consumed = 0;
        bwr.read_buffer = 0;
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        if (res < 0) {
            fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                    strerror(errno));
        }
        return res;
    }
    
    • binder_write实际上还是通过IO控制命令写入一个binder_write_read结构体,注意这个结构体输入缓冲区是没有数据的,也就是说不需要处理返回协议
    • 略过各种调用我们来看内核中binder_thread_write对于BC_FREE_BUFFER\BC_REPLY的处理
    platform/drivers/staging/android/binder.c
    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);
            ...
            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;
                }
            ...
        }
    
    • BC_FREE_BUFFER主要是做一些资源释放的操作,感兴趣可以自己看这里不再细看
    • 重点看BC_REPLY,查看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;
        ...
        if (reply) {
            //寻找请求通信的thread
            //从之前的thread中取出通信的binder_transaction_data
            in_reply_to = thread->transaction_stack;
            if (in_reply_to == NULL) {
                ...
                return_error = BR_FAILED_REPLY;
                goto err_empty_call_stack;
            }
            //恢复线程优先级
            binder_set_nice(in_reply_to->saved_priority);
            if (in_reply_to->to_thread != thread) {
                ...
                return_error = BR_FAILED_REPLY;
                in_reply_to = NULL;
                goto err_bad_call_stack;
            }
            thread->transaction_stack = in_reply_to->to_parent;
            target_thread = in_reply_to->from;
            if (target_thread == NULL) {
                return_error = BR_DEAD_REPLY;
                goto err_dead_binder;
            }
            if (target_thread->transaction_stack != in_reply_to) {
                ...
                return_error = BR_FAILED_REPLY;
                in_reply_to = NULL;
                target_thread = NULL;
                goto err_dead_binder;
            }
            //目标进程
            target_proc = target_thread->proc;
        }else{
            ...
        }
        //有空闲线程就是用空间线程的等待队列,否则使用进程的
        if (target_thread) {
            ...
            target_list = &target_thread->todo;
            target_wait = &target_thread->wait;
        } else {
            ...
        }
        ...
        //创建binder_transaction结构体,BINDER_WORK_TRANSACTION
        t = kzalloc(sizeof(*t), GFP_KERNEL);
        ...
        //创建binder_work结构体,BINDER_STAT_TRANSACTION_COMPLETE
        tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
        ...
        //分配事务t的要进入那个栈
        if (reply) {
            BUG_ON(t->buffer->async_transaction != 0);
            //将事务弹出todo栈
            binder_pop_transaction(target_thread, in_reply_to);
        } else if (!(t->flags & TF_ONE_WAY)) {
            ...
        }else{
            ...
        }
        //将binder_transaction_data指针t的类型修改为BINDER_WORK_TRANSACTION
        t->work.type = BINDER_WORK_TRANSACTION;
        //添加到target_list队列尾部
        list_add_tail(&t->work.entry, target_list);
        //将binder_work指针tcomplete.type置为BINDER_WORK_TRANSACTION_COMPLETE
        tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
        list_add_tail(&tcomplete->entry, &thread->todo);
        //这里有两个执行分支
        //1.处理类型为BINDER_WORK_TRANSACTION的binder_transaction_data
        //2.处理类型为BINDER_WORK_TRANSACTION_COMPLETE的binder_work
        if (target_wait)
            wake_up_interruptible(target_wait);
        return;
        ...
    }   
    
    • 这里跟只爱去哪调用不同的地方在于走的是if分支,需要查找到之前通信的目标线程及进程,然后将上次通信的binder_transaction弹栈,然后回想之前通信的进程发送一个type为BINDER_WORK_TRANSACTION的binder_work,之前那个进程对应的binder_thread_read处理如下:
    static int binder_thread_read(struct binder_proc *proc,
                      struct binder_thread *thread,
                      binder_uintptr_t binder_buffer, size_t size,
                      binder_size_t *consumed, int non_block)
    {
        void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
        void __user *ptr = buffer + *consumed;
        void __user *end = buffer + size;
    
        int ret = 0;
        ...
        //线程唤醒
        while (1) {
            uint32_t cmd;
            struct binder_transaction_data tr;
            struct binder_work *w;
            struct binder_transaction *t = NULL;
            //检查工作队列,并将待处理项赋值给w
            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 {
                ...
            }
            ...
            switch (w->type) {
                case BINDER_WORK_TRANSACTION: {
                    t = container_of(w, struct binder_transaction, work);
                } break;
                ...
            }
            //返回协议的处理,现在target_node指向的是binder_context_mgr_node
            if (t->buffer->target_node) {
                ...
            }else{
                tr.target.ptr = 0;
                tr.cookie = 0;
                cmd = BR_REPLY;
            }
            
            //Binder驱动程序分配给进程的内核缓冲区同时,映射了用户的内核地址、用户空间地址
            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);
            //直接操作offsets
            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);
            ...
            //cmd = BR_TRANSACTION && 不是正在处理异步通信请求
            //就需要等待该同步进程通信完以后再进行下一步的操作
            if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
                ...
            } else {
                t->buffer->transaction = NULL;
                kfree(t);
                binder_stats_deleted(BINDER_STAT_TRANSACTION);
            }
            break;
        }
        ...
    }
    
    • 这里就会封装一个BR_REPLY返回协议,然后返回到IPCThreadState::waitForResponse中
    • 接下来看IPCThreadState::waitForResponse对于BR_REPLY的处理
    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
    {
        uint32_t cmd;
        ...
        while (1) {
            ...
            cmd = (uint32_t)mIn.readInt32();
            ...
            switch (cmd) {
                case BR_REPLY:
                {
                    binder_transaction_data tr;
                    err = mIn.read(&tr, sizeof(tr));
                    ...
                    if (reply) {
                      if ((tr.flags & TF_STATUS_CODE) == 0) {
                         //重置Parcel对象内部数据缓冲区,并指定释放函数为freeBuffer
                         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 {
                           ...
                    } else {
                        ...
                    }
                }
                goto finish;
                ...
            }
        }
        ...
    }
    
    • 实际上会调用reply->ipcSetDataReference去重置数据缓冲区,这里不再细述,整个Service注册就大致完成了,后续还有Binder线程的启动感兴趣可以自行查看

    ServiceManager查找服务

    完整的通信流程

聊聊Android的Binder Binder 是 Android 平台中的一个关键组件,负责实现进程间通信(IPC)。它提供了一种高效的方式让不同进程中的应用程序进行交互,是 Android 系统的核心之一。 阅读详情

相关推荐

Android之Binder原理剖析

binder

zhuhai0613的博客 2808

Android跨进程通信:图文详解 Binder机制 原理

前言 如果你接触过 跨进程通信 (IPC),那么你对Binder一定不陌生 虽然 网上有很多介绍 Binder的文章,可是存在一些问题:浅显的讨论Binder机制 或 一味讲解 Binder源码、逻辑不清楚,最终导致的是读者们还是无法形成一个完整的Binder概念 本文采用 清晰的图文讲解方式,按照 大角度 -&gt; 小角度 去分析Binder,即: 先从 机制、模型的角度 去分析 整个B...

Carson带你学Android 14万+

EDSR-PyTorch实战:从模型下载到超分辨率图像生成

本文详细介绍了如何使用PyTorch实现EDSR模型进行超分辨率图像生成,包括环境配置、模型下载、参数调优及常见问题解决方案。EDSR作为超分辨率重建的利器,通过深度残差网络显著提升图像质量,特别适合老照片修复等场景。文章还提供了视频处理和自定义训练的进阶技巧,帮助开发者快速掌握这一技术。

weixin_29046035的博客 458

android framework实战-跨进程通信binder专题

千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其中的binder是重中之重,都说无binder无Android,binde是Android系统的任督二脉。课程水平循序渐进,由中级再到高级,满足各个层次水平的android开发者。1、灵活使用binder跨进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码中任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程中遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码中使用的socket源码轻松掌握9、android系统源码中最常见的socketpair中双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序

1.47寸ST7789V3彩屏硬件设计与驱动调试指南

TFT LCD是一种基于薄膜晶体管阵列控制像素明暗的主动式显示技术,其核心依赖于专用驱动IC(如ST7789V3)完成时序生成、GRAM管理与伽马校正。该类小尺寸彩色显示屏广泛应用于嵌入式HMI、IoT终端与可穿戴设备,具备高PPI、低功耗和SPI接口易集成等工程优势。理解RGB565数据格式、SPI Mode 0通信时序及关键寄存器(如0x36方向控制、0x3A像素格式、0x2A/0x2B地址窗口)是实现稳定显示的基础;而正确处理电源设计(严禁5V直供)、复位时序与背光PWM调光,则直接决定系统可靠性与能

weixin_30995917的博客 166

SpotBugs实战:10大类Bug检测规则详解与代码优化实例(附避坑清单)

本文深入解析SpotBugs在Java开发中的实战应用,详细讲解10大类Bug检测规则与代码优化实例,包括NPE防御、多线程安全、性能优化等关键问题。通过具体代码示例和避坑清单,帮助开发者提升代码质量,有效集成到CI/CD流程中。

weixin_42665255的博客 197

Android进阶知识(五):IPC基本概念之Binder、Binder工作机制及其原理

Android进阶知识(五):IPC基本概念之Binder、Binder工作机制及其原理   Binder是一个很深入的话题——任玉刚老师如是说。就笔者的水平而言,实际上从任玉刚老师的《艺术探索》中读完从AIDL代码中去解析其工作机制,确实可以理解。但是笔者在这不会老套照搬代码,介绍其工作机制时只是必要的些许代码,不会整个代码文件上,有兴趣的读者可以阅读该书,按照书的步骤走即可。 一、Binde...

weixin_38196407的博客 609

用 ABAP CDS View 把数据稳定抽到 SAP BW/4HANA:从 ODP 架构到增量机制的落地实践

本文探讨了SAP数据仓库中从业务系统抽取数据到SAP BW/4HANA的最佳实践,重点分析了基于ABAP CDS视图的抽取方法。文章指出CDS视图通过注解可实现元数据描述、增量机制的统一管理,替代传统抽取器。详细介绍了ODP架构如何作为抽取基础设施,以及从CDS到BW的完整链路。同时比较了三种增量抽取方式(BW管理时间戳、ODP通用增量、CDC触发器)的适用场景和注意事项,并强调版本兼容性和云环境连接差异对实施的影响。通过实际案例说明合理选择增量策略对数据仓库稳定性的重要性。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 332

Android IPC机制(二)Binder的工作机制

Binder的理解 Binder是Android中的一个类,它实现了IBinder接口。 从各个角度来说明Binder: IPC Android Framework Android应用层 是Android中的一种跨进程通信方式;还可以理解为一种虚拟的物理设备,该方式在Linux中没有 是ServiceManager连接各种Manager和相应ManagerService的桥梁 是客...

Egypt_nova 604

基于STM32L4XX、HAL库的MCP4561数字电位器驱动程序设计

/ HAL库需要左移一位。* @param address: 设备地址(0x2C-0x2F)* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hi2c: I2C句柄。

zhusl6688的博客 341

(四)美赛画图篇:画图模板+画图工具

美赛画图篇:画图模板+画图工具(一)画图模板(二)画图工具 因为散点图、折线图等多与数据有关,且需相关软件生成,故此处多是通用模板。直接替换文字内容即可。 (一)画图模板 1、Visio圆圈图 适合于:指标体系(E题常用) 点击下载:1 C币 如果不想花费且时间充足,悄咪咪地说,在visio-模板搜索可以找到很多。(稍微会耗一点时间) 2、简单指标体系图PPT 适合于指标体系 点击下载:0 C币...

weixin_43689393的博客 1万+

安卓IPC机制(二)---Binder的工作机制

吐槽 中午起床后晕乎乎的,还是自己下午看书学东西,晚上写项目吧 Binder的理解 发现这个感觉真的是现在给我看好复杂啊,,,然后还是先了解下吧,以后自己看的时候会好受一点。 直观的说Binder是Android的一个类,它实现IBinder接口 从IPC的角度来看,Binder是一种跨进程通信的方式 Binder还可以理解为一种虚拟的物理设备,它的驱动是/dev/binder 从A...

sakurakider的博客 632

QCM2290 PM-3 如何让mirco-usb支持关机充电

PM4125-3插入type-C触发开机进入关机充电的CC脚中断条件是否可以软件上屏蔽, 做到只通过VBUS中断即可触发进入关机充电模式,达到和PM4125-2的效果一样只要插入micro USB 就可以触发进入关机充电模式。硬件团队提议修改寄存器 SCHG_L_MISC_SYSOK_CFG 0x164A bit[4] 目前修改如下 — a/BOOT.XF.4.1/boot_images/QcomPkg/Library/PmicLib/target/Agatti_pmCocos/psi/pm_confi

墨染天玑的博客 444

Framework详解面试题之 为什么Android 要采用 Binder 作为 IPC 机制?和Binder线程池的工作过程是什么样?

Binder主线程:进程创建过程会调用startThreadPool()过程中再进入spawnPooledThread(true),来创建Binder主线程。编号从1开始,也就是意味着binder主线程名为binder_1,并且主线程是不会退出的。Binder普通线程:是由Binder Driver来根据是否有空闲的binder线程来决定是否创建binder线程,回调spawnPooledThread(false) ,isMain=false,该线程名格式为binder_x。

bugyinyin的博客 531

【2024年5月备考新增】《2024高项论文精华版(5)项目工作绩效域和度量绩效域》

3、专注于工作过程和能力。③专注于工作过程和能力。1、制定有效的度量指标。2、度量内容及相应指标。3、展示度量信息和结果。4、管理沟通和参与。7、监督新工作和变更。①制定有效的度量指标。②度量内容及相应指标。③展示度量信息和结果。5、基于度量进行诊断。

Else 的博客 1268

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

安卓IPC机制之Binder详解

IPC(Inter-Process Communication,跨进程通信)是指两个进程之间数据交换的过程,因此我们首先必须了解什么是进程,什么是线程。

(* ̄︶ ̄) 3万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

安卓开发之IPC机制详解

IPC(Inter-Process Communication),意为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。前面在学习Handler机制时提到过线程与进程的概念,在安卓中一个进程可以简单理解为一个程序或应用,而线程是CPU调度的最小单元,一个进程可以包含多个线程,也可以只有一个线程即主(UI)线程。 1. 多进程模式 既然是跨进程通信,必然要在多进程模式下进行。 使用多进程的情况分为两种: 由于某些原因,应用自身需要采用多进程模式来实现。可能原因有:应用中某些模块因特殊原因要运行在

iris的博客 1033

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Android IPC机制详解--Binder

最近在学习贯穿android 系统的binder,今天就分享下这几天的学习心得: 本文主要从以下几个方面来介绍IPC机制 1、什么是IPC 2、Binder机制原理 3、AIDL实现 一、什么是IPC IPC是Inter-Process-Communication的缩写,意思是进程间通信或者跨进程通信; 说起进程间通信,我们应该首先来了解一下什么是进程。按照操作系统的描述,线程是CPU调度的最小单元,而进程一般指一个执行单元,在移动设备上指一个程序或应用;一个进程可以包含多个线程; 为什么要用到多进程? 在

hipeboy的博客 732

Android IPC机制(二)Binder

在Android开发中,进程间通信(IPC)是一个重要的概念,而Binder则是Android系统中实现IPC的核心机制。本文将详细介绍Binder的工作原理、其在Android中的重要性以及与其他IPC机制的对比。

weixin_63357306的博客 1302

借助 AIDL 理解 Android Binder 机制——Binder 来龙去脉

AIDL 是 Android Interface Definition Language(Android 接口定义语言)的缩写,它是 Android 进程间通信的接口语言。由于 Android 系统的内核是 Linux,它采用了进程隔离机制,使得不同的应用程序运行在不同的进程当中,有时候两个应用之间需要传递或者共享某些数据,就需要进行进程间的通信讯。 Android 进程间通信的方式有很多种,比如...

weixin_34306446的博客 159

Android Binder 作为 IPC 机制原理和面试回答

一、Binder机制 在Android开发中,很多时候我们需要用到进程间通信,所谓进程间通信,实现进程间通信的机制有很多种,比如说socket、pipe等,Android中进程间通信的方式主要有三种: 1.标准Linux Kernel IPC 接口; 2.标准D-BUS接口; 3.Binder接口。 IPC(Inter-Process Co

深南大盗的博客 2787

IPC机制(二)--->Binder简介

IPC机制--->Binder简介

weixin_51065489的博客 1684

Android面试题(二)——IPC机制

引言 IPC是Inter-Process Communication的缩写,含义是进程间通信和跨进程通信,是指两个进程直接进行数据交换的过程。 Binder机制是Android 采用的独特的进程间通信机制。基于OpenBinder框架的一个驱动,用于提供Android平台的进程间通信。 Messenger、ContentProvider、AIDL底层实现都是Binder。

a471893438的专栏 5570
上一篇: Android开源的UI特效
下一篇: GreenDao集成与使用
Watch_the_corner
博客等级 码龄10年 30粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值