Binder native层源码分析(三):BpBinder通信类

在源码分析(一)的结尾,addService函数中构造了数据包Parcel data并发送给了service manager,如下:

    //将服务名和MediaPlayerService写入Parcel
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    data.writeStrongBinder(service);
    data.writeInt32(allowIsolated ? 1 : 0);
    //在interface_cast分析中我们知道BpServiceManager的remote成员是handle值
    //为0的BpBinder,这里相当于BpBinder->transact。该函数完成数据的发送
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

其中remote()返回BpBinder指针。我们接下来就来分析BpBinder,看数据是怎么被交给Binder驱动的。

BpBinder

先看BpBinder的构造函数:

//\frameworks\native\libs\binder\BpBinder.cpp
BpBinder::BpBinder(int32_t handle)
    : mHandle(handle)
    , mAlive(1)
    , mObitsSent(0)
    , mObituaries(NULL)
{
    //...
}

构造BpBinder时需要一个参数handle用于初始化成员变量mHandle。每个BpBinder都有唯一一个和他对应的BBinder对象,BpBinder通过这个mHandle来标识它的传输目标。可以看到在后面的transact()中,这个mHandle会作为一个参数传入,代表本次通信的目的端。而本次分析的BpBinder的mHandle值为0,代表service manager。

接下来看完成通信的transact函数。

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.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

注意该函数的几个参数。code控制服务端进入不同的分支,具体来说,在BBinder的transact()或onTransact()函数中会根据接收到的code的值进入不同的分支。data即传输的数据(很多情况下是远程函数的参数数据),reply用于接收回复,flags表示本次通信的类型,默认为0。

本次传输中,code是ADD_SERVICE_TRANSACTION,data主要是由MediaPlayerService构造而得的flat_binder_object

BpBinder的transact()函数只是将参数原封不动的交给IPCThreadState的transact()处理,并且还额外传入了mHandle表示通信的目的端。

IPCThreadState::transact

//\frameworks\native\libs\binder\IPCThreadState.cpp,删去了一些debug代码
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();
    flags |= TF_ACCEPT_FDS;
    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
    
    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }
    
    if ((flags & TF_ONE_WAY) == 0) {//flags为0,会进入该if
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        
    } else {//不会进入else
        err = waitForResponse(NULL, NULL);
    }
    
    return err;
}

IPCThreadState的transact()将传进来的所有参数又传给了writeTransactionData(),额外传入了BC_TRANSACTION表示通信协议,然后waitForResponse()。

这两个函数的函数名已经把transact()做的事情说得很清楚了,先是发送数据,然后等待响应。继续看writeTransacctionData,看数据是怎么发送的。

writeTransacctionData

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    binder_transaction_data tr;

    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;
    
    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }
    
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));
    
    return NO_ERROR;
}

这个函数中首先构造了一个binder_transaction_data对象tr,它的内容来源于传入的Parcel data和其它用于通信的参数例如pid,uid,handle。其中,tr.data.ptr.buffer等于data.mData,即为传输的数据。

函数的最后把协议BC_TRANSACTION和tr写进mOut。mIn和mOut是IPCThreadState的成员,类型是Parcel。从代码中可以看出,传进来的Parcel data并不直接用于传输,而是用于填充binder_transaction_data,之后将协议cmd和binder_transaction_data写入mOut,所以mOut才是Binder通信中传输的Parcel。

writeTransactData仅仅只是做了填充数据结构的工作,并没有将数据真正发送出去。事实上数据的发送和接收都在waitForResponse的talkWithDriver中进行。

waitForResponse分段1

waitForResponse中,我们只需看数据是怎么发送的即可,后面部分的代码暂时用不到,等用到时再分析。

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        

在waitForResponse()中,首先是调用talkWithDriver()。

talkWithDriver

//删去dubug代码
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }
    
    binder_write_read bwr;
    
    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    
    // We don't want to write anything if we are still reading
    // from data left in the input buffer and the caller
    // has requested to read the next data.
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
    
    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

这里构造了一个binder_write_read类型变量bwr,然后根据mIn和mOut的mDataPos,mDataSize,mDataCapacity来填写bwr。

当mIn的mDataPos<mDataSize时 ,说明mIn中还有未读的数据,所以此时不需要Binder读取数据,所以needRead为false。当mDataPos>=mDataSize时,说明mIn中的数据都被我们读完了,所以needRead为true,代表我们希望从Binder中读取数据放到mIn中。也就是说,只有当mIn中的数据全部读完时,才允许从Binder中读取新数据。

对bwr的read_size,write_size的赋值很容易理解,这里不再浪费篇幅赘述,主要注意bwr的buffer指针等于mIn和mOut的数据指针,所以Binder驱动通过bwr就可以从mIn和mOut中读写数据。继续看talkWithDriver的后半部分:

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
        if (mProcess->mDriverFD <= 0) {
            err = -EBADF;
        }
    } 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);
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        return NO_ERROR;
    }
    return err;
}

调用了ioctl,该函数属于驱动层,驱动层我放在后面的文章分析,所以在这里就到函数为止,不再继续往底层钻。

调用完ioctl之后,把mOut中已经发出去的数据移除掉,更新mIn的数据大小和读写位置(置零)。

总结

在前面的分析中,我们传入的数据data经过了层层包装和转化,最终被传给了Binder驱动,这里用一张图来直观地表现这一过程。
在这里插入图片描述
其中,binder_transaction_data中除了储存Parcel data的数据外,还添加了发送者和接收者等额外通信信息。

mOut和mIn是进程专门用于收发Binder通信数据的区域。数据被发送前,统一被放到mOut中,而接收的数据则统一放到mIn中。

bwr记录了mOut和mIn的相关信息,这样驱动层就可以通过这些信息直接对mOut和mIn进行读写操作。

本文到此结束,下篇文章将分析Binder驱动层。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Binder是Android操作系统中的一个IPC(进程间通信)机制,用于实现进程之间的通信和数据传输。Binder源码主要位于frameworks/native目录下。 在Binder源码中,最核心的部分是Binder驱动和Binder服务。Binder驱动是位于内核空间的组件,负责处理进程间的数据传输和交互。Binder服务是位于用户空间的组件,负责提供接口和功能来进行进程间通信。 在Binder源码中,主要涉及到以下几个重要的文件和目录: 1. drivers目录:包含了Binder驱动的代码,其中最重要的文件是binder.c,它实现了Binder驱动的核心逻辑。 2. include目录:包含了Binder的头文件,其中最重要的文件是binder.h,它定义了Binder的接口和数据结构。 3. libbinder目录:包含了Binder服务的代码,其中最重要的文件是IBinder.cpp和BpBinder.cpp,它们分别实现了Binder服务的接口和代理。 4. services目录:包含了一些系统级别的Binder服务,例如Package Manager Service和Activity Manager Service。 如果你想深入了解Android Binder源码,可以参考以下资源: 1. Android 源码:你可以从Android官网或者GitHub上获取Android源码,并在frameworks/native目录下查看Binder相关的代码。 2. Android系统架构指南:Android官网提供了关于Android系统架构的详细文档,其中有关IPC和Binder的章节对于理解Binder的实现原理和源码结构很有帮助。 3. 《深入理解Android:卷2》一书中有关于Binder的详细介绍和源码解析,可以作为参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值