binder ---client与service端交互过程

1、client端面获取service

virtual sp BpServiceManager::checkService( const String16& name) const
{
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
    return reply.readStrongBinder();
}

a)、
1)、transact->BpBinder::transact->IPCThreadState::self()->transact,进入这里handle为0, 再通过waitForRespon se-->talkWithDriver调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)把参数传入驱动
2)、驱动进入binder_thread_write
(1)、分配了一个待处理事务t和待完成工作项tcomplete
(2)、把处理线程设置为service manager
(3)、在处理线程中分配空间,并把参数拷贝进来
(4)、把待处理的事务加入到service manager处理线程的todo列表,唤醒它
(5)、待完成工作项加入到本线程的todo队列

3)、驱动进入binder_thread_read
(1)、写入用户空间参数BR_NOOP,修改ptr
(2)、从todo队列取得前面加入的待完成项
(3)、写入用户空间参数BR_TRANSACTION_COMPLETE,修改ptr,删除前面取得的待完成项
(4)、修改consumed
4)、回到用户态
(1)、先取到BR_NOOP,不做事
(2)、再次进入 talkWithDriver,bwr.write_size和bwr.read_size全为0直接返回
(3)、进入 waitForResponse,由于reply不为空,再次返回到talkWithDriver
(4)、needRead就为true了,而outAvail仍为0,所以bwr.read_size不为0,bwr.write_size为0,通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) 进入wait_event_interruptible睡眠




b)、service manager唤醒后处理client请求
1)、从binder_thread_read唤醒
2)、获取事务t,把相应的数据拷贝到本地局部变量struct binder_transaction_data tr(指针映射到用户空间)
3)、把事务t从todo列表中删除,放在thread->transaction_stack队列的头部
4)、本地变量struct binder_write_read bwr的内容拷贝回到用户传进来的缓冲区中,返回
5)、调用binder_parse进行解析
6)、查找到该servie,把这个service的弱引用写入reply
7)、调用binder_send_reply往驱动发送两个命令BC_FREE_BUFFER,BC_REPLY,第一个用于释放binder_transaction分配的空间,后者用于告诉service它的addService操作已经完成了,错误码是0,保存在data.txn.data中
8)、返回驱动,处理第一个命令,先释放前面的空间
9)、对于BC_REPLY,调用binder_transaction分配一个事件t,target_thread 设为请求add service的进程,把事务t放到它的todo队列,并唤醒它
10)、处理Service Manager返回来的Binder引用,调用binder_get_ref_for_node函数为这个Binder实体在target_proc创建一个引用
11)、把fp->handle的值改为在target_proc中的引用值
12)、service manager重新回到binder_loop,等待下一个client的请求

c)、client被manager唤醒后
1)、从binder_thread_read唤醒(Service Manager返回来了一个Binder引用和一个结果码0回来,写在t->buffer->data里面)
2)、调用reply->ipcSetDataReference把参数保存在reply里面
3)、调用readStrongBinder,再调用unflatten_binder,flat->type为BINDER_TYPE_HANDLE,再调用getStrongProxyForHandle,创建一个BpBinder对象(new BpBinder(handle))
4)、interface_cast(binder); 构建一个BpMediaPlayerService(new BpMediaPlayerService(new BpBinder(handle)))
5)、跳出循环

2、clien使用service方法

    virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        data.writeCString(url);
        remote()->transact(DECODE_URL, data, &reply);
        *pSampleRate = uint32_t(reply.readInt32());
        *pNumChannels = reply.readInt32();
        *pFormat = reply.readInt32();
        return interface_cast(reply.readStrongBinder());
    }

a、client把数据传入驱动
    1)、transact->BpBinder::transact->IPCThreadState::self()->transact这里的第一个参数不再是0,而是前面返回的handle
    2)、再通过waitForRespon se-->talkWithDriver调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)进入驱动
    3)、分配了一个待处理事务t和待完成工作项tcomplete
    4)、binder_transaction中reply为0,handle不为0调用binder_get_ref获取前面创建的引用target_node设为该引用的node,target_proc设为target_node的proc
    5)、把事务放到target_proc的todo队列
    6)、写入用户空间参数BR_NOOP,修改ptr
    7)、从todo队列取得前面加入的待完成项
    8)、写入用户空间参数BR_TRANSACTION_COMPLETE,修改ptr,删除前面取得的待完成项,修改consumed
b、回到用户态
(1)、先取到BR_NOOP,不做事
(2)、再次进入 talkWithDriver,bwr.write_size和bwr.read_size全为0直接返回
(3)、进入 waitForResponse,由于reply不为空,再次返回到talkWithDriver
(4)、needRead就为true了,而outAvail仍为0,所以bwr.read_size不为0,bwr.write_size为0,通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) 进入wait_event_interruptible睡眠


c、service处理client请求
1)、service进程从binder_thread_read唤醒
2)、获取事务t,把相应的数据拷贝到本地局部变量struct binder_transaction_data tr(指针映射到用户空间)
3)、把事务t从todo列表中删除,放在thread->transaction_stack队列的头部
4)、本地变量struct binder_write_read bwr的内容拷贝回到用户传进来的缓冲区中,返回
5)、service回到用户态,talkWithDriver会把返回数据写到mIn,调用executeCommand处理,从mIn中读出数据到 binder_transaction_data tr;
6)、从tr.cookie获取BBinder调用b->transact(tr.code, buffer, &reply, tr.flags); 
7)、b->transact最终调用onTransact处理请求

	        case DECODE_URL: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            const char* url = data.readCString();
            uint32_t sampleRate;
            int numChannels;
            int format;
            sp player = decode(url, &sampleRate, &numChannels, &format);
            reply->writeInt32(sampleRate);
            reply->writeInt32(numChannels);
            reply->writeInt32(format);
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
8)、先从data里面读出相应的参数,调用service相应 方法,再把需要返回的参数写回replsy
9)、调用sendReply把返回数据写给驱动(BC_REPLY)
10)、service manager重新回到binder_loop,等待下一个client的请求
11)、对于BC_REPLY,调用binder_transaction分配一个事件t,target_thread 设为请求add service的进程,把事务t放到它的todo队列,并唤醒它(client)
12)、service重新进入循环,等待下一个client
d、client再次被唤醒
1)、从binder_thread_read唤醒
2)、将写在t->buffer->data里面的数据映射成用户空间地址(加上proc->user_buffer_offset)
3)、回到用户空间talkWithDriver函数,把相应的参数从binder_write_read中读出到mIn
4)、回到waitForResponse,把参数从mIn读到binder_transaction_data,并设置到transact传下来的reply中
5)、从reply中读出返回参数,并从reply中读出返回结果,返回

你可能感兴趣的:(android框架)