Android Binder进程间通信---注册Service组件---发送和处理BC_TRANSACTION

本文参考《Android系统源代码情景分析》,作者罗升阳

一、测试代码:

       ~/Android/external/binder/server

        ----FregServer.cpp

        ~/Android/external/binder/common

        ----IFregService.cpp

        ----IFregService.h

       ~/Android/external/binder/client

       ----FregClient.cpp


       Binder库(libbinder)代码:

       ~/Android/frameworks/base/libs/binder

       ----BpBinder.cpp

       ----Parcel.cpp

       ----ProcessState.cpp

       ----Binder.cpp

       ----IInterface.cpp

       ----IPCThreadState.cpp

       ----IServiceManager.cpp

       ----Static.cpp

       ~/Android/frameworks/base/include/binder

       ----Binder.h

       ----BpBinder.h

       ----IInterface.h

       ----IPCThreadState.h

       ----IServiceManager.h

       ----IBinder.h

       ----Parcel.h

       ----ProcessState.h


        驱动层代码:

       ~/Android//kernel/goldfish/drivers/staging/android

       ----binder.c

       ----binder.h


二、源码分析

       上一篇文章Android Binder进程间通信---注册Service组件---封装进程间通信数据http://blog.csdn.net/jltxgcy/article/details/26059215,我们执行完了addService中封装数据部分代码,如下:

      ~/Android/frameworks/base/libs/binder

       ----IServiceManager.cpp

class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    .........
    virtual status_t addService(const String16& name, const sp<IBinder>& service)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());//写入一个Binder进程间通信请求头
        data.writeString16(name);//写入将要注册的Service组件的名称
        data.writeStrongBinder(service);//将要注册的Service组件封装成一个flat_binder_object结构体,写入data
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);//remote为BpBinder对象
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
    ..........
};
      接下来调用内部的一个Binder代理对象的成员函数transact发送一个ADD_SERVICE_TRANSACTION命令协议。
      remote()获取BpBinder对象,调用它的成员函数transact函数,实现如下:

      ~/Android/frameworks/base/libs/binder

      ----BpBinder.cpp

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)//注意data是一个引用,reply是一个指针
{
    // 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;
}
       目前mHandle为0,code为ADD_SERVICE_TRANSACTION,data包含了要传递给Binder驱动程序的进程间通信数据;第三个参数reply是一个输出参数,用来保存进程间通信结果,第四个参数flags用来描述这是一个同步的进程间通信请求,还是一个异步的进程间通信请求,它是一个默认参数,默认值为0,表示这是一个同步的进程请求。

       调用上文http://blog.csdn.net/jltxgcy/article/details/25953361已经创建的IPCThreadState对象的成员函数transact,实现如下:

      ~/Android/frameworks/base/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 = data.errorCheck();

    flags |= TF_ACCEPT_FDS;//flags等于0|TF_ACCEPT_FDS
    .......
    if (err == NO_ERROR) {
        ..........
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//将data的内容写入到一个binder_transaction_data结构体中
    }
    ........
    if ((flags & TF_ONE_WAY) == 0) {//最后一位为0,按位与TF_ONE_WAY等于0,表示同步的进程间通信请求
        ..........
        if (reply) {//reply不为空,是一个指针
            err = waitForResponse(reply);
        } else {
            .........
        }
        ..........
    } else {
        ..........
    }
    
    return err;
}
      其中, TF_ACCEPT_FDS,TF_ONE_WAY定义在一个枚举中。实现如下:

      ~/Android/frameworks/base/include/binder

      ----binder.h

enum transaction_flags {
 TF_ONE_WAY = 0x01,
 TF_ROOT_OBJECT = 0x04,
 TF_STATUS_CODE = 0x08,
 TF_ACCEPT_FDS = 0x10,
};

      首先检查Parcel对象中的进程间通信数据是否正确,然后将参数flags的TF_ACCEPT_FDS位设置为1,表示允许Server进程在返回结果中携带文件描述符。如果Parcel对象data中的进程间通信数据没有问题,那么就会调用成员函数writeTransactionData将它的内容写入到一个binder_transaction_data结构体中。接着判断flags的TF_ONE_WAY位是否等于0。如果是,那么就说明这是一个同步的进程间通信请求,这时候如果用来保存通信结果的Parcel对象reply不等于NULL,那么就调用成员函数waitForResponse函数。

      

      我们先来分析writeTransactionData函数,实现如下:

      ~/Android/frameworks/base/include/binder
      ----IPCThreadState.cpp

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,//此时cmd为BC_TRANSACTION,binderFlags为0|TF_ACCEPT_FDS
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)//handle为0,code为ADD_SERVICE_TRANSACTION,data包含了包含了要传递给Binder驱动程序的进程间通信数据,statusBuffer为NULL
{
    binder_transaction_data tr;

    tr.target.handle = handle;//0
    tr.code = code;//ADD_SERVICE_TRANSACTION
    tr.flags = binderFlags;//0|TF_ACCEPT_FDS
    
    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(size_t);//偏移数组大小
        tr.data.ptr.offsets = data.ipcObjects();//偏移数组起始位置
    } else if (statusBuffer) {
        ........
    } else {
        ........
    }
    
    mOut.writeInt32(cmd);//BC_TRANSACTION
    mOut.write(&tr, sizeof(tr));
    
    return NO_ERROR;
}
      其中binder_transaction_data结构体,实现如下:

