// establish binder interface to MediaPlayerService
/*static*/constsp<IMediaPlayerService>&IMediaDeathNotifier::getMediaPlayerService(){LOGV("getMediaPlayerService");Mutex::Autolock_l(sServiceLock);if(sMediaPlayerService.get()==0){sp<IServiceManager>sm=defaultServiceManager();sp<IBinder>binder;do{binder=sm->getService(String16("media.player"));if(binder!=0){break;}LOGW("Media player service not published, waiting...");usleep(500000);// 0.5 s
}while(true);if(sDeathNotifier==NULL){sDeathNotifier=newDeathNotifier();}binder->linkToDeath(sDeathNotifier);sMediaPlayerService=interface_cast<IMediaPlayerService>(binder);}LOGE_IF(sMediaPlayerService==0,"no media player service!?");returnsMediaPlayerService;}
classBpServiceManager:publicBpInterface<IServiceManager>{......virtualsp<IBinder>getService(constString16&name)const{unsignedn;for(n=0;n<5;n++){sp<IBinder>svc=checkService(name);if(svc!=NULL)returnsvc;LOGI("Waiting for service %s...\n",String8(name).string());sleep(1);}returnNULL;}virtualsp<IBinder>checkService(constString16&name)const{Parceldata,reply;data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());data.writeString16(name);remote()->transact(CHECK_SERVICE_TRANSACTION,data,&reply);returnreply.readStrongBinder();}......};
在BpServiceManager::checkService中,首先是通过Parcel::writeInterfaceToken往data写入一个RPC头,这个我们在Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析一文已经介绍过了,就是写往data里面写入了一个整数和一个字符串“android.os.IServiceManager”, Service Manager来处理CHECK_SERVICE_TRANSACTION请求之前,会先验证一下这个RPC头,看看是否正确。接着再往data写入一个字符串name,这里就是“media.player”了。回忆一下Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析这篇文章,那里已经往Service Manager中注册了一个名字为“media.player”的MediaPlayerService。
status_tBpBinder::transact(uint32_tcode,constParcel&data,Parcel*reply,uint32_tflags){// Once a binder has died, it will never come back to life.
if(mAlive){status_tstatus=IPCThreadState::self()->transact(mHandle,code,data,reply,flags);if(status==DEAD_OBJECT)mAlive=0;returnstatus;}returnDEAD_OBJECT;}
status_tIPCThreadState::waitForResponse(Parcel*reply,status_t*acquireResult){int32_tcmd;int32_terr;while(1){if((err=talkWithDriver())<NO_ERROR)break;err=mIn.errorCheck();if(err<NO_ERROR)break;if(mIn.dataAvail()==0)continue;cmd=mIn.readInt32();IF_LOG_COMMANDS(){alog<<"Processing waitForResponse Command: "<<getReturnString(cmd)<<endl;}switch(cmd){caseBR_TRANSACTION_COMPLETE:if(!reply&&!acquireResult)gotofinish;break;caseBR_DEAD_REPLY:err=DEAD_OBJECT;gotofinish;caseBR_FAILED_REPLY:err=FAILED_TRANSACTION;gotofinish;caseBR_ACQUIRE_RESULT:{LOG_ASSERT(acquireResult!=NULL,"Unexpected brACQUIRE_RESULT");constint32_tresult=mIn.readInt32();if(!acquireResult)continue;*acquireResult=result?NO_ERROR:INVALID_OPERATION;}gotofinish;caseBR_REPLY:{binder_transaction_datatr;err=mIn.read(&tr,sizeof(tr));LOG_ASSERT(err==NO_ERROR,"Not enough command data for brREPLY");if(err!=NO_ERROR)gotofinish;if(reply){if((tr.flags&TF_STATUS_CODE)==0){reply->ipcSetDataReference(reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),tr.data_size,reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),tr.offsets_size/sizeof(size_t),freeBuffer,this);}else{err=*static_cast<conststatus_t*>(tr.data.ptr.buffer);freeBuffer(NULL,reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),tr.data_size,reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),tr.offsets_size/sizeof(size_t),this);}}else{freeBuffer(NULL,reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),tr.data_size,reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),tr.offsets_size/sizeof(size_t),this);continue;}}gotofinish;default:err=executeCommand(cmd);if(err!=NO_ERROR)gotofinish;break;}}finish:if(err!=NO_ERROR){if(acquireResult)*acquireResult=err;if(reply)reply->setError(err);mLastError=err;}returnerr;}
status_tIPCThreadState::talkWithDriver(booldoReceive){LOG_ASSERT(mProcess->mDriverFD>=0,"Binder driver is not opened");binder_write_readbwr;// Is the read buffer empty?
constboolneedRead=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.
constsize_toutAvail=(!doReceive||needRead)?mOut.dataSize():0;bwr.write_size=outAvail;bwr.write_buffer=(longunsignedint)mOut.data();// This is what we'll read.
if(doReceive&&needRead){bwr.read_size=mIn.dataCapacity();bwr.read_buffer=(longunsignedint)mIn.data();}else{bwr.read_size=0;}......// Return immediately if there is nothing to do.
if((bwr.write_size==0)&&(bwr.read_size==0))returnNO_ERROR;bwr.write_consumed=0;bwr.read_consumed=0;status_terr;do{......#if defined(HAVE_ANDROID_OS)
if(ioctl(mProcess->mDriverFD,BINDER_WRITE_READ,&bwr)>=0)err=NO_ERROR;elseerr=-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);elsemOut.setDataSize(0);}if(bwr.read_consumed>0){mIn.setDataSize(bwr.read_consumed);mIn.setDataPosition(0);}......returnNO_ERROR;}returnerr;}
structbinder_write_read{signedlongwrite_size;/* bytes to write */signedlongwrite_consumed;/* bytes consumed by driver */unsignedlongwrite_buffer;signedlongread_size;/* bytes to read */signedlongread_consumed;/* bytes consumed by driver */unsignedlongread_buffer;};
staticintbinder_thread_read(structbinder_proc*proc,structbinder_thread*thread,void__user*buffer,intsize,signedlong*consumed,intnon_block){void__user*ptr=buffer+*consumed;void__user*end=buffer+size;intret=0;intwait_for_proc_work;if(*consumed==0){if(put_user(BR_NOOP,(uint32_t__user*)ptr))return-EFAULT;ptr+=sizeof(uint32_t);}retry:wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);......if(wait_for_proc_work){......}else{if(non_block){if(!binder_has_thread_work(thread))ret=-EAGAIN;}elseret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread));}......while(1){uint32_tcmd;structbinder_transaction_datatr;structbinder_work*w;structbinder_transaction*t=NULL;if(!list_empty(&thread->todo))w=list_first_entry(&thread->todo,structbinder_work,entry);elseif(!list_empty(&proc->todo)&&wait_for_proc_work)w=list_first_entry(&proc->todo,structbinder_work,entry);else{if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/* no data added */gotoretry;break;}if(end-ptr<sizeof(tr)+4)break;switch(w->type){......caseBINDER_WORK_TRANSACTION_COMPLETE:{cmd=BR_TRANSACTION_COMPLETE;if(put_user(cmd,(uint32_t__user*)ptr))return-EFAULT;ptr+=sizeof(uint32_t);binder_stat_br(proc,thread,cmd);if(binder_debug_mask&BINDER_DEBUG_TRANSACTION_COMPLETE)printk(KERN_INFO"binder: %d:%d BR_TRANSACTION_COMPLETE\n",proc->pid,thread->pid);list_del(&w->entry);kfree(w);binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++;}break;......}if(!t)continue;......}done:......return0;}
staticintbinder_thread_read(structbinder_proc*proc,structbinder_thread*thread,void__user*buffer,intsize,signedlong*consumed,intnon_block){void__user*ptr=buffer+*consumed;void__user*end=buffer+size;intret=0;intwait_for_proc_work;if(*consumed==0){if(put_user(BR_NOOP,(uint32_t__user*)ptr))return-EFAULT;ptr+=sizeof(uint32_t);}retry:wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);......if(wait_for_proc_work){......if(non_block){if(!binder_has_proc_work(proc,thread))ret=-EAGAIN;}elseret=wait_event_interruptible_exclusive(proc->wait,binder_has_proc_work(proc,thread));}else{......}......while(1){uint32_tcmd;structbinder_transaction_datatr;structbinder_work*w;structbinder_transaction*t=NULL;if(!list_empty(&thread->todo))w=list_first_entry(&thread->todo,structbinder_work,entry);elseif(!list_empty(&proc->todo)&&wait_for_proc_work)w=list_first_entry(&proc->todo,structbinder_work,entry);else{if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/* no data added */gotoretry;break;}if(end-ptr<sizeof(tr)+4)break;switch(w->type){caseBINDER_WORK_TRANSACTION:{t=container_of(w,structbinder_transaction,work);}break;......}if(!t)continue;BUG_ON(t->buffer==NULL);if(t->buffer->target_node){structbinder_node*target_node=t->buffer->target_node;tr.target.ptr=target_node->ptr;tr.cookie=target_node->cookie;t->saved_priority=task_nice(current);if(t->priority<target_node->min_priority&&!(t->flags&TF_ONE_WAY))binder_set_nice(t->priority);elseif(!(t->flags&TF_ONE_WAY)||t->saved_priority>target_node->min_priority)binder_set_nice(target_node->min_priority);cmd=BR_TRANSACTION;}else{......}tr.code=t->code;tr.flags=t->flags;tr.sender_euid=t->sender_euid;if(t->from){structtask_struct*sender=t->from->proc->tsk;tr.sender_pid=task_tgid_nr_ns(sender,current->nsproxy->pid_ns);}else{......}tr.data_size=t->buffer->data_size;tr.offsets_size=t->buffer->offsets_size;tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset;tr.data.ptr.offsets=tr.data.ptr.buffer+ALIGN(t->buffer->data_size,sizeof(void*));if(put_user(cmd,(uint32_t__user*)ptr))return-EFAULT;ptr+=sizeof(uint32_t);if(copy_to_user(ptr,&tr,sizeof(tr)))return-EFAULT;ptr+=sizeof(tr);......list_del(&t->work.entry);t->buffer->allow_user_free=1;if(cmd==BR_TRANSACTION&&!(t->flags&TF_ONE_WAY)){t->to_parent=thread->transaction_stack;t->to_thread=thread;thread->transaction_stack=t;}else{......}break;}done:*consumed=ptr-buffer;......return0;}
intsvcmgr_handler(structbinder_state*bs,structbinder_txn*txn,structbinder_io*msg,structbinder_io*reply){structsvcinfo*si;uint16_t*s;unsignedlen;void*ptr;uint32_tstrict_policy;// LOGI("target=%p code=%d pid=%d uid=%d\n",
// txn->target, txn->code, txn->sender_pid, txn->sender_euid);
if(txn->target!=svcmgr_handle)return-1;// Equivalent to Parcel::enforceInterface(), reading the RPC
// header with the strict mode policy mask and the interface name.
// Note that we ignore the strict_policy and don't propagate it
// further (since we do no outbound RPCs anyway).
strict_policy=bio_get_uint32(msg);s=bio_get_string16(msg,&len);if((len!=(sizeof(svcmgr_id)/2))||memcmp(svcmgr_id,s,sizeof(svcmgr_id))){fprintf(stderr,"invalid id %s\n",str8(s));return-1;}switch(txn->code){caseSVC_MGR_GET_SERVICE:caseSVC_MGR_CHECK_SERVICE:s=bio_get_string16(msg,&len);ptr=do_find_service(bs,s,len);if(!ptr)break;bio_put_ref(reply,ptr);return0;......}default:LOGE("unknown code %d\n",txn->code);return-1;}bio_put_uint32(reply,0);return0;}
这里, Service Manager要处理的code是SVC_MGR_CHECK_SERVICE,这是在前面的BpServiceManager::checkService函数里面设置的。
staticintbinder_thread_read(structbinder_proc*proc,structbinder_thread*thread,void__user*buffer,intsize,signedlong*consumed,intnon_block){void__user*ptr=buffer+*consumed;void__user*end=buffer+size;intret=0;intwait_for_proc_work;if(*consumed==0){if(put_user(BR_NOOP,(uint32_t__user*)ptr))return-EFAULT;ptr+=sizeof(uint32_t);}retry:wait_for_proc_work=thread->transaction_stack==NULL&&list_empty(&thread->todo);......if(wait_for_proc_work){......}else{if(non_block){if(!binder_has_thread_work(thread))ret=-EAGAIN;}elseret=wait_event_interruptible(thread->wait,binder_has_thread_work(thread));}......while(1){uint32_tcmd;structbinder_transaction_datatr;structbinder_work*w;structbinder_transaction*t=NULL;if(!list_empty(&thread->todo))w=list_first_entry(&thread->todo,structbinder_work,entry);elseif(!list_empty(&proc->todo)&&wait_for_proc_work)w=list_first_entry(&proc->todo,structbinder_work,entry);else{if(ptr-buffer==4&&!(thread->looper&BINDER_LOOPER_STATE_NEED_RETURN))/* no data added */gotoretry;break;}......switch(w->type){caseBINDER_WORK_TRANSACTION:{t=container_of(w,structbinder_transaction,work);}break;......}if(!t)continue;BUG_ON(t->buffer==NULL);if(t->buffer->target_node){......}else{tr.target.ptr=NULL;tr.cookie=NULL;cmd=BR_REPLY;}tr.code=t->code;tr.flags=t->flags;tr.sender_euid=t->sender_euid;if(t->from){......}else{tr.sender_pid=0;}tr.data_size=t->buffer->data_size;tr.offsets_size=t->buffer->offsets_size;tr.data.ptr.buffer=(void*)t->buffer->data+proc->user_buffer_offset;tr.data.ptr.offsets=tr.data.ptr.buffer+ALIGN(t->buffer->data_size,sizeof(void*));if(put_user(cmd,(uint32_t__user*)ptr))return-EFAULT;ptr+=sizeof(uint32_t);if(copy_to_user(ptr,&tr,sizeof(tr)))return-EFAULT;ptr+=sizeof(tr);......list_del(&t->work.entry);t->buffer->allow_user_free=1;if(cmd==BR_TRANSACTION&&!(t->flags&TF_ONE_WAY)){......}else{t->buffer->transaction=NULL;kfree(t);binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++;}break;}done:......return0;}
status_tIPCThreadState::waitForResponse(Parcel*reply,status_t*acquireResult){int32_tcmd;int32_terr;while(1){if((err=talkWithDriver())<NO_ERROR)break;......cmd=mIn.readInt32();......switch(cmd){......caseBR_REPLY:{binder_transaction_datatr;err=mIn.read(&tr,sizeof(tr));LOG_ASSERT(err==NO_ERROR,"Not enough command data for brREPLY");if(err!=NO_ERROR)gotofinish;if(reply){if((tr.flags&TF_STATUS_CODE)==0){reply->ipcSetDataReference(reinterpret_cast<constuint8_t*>(tr.data.ptr.buffer),tr.data_size,reinterpret_cast<constsize_t*>(tr.data.ptr.offsets),tr.offsets_size/sizeof(size_t),freeBuffer,this);}else{......}}else{......}}gotofinish;......}}finish:......returnerr;}
voidParcel::ipcSetDataReference(constuint8_t*data,size_tdataSize,constsize_t*objects,size_tobjectsCount,release_funcrelFunc,void*relCookie){freeDataNoInit();mError=NO_ERROR;mData=const_cast<uint8_t*>(data);mDataSize=mDataCapacity=dataSize;//LOGI("setDataReference Setting data size of %p to %lu (pid=%d)\n", this, mDataSize, getpid());
mDataPos=0;LOGV("setDataReference Setting data pos of %p to %d\n",this,mDataPos);mObjects=const_cast<size_t*>(objects);mObjectsSize=mObjectsCapacity=objectsCount;mNextObjectHint=0;mOwner=relFunc;mOwnerCookie=relCookie;scanForFds();}
sp<IBinder>ProcessState::getStrongProxyForHandle(int32_thandle){sp<IBinder>result;AutoMutex_l(mLock);handle_entry*e=lookupHandleLocked(handle);if(e!=NULL){// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder*b=e->binder;if(b==NULL||!e->refs->attemptIncWeak(this)){b=newBpBinder(handle);e->binder=b;if(b)e->refs=b->getWeakRefs();result=b;}else{// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);e->refs->decWeak(this);}}returnresult;}
Preview: