以一个MediaPlayerService添加为例子:
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
1、创建一个ProcessState实例
a)、打开binder驱动
b)、获取binder版本
c)、设置线程数
2、添加service到serviceManager(一般调用 defaultServiceManager()->addService(name,service))
virtual status_t addService(const String16& name, const sp<IBinder>& service)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode()
}
a)、service binder实体是如何传到binder驱动
1)、通过writeStrongBinder将其写入Parcel序列化对象,修改其mDataPos,mObjectsSize等
2)、在writeTransactionData将参数以binder_transaction_data结构组织写入mOut
3)、将mOut中的数据传到 binder_write_read bwr; 的write_buffer
4)、驱动中获取传入的数据后重新转化成binder_transaction_data结构,然后获取binder实体位置
5)、new一个binder_node结构保存在该service的内核中,添加到它的binder_proc中
b)、service与binder驱动交互流程
1)、调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);
2)、驱动进入binder_thread_write
(1)、分配了一个待处理事务t和待完成工作项tcomplete
(2)、把处理线程设置为service manager
(3)、在处理线程中分配空间
binder_alloc_buf,并把参数拷贝进来
(4)、获取binder结构地址,在内核中为其分配一个binder_node结构,插入该线程binder_proc
(5)、为该binder实体分配一个引用,把分配到service manager中的binder改为引用,赋值引用值
(6)、把待处理的事务加入到service manager处理线程的todo列表,唤醒它
(7)、待完成工作项加入到本线程的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睡眠
c)、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)、获取service名称和一个弱引用的binder,构造一个个struct svcinfo结构,插入到链接svclist的头部
7)、调用binder_send_reply往驱动发送两个命令BC_FREE_BUFFER,BC_REPLY,第一个用于释放binder_transaction分配的空间(
binder_alloc_buf),后者用于告诉
service它
的addService操作已经完成了,错误码是0,保存在data.txn.data中
8)、返回驱动,处理第一个命令,先释放前面的空间
9)、对于BC_REPLY,调用binder_transaction分配一个事件t,target_thread 设为请求add service的进程,把事务t放到它的todo队列,并唤醒它
10)、service manager重新回到binder_loop,等待下一个client的请求
d)、service被manager唤醒后
1)、从binder_thread_read唤醒
2)、将写在t->buffer->data里面的数据映射成用户空间地址(加上proc->user_buffer_offset)
3)、回到用户空间IPCThreadState::talkWithDriver函数
4)、处理BR_REPLY,把结果保存在reply里,跳出入循环
3、service等待处理client请求
1)、调用startThreadPool最终调用spwanPooledThread创建一个线程并执行
2)、threadLoop函数即为PoolThread::threadLoop函数,调用joinThreadPool
3)、joinThreadPool调用 talkWithDriver和Binder驱动程序进行交互,再调用executeCommand来处理请求
4)、对于BR_TRANSACTION调用b->transact(tr.code, buffer, &reply, tr.flags);
5)、b->transact最终调用onTransact处理请求
最后引用老罗的一个图: