1分钟部署网站📞AI智能客服,大模型训练自有数据,简单好用,有效降低客服成本 广告
1. 业务层的工作 再回到MS的main函数,下一个要分析的是MediaPlayerService,它的代码如下所示: **MediaPlayerService.cpp** ~~~ void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService()); } ~~~ 根据前面的分析,defaultServiceManager()实际返回的对象是BpServiceManager,它是IServiceManager的后代,代码如下所示: **IServiceManager.cpp::BpServiceManager的addService()函数** ~~~ virtual status_t addService(const String16&name, const sp<IBinder>& service) { //Parcel:就把它当作是一个数据包。 Parceldata, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); //remote返回的是mRemote,也就是BpBinder对象 status_terr = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); returnerr == NO_ERROR ? reply.readInt32() : err; } ~~~ 别急着往下走,应先思考以下两个问题: - 调用BpServiceManager的addService是不是一个业务层的函数? - addService函数中把请求数据打包成data后,传给了BpBinder的transact函数,这是不是把通信的工作交给了BpBinder? 两个问题的答案都是肯定的。至此,业务层的工作原理应该是很清晰了,它的作用就是将请求信息打包后,再交给通信层去处理。 2. 通信层的工作 下面分析BpBinder的transact函数。前面说过,在BpBinder中确实找不到任何与Binder设备交互的地方吗?那它是如何参与通信的呢?原来,秘密就在这个transact函数中,它的实现代码如下所示: **BpBinder.cpp** ~~~ status_t BpBinder::transact(uint32_t code, constParcel& data, Parcel* reply, uint32_tflags) { if(mAlive) { //BpBinder果然是道具,它把transact工作交给了IPCThreadState status_t status = IPCThreadState::self()->transact( mHandle,code, data, reply, flags);//mHandle也是参数 if(status == DEAD_OBJECT) mAlive = 0; return status; } returnDEAD_OBJECT; } ~~~ 这里又遇见了IPCThreadState,之前也见过一次。看来,它确实与Binder通信有关,所以必须对其进行深入分析! (1)“劳者一份”的IPCThreadState 谁是“劳者”?线程,是进程中真正干活的伙计,所以它正是劳者。而“劳者一份”,就是每个伙计一份的意思。IPCThreadState的实现代码在IPCThreadState.cpp中,如下所示: **IPCThreadState.cpp** ~~~ IPCThreadState* IPCThreadState::self() { if(gHaveTLS) {//第一次进来为false restart: constpthread_key_t k = gTLS; /* TLS是Thread Local Storage(线程本地存储空间)的简称。 这里只需知晓:这种空间每个线程都有,而且线程间不共享这些空间。 通过pthread_getspecific/pthread_setspecific函数可以获取/设置这些空间中的内容。 从线程本地存储空间中获得保存在其中的IPCThreadState对象。 有调用pthread_getspecific的地方,肯定也有调用pthread_setspecific的地方 */ IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if(st) return st; // new一个对象,构造函数中会调用pthread_setspecific return new IPCThreadState; } if(gShutdown) return NULL; pthread_mutex_lock(&gTLSMutex); if(!gHaveTLS) { if(pthread_key_create(&gTLS, threadDestructor) != 0) { pthread_mutex_unlock(&gTLSMutex); return NULL; } gHaveTLS = true; } pthread_mutex_unlock(&gTLSMutex); //其实goto没有我们说的那么不好,汇编代码也有很多跳转语句(没办法,太低级的语言了),关键是要用好 goto restart; } ~~~ 接下来,有必要转向分析它的构造函数IPCThreadState(),如下所示: **IPCThreadState.cpp** ~~~ IPCThreadState::IPCThreadState() :mProcess(ProcessState::self()), mMyThreadId(androidGetTid()) { //在构造函数中,把自己设置到线程本地存储中去。 pthread_setspecific(gTLS, this); clearCaller(); //mIn和mOut是两个Parcel。把它看成是发送和接收命令的缓冲区即可。 mIn.setDataCapacity(256); mOut.setDataCapacity(256); } ~~~ 每个线程都有一个IPCThreadState,每个IPCThreadState中都有一个mIn、一个mOut,其中mIn是用来接收来自Binder设备的数据的,而mOut则是用来存储发往Binder设备的数据的。 (2)勤劳的transact 传输工作是很辛苦的。我们刚才看到BpBinder的transact调用了IPCThreadState的transact函数,这个函数实际完成了与Binder通信的工作,如下面的代码所示: **IPCThreadState.cpp** ~~~ //注意,handle的值为0,代表了通信的目的端 status_t IPCThreadState::transact(int32_t handle, uint32_tcode, const Parcel& data, Parcel* reply, uint32_t flags) { status_terr = data.errorCheck(); flags |=TF_ACCEPT_FDS; ...... /* 注意这里的第一个参数BC_TRANSACTION,它是应用程序向binder设备发送消息的消息码, 而binder设备向应用程序回复消息的消息码以BR_开头。消息码的定义在binder_module.h中, 请求消息码和回应消息码的对应关系,需要查看Binder驱动的实现才能将其理清楚,我们这里暂时用不上。 */ err =writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); ...... err = waitForResponse(reply); ...... returnerr; } ~~~ 多熟悉的流程:先发数据,然后等结果。再简单不过了!不过,我们有必要确认一下handle这个参数到底起了什么作用。先来看writeTransactionData函数,它的实现如下所示: **IPCThreadState.cpp** ~~~ status_tIPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_thandle, uint32_t code, const Parcel& data, status_t* statusBuffer) { //binder_transaction_data 是和binder设备通信的数据结构。 binder_transaction_data tr; //果然,handle的值传递给了target,用来标识目的端,其中0是ServiceManager的标志。 tr.target.handle= handle; //code是消息码,用来switch/case的! tr.code =code; tr.flags= binderFlags; conststatus_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) { tr.flags |= TF_STATUS_CODE; *statusBuffer = err; tr.data_size = sizeof(status_t); tr.data.ptr.buffer = statusBuffer; tr.offsets_size = 0; tr.data.ptr.offsets = NULL; } else { return (mLastError = err); } //把命令写到mOut中, 而不是直接发出去,可见这个函数有点名不副实。 mOut.writeInt32(cmd); mOut.write(&tr, sizeof(tr)); returnNO_ERROR; } ~~~ 现在,已经把addService的请求信息写到mOut中了。接下来再看发送请求和接收回复部分的实现,代码在waitForResponse函数中,如下所示: **IPCThreadState.cpp** ~~~ status_t IPCThreadState::waitForResponse(Parcel*reply, status_t *acquireResult) { int32_tcmd; int32_terr; while (1) { //好家伙,talkWithDriver! if((err=talkWithDriver()) < NO_ERROR) break; err =mIn.errorCheck(); if(err < NO_ERROR) break; if(mIn.dataAvail() == 0) continue; cmd =mIn.readInt32(); switch(cmd) { caseBR_TRANSACTION_COMPLETE: if (!reply && !acquireResult) goto finish; break; ...... default: err = executeCommand(cmd);//看这个! if (err != NO_ERROR) goto finish; break; } } finish: if (err!= NO_ERROR) { if(acquireResult) *acquireResult = err; if(reply) reply->setError(err); mLastError = err; } returnerr; } ~~~ OK,我们已发送了请求数据,假设马上就收到了回复,后续该怎么处理呢?来看executeCommand函数,如下所示: **IPCThreadState.cpp** ~~~ status_t IPCThreadState::executeCommand(int32_tcmd) { BBinder*obj; RefBase::weakref_type* refs; status_tresult = NO_ERROR; switch(cmd) { caseBR_ERROR: result = mIn.readInt32(); break; ...... caseBR_TRANSACTION: { binder_transaction_data tr; result = mIn.read(&tr, sizeof(tr)); if (result != NO_ERROR) break; Parcel buffer; Parcel reply; if (tr.target.ptr) { /* 看到了BBinder,想起图6-3了吗?BnServiceXXX从BBinder派生, 这里的b实际上就是实现BnServiceXXX的那个对象,关于它的作用,我们要在6.5节中讲解。 */ sp<BBinder> b((BBinder*)tr.cookie); const status_t error = b->transact(tr.code, buffer, &reply, 0); if (error < NO_ERROR)reply.setError(error); } else { /* the_context_object是IPCThreadState.cpp中定义的一个全局变量, 可通过setTheContextObject函数设置 */ const status_t error = the_context_object->transact(tr.code,buffer, &reply, 0); if (error < NO_ERROR) reply.setError(error); } break; ...... caseBR_DEAD_BINDER: { /* 收到binder驱动发来的service死掉的消息,看来只有Bp端能收到了, 后面,我们将会对此进行分析。 */ BpBinder *proxy = (BpBinder*)mIn.readInt32(); proxy->sendObituary(); mOut.writeInt32(BC_DEAD_BINDER_DONE); mOut.writeInt32((int32_t)proxy); }break; ...... case BR_SPAWN_LOOPER: //特别注意,这里将收到来自驱动的指示以创建一个新线程,用于和Binder通信。 mProcess->spawnPooledThread(false); break; default: result = UNKNOWN_ERROR; break; } ...... if(result != NO_ERROR) { mLastError = result; } returnresult; } ~~~ (3)打破砂锅问到底 你一定想知道如何和Binder设备交互的吧?是通过write和read函数来发送和接收请求的吗?来看talkwithDriver函数,如下所示: **IPCThreadState.cpp** ~~~ status_t IPCThreadState::talkWithDriver(booldoReceive) { // binder_write_read是用来与Binder设备交换数据的结构 binder_write_read bwr; constbool needRead = mIn.dataPosition() >= mIn.dataSize(); constsize_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; //请求命令的填充 bwr.write_size = outAvail; bwr.write_buffer = (long unsigned int)mOut.data(); if(doReceive && needRead) { //接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。 bwr.read_size = mIn.dataCapacity(); bwr.read_buffer = (long unsigned int)mIn.data(); } else { bwr.read_size = 0; } if((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; bwr.write_consumed = 0; bwr.read_consumed = 0; status_terr; do { #ifdefined(HAVE_ANDROID_OS) //看来不是read/write调用,而是ioctl方式。 if(ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) err = NO_ERROR; else err = -errno; #else err =INVALID_OPERATION; #endif }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; } returnerr; } ~~~ 较为深入地分析了MediaPlayerService的注册过程后,下面还剩最后两个函数了,就让我们向它们发起进攻吧!