struct binder_transaction_data {

 union {
    size_t handle;
    void *ptr;
 } target;
 void *cookie;
 unsigned int code;

 unsigned int flags;
 pid_t sender_pid;
 uid_t sender_euid;
 size_t data_size;
 size_t offsets_size;

 union {
    struct {
       const void *buffer;
       const void *offsets;
    }ptr;
    uint8_t buf[8];
 } data;
};
      执行完writeTransactionData,此时命令协议缓冲区mOut的内存布局如下图:

Android Binder进程间通信---注册Service组件---发送和处理BC_TRANSACTION
       注意此图有错误,flat_binder_object中cookie为BBinder类指针,即binder本地对象指针。binder为本地对象弱引用计数的地址。


      执行完writeTransactionData函数,该执行waitForResponse函数了,实现如下:

      ~/Android/frameworks/base/include/binder

      ----IPCThreadState.cpp

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

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        .....
    }
    .......
}
      这个函数通过一个while循环不断地调用成员函数talkWithDriver来与Binder驱动程序进行交互,以便可以将前面准备好的BC_TRANSACTION命令协议发送给Binder驱动程序处理,并等待Binder驱动程序将进程间通信结果返回来。

      talkWithDriver函数实现如下:

      ~/Android/frameworks/base/include/binder

      ----IPCThreadState.cpp

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
    
    binder_write_read bwr;
    
    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();//needRead为1,表示有需要读的数据
    
    // 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;//doReceive为true表示,只接受Binder驱动程序发送给该进程的返回协议。默认为true。doReceive为false,即不只接受Binder驱动程序发送给该进程的返回协议,或者有需要读的数据,那么outAvail就不为0
    
    bwr.write_size = outAvail;//要写入的数据大小
    bwr.write_buffer = (long unsigned int)mOut.data();//要写入的数据起始位置

    // This is what we‘ll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();//读入数据的大小
        bwr.read_buffer = (long unsigned int)mIn.data();//读入数据的起始位置
    } else {
        bwr.read_size = 0;
    }
    .........
    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;//如果两者都为0,就不用继续执行驱动程序了
    
    bwr.write_consumed = 0;//消费清0
    bwr.read_consumed = 0;//消费清0
    status_t err;
    do {
        .........
#if defined(HAVE_ANDROID_OS)
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//IPCThreadState在构造函数初始化时,初始化了mProcess
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        IF_LOG_COMMANDS() {
            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
        }
    } while (err == -EINTR);
    ........
    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < (ssize_t)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;
}
       在IPCThreadState类内部,除了使用缓冲区mOut来保存即将要发送给Binder驱动程序的命令协议外,还使用缓冲区mIn来保存那些从Binder驱动程序接受到的返回协议。

       通过IPCThreadState类的mIn,mOut设置一个局部变量binder_write_read结构体,最后调用了ioctl映射到Binder驱动程序去执行。

       ~/Android/kernel/goldfish/drivers/staging/android

       ----binder.c

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int ret;
	struct binder_proc *proc = filp->private_data;
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);
	void __user *ubuf = (void __user *)arg;//上面传递的过来的局部变量binder_write_read结构体的地址

	.........

	mutex_lock(&binder_lock);
	thread = binder_get_thread(proc);//第一次获取的thread,looper为BINDER_LOOPER_STATE_NEED_RETURN
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {//cmd为上面传递过来的BINDER_WRITE_READ
	case BINDER_WRITE_READ: {
		struct binder_write_read bwr;
		if (size != sizeof(struct binder_write_read)) {
			ret = -EINVAL;
			goto err;
		}
		if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间传进来的一个binder_write_read结构体拷贝出来,并且保存在变量bwr中,里面有数据地址,数据总大小,数据现在消费了多少
			ret = -EFAULT;
			goto err;
		}
                .........
		if (bwr.write_size > 0) {//bwr.write_size大于0,执行这里
			ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			if (ret < 0) {
				bwr.read_consumed = 0;
				if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
					ret = -EFAULT;
				goto err;
			}
		}
		if (bwr.read_size > 0) {//bwr.read_size大于0,执行这里
			ret = binder_thread_read(proc, thread, (void __user *)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)))
					ret = -EFAULT;
				goto err;
			}
		}
                ...........
		if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//将结果返回用户空间bwr
			ret = -EFAULT;
			goto err;
		}
		break;
	}
	..........
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	mutex_unlock(&binder_lock);
        ...........
	return ret;
}




























Android Binder进程间通信---注册Service组件---发送和处理BC_TRANSACTION,布布扣,bubuko.com

Android Binder进程间通信---注册Service组件---发送和处理BC_TRANSACTION

上一篇:Android Intent传递对象小结


下一篇:android笔记1——开发环境的搭建