標籤:android binder mediaplayer server ipc
在講它們之間的通訊之前,我們先以MediaServer為例看看普通Server進程都在幹些什麼。
int main(){……// 獲得ProcessState執行個體sp<ProcessState> proc(ProcessState::self());// 得到ServiceManager的Binder用戶端執行個體 sp<IServiceManager> sm = defaultServiceManager();……// 通過ServiceManager的Binder用戶端向系統註冊MediaPlayer服務 MediaPlayerService::instantiate(); ……// start run ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();}
defaultServiceManager()在上一篇中已經有介紹。
MediaPlayerService::instantiate()的實現如下,就是addService到ServiceManager,和上一篇的getService類似,故不作介紹。
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}接下來看ProcessState::self()->startThreadPool()的實現
void ProcessState::startThreadPool(){ AutoMutex _l(mLock); if (!mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); }}void ProcessState::spawnPooledThread(bool isMain){ if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); ALOGV("Spawning new pooled thread, name=%s\n", name.string()); sp<Thread> t = new PoolThread(isMain); t->run(name.string()); }}
class PoolThread : public Thread{public: PoolThread(bool isMain) : mIsMain(isMain) { } protected: virtual bool threadLoop() { IPCThreadState::self()->joinThreadPool(mIsMain); return false; } const bool mIsMain;};實際上,這個函數不過是建立了一個新的線程,然後線上程中又建立了一個IPCThreadState,並調用了joinThreadPool函數。
void IPCThreadState::joinThreadPool(bool isMain){ mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); set_sched_policy(mMyThreadId, SP_FOREGROUND); status_t result; do { processPendingDerefs(); // now get the next command to be processed, waiting if necessary result = getAndExecuteCommand(); if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) { ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting", mProcess->mDriverFD, result); abort(); } // Let this thread exit the thread pool if it is no longer // needed and it is not the main process thread. if(result == TIMED_OUT && !isMain) { break; } } while (result != -ECONNREFUSED && result != -EBADF); mOut.writeInt32(BC_EXIT_LOOPER); talkWithDriver(false);}
status_t IPCThreadState::getAndExecuteCommand(){ status_t result; int32_t cmd; result = talkWithDriver(); if (result >= NO_ERROR) { size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) return result; cmd = mIn.readInt32(); result = executeCommand(cmd); set_sched_policy(mMyThreadId, SP_FOREGROUND); } return result;}
我們可以看到,主線程和新建立的線程,都在做一件事,talkWithDriver讀取Binder驅動,然後就executeCommand處理請求。這就是普通Server進程啟動後一直都在乾的事:等待用戶端請求,處理請求,然後返回給用戶端。
既然Server進程已經準備就緒了,那麼現在就應該要輪到Client端閃亮登場,Client端將通過Binder來請求Server做一些事情。接下來看代碼:
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length){ status_t err = UNKNOWN_ERROR; const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(fd, offset, length))) { player.clear(); } err = attachNewPlayer(player); } return err;}
getMediaPlayerService()之前分析過,返回一個BpMediaPlayerService,這裡問一個問題:為什麼這個BpMediaPlayerService就能和MediaPlayerService進程進行Binder通訊,而不是和別的什麼Server進程?
再回顧一下代碼:
/*static*/const sp<IMediaPlayerService>&IMediaDeathNotifier::getMediaPlayerService(){ Mutex::Autolock _l(sServiceLock); if (sMediaPlayerService == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { binder = sm->getService(String16("media.player")); if (binder != 0) { break; } ALOGW("Media player service not published, waiting..."); usleep(500000); // 0.5 s } while (true); if (sDeathNotifier == NULL) { sDeathNotifier = new DeathNotifier(); } binder->linkToDeath(sDeathNotifier); sMediaPlayerService = interface_cast<IMediaPlayerService>(binder); } ALOGE_IF(sMediaPlayerService == 0, "no media player service!?"); return sMediaPlayerService;}答案應該在binder = sm->getService(String16("media.player"))這句話裡面,返回值binder將會作為BpMediaPlayerService建構函式的參數。下面來看getService
virtual sp<IBinder> getService(const String16& name) const { unsigned n; for (n = 0; n < 5; n++){ sp<IBinder> svc = checkService(name); if (svc != NULL) return svc; ALOGI("Waiting for service %s...\n", String8(name).string()); sleep(1); } return NULL; } virtual sp<IBinder> 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(); }sp<IBinder> Parcel::readStrongBinder() const{ sp<IBinder> val; unflatten_binder(ProcessState::self(), *this, &val); return val;}status_t unflatten_binder(const sp<ProcessState>& proc, const Parcel& in, sp<IBinder>* out){ const flat_binder_object* flat = in.readObject(false); if (flat) { switch (flat->type) { case BINDER_TYPE_BINDER: *out = static_cast<IBinder*>(flat->cookie); return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_HANDLE: *out = proc->getStrongProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in); } } return BAD_TYPE;}
unflatten_binder函數中,flat->type和flat->handle在ServiceManager中被賦值,其中flat->type的值是BINDER_TYPE_HANDLE,flat->handle的值是所查詢Service對應的Handle值,中間過程涉及到binder底層驅動的代碼,不在這裡闡述。
這樣binder = sm->getService(String16("media.player"))執行後,binder=BpBinder(Handle),其中Handle的值為所查詢Service對應的Handle值,這樣,client端和service端之間的通訊就建立了。
分析完getMediaPlayerService(),建立了通訊的通路,接下來正式進入通訊。
sp<IMediaPlayer>player(service->create(this, mAudioSessionId));
進入IMediaPlayerService.cpp看看create的實現。
virtual sp<IMediaPlayer> create( const sp<IMediaPlayerClient>& client, int audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeStrongBinder(client->asBinder()); data.writeInt32(audioSessionId); remote()->transact(CREATE, data, &reply); return interface_cast<IMediaPlayer>(reply.readStrongBinder()); }經過之前的分析,我們可以很容易的指導remote()返回的是BpBinder(handle), transact(CREATE,data, &reply)將資料寫入到Binder驅動,並喚醒Service進程,接下來我們就來看Server將作何反應。現在我們已經知道,Server進程一直都在讀取Binder驅動,然後executeCommand,下面就直接看executeCommand的實現。
status_t IPCThreadState::executeCommand(int32_t cmd){ BBinder* obj; RefBase::weakref_type* refs; status_t result = NO_ERROR; switch (cmd) { …… case BR_TRANSACTION: { binder_transaction_data tr; result = mIn.read(&tr, sizeof(tr)); ALOG_ASSERT(result == NO_ERROR, "Not enough command data for brTRANSACTION"); if (result != NO_ERROR) break; Parcel buffer; buffer.ipcSetDataReference( reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size, reinterpret_cast<const size_t*>(tr.data.ptr.offsets), tr.offsets_size/sizeof(size_t), freeBuffer, this); const pid_t origPid = mCallingPid; const uid_t origUid = mCallingUid; mCallingPid = tr.sender_pid; mCallingUid = tr.sender_euid; int curPrio = getpriority(PRIO_PROCESS, mMyThreadId); if (gDisableBackgroundScheduling) { if (curPrio > ANDROID_PRIORITY_NORMAL) { // We have inherited a reduced priority from the caller, but do not // want to run in that state in this process. The driver set our // priority already (though not our scheduling class), so bounce // it back to the default before invoking the transaction. setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL); } } else { if (curPrio >= ANDROID_PRIORITY_BACKGROUND) { // We want to use the inherited priority from the caller. // Ensure this thread is in the background scheduling class, // since the driver won't modify scheduling classes for us. // The scheduling group is reset to default by the caller // once this method returns after the transaction is complete. set_sched_policy(mMyThreadId, SP_BACKGROUND); } } //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); Parcel reply; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BR_TRANSACTION thr " << (void*)pthread_self() << " / obj " << tr.target.ptr << " / code " << TypeCode(tr.code) << ": " << indent << buffer << dedent << endl << "Data addr = " << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer) << ", offsets addr=" << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl; } if (tr.target.ptr) { sp<BBinder> b((BBinder*)tr.cookie); const status_t error = b->transact(tr.code, buffer, &reply, tr.flags); if (error < NO_ERROR) reply.setError(error); } else { const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags); if (error < NO_ERROR) reply.setError(error); } //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n", // mCallingPid, origPid, origUid); if ((tr.flags & TF_ONE_WAY) == 0) { LOG_ONEWAY("Sending reply to %d!", mCallingPid); sendReply(reply, 0); } else { LOG_ONEWAY("NOT sending reply to %d!", mCallingPid); } mCallingPid = origPid; mCallingUid = origUid; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj " << tr.target.ptr << ": " << indent << reply << dedent << endl; } } break; …… default: printf("*** BAD COMMAND %d received from Binder driver\n", cmd); result = UNKNOWN_ERROR; break; } if (result != NO_ERROR) { mLastError = result; } return result;}
看這裡:
if (tr.target.ptr) {sp<BBinder> b((BBinder*)tr.cookie);const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);if (error < NO_ERROR) reply.setError(error);} else {const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);if (error < NO_ERROR) reply.setError(error);}這裡的b實際上就是我們在addService時建立的MediaPlayerService對象,經過包括Binder驅動在內的傳輸和轉換,就成這麼個資料類型了。
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}
看下面的繼承關係,
classMediaPlayerService : public BnMediaPlayerService
MediaPlayerService本身沒有實現transact方法,因此,b->transact(tr.code,buffer, &reply, tr.flags)是調用了BnMediaPlayerService的transact方法。
進入IMediaPlayerService.cpp中找到BnMediaPlayerService的transact方法,如下:
status_t BnMediaPlayerService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ switch (code) { case CREATE: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder()); int audioSessionId = data.readInt32(); sp<IMediaPlayer> player = create(client, audioSessionId); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break;……}sp<IMediaPlayer> player = create(client,audioSessionId)這裡調用的create方法在MediaPlayerService類中實現,進入MediaPlayerService.cpp中:
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client, int audioSessionId){ pid_t pid = IPCThreadState::self()->getCallingPid(); int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client( this, pid, connId, client, audioSessionId, IPCThreadState::self()->getCallingUid()); ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid, IPCThreadState::self()->getCallingUid()); /* add by Gary. start {{----------------------------------- */ c->setScreen(mScreen); /* add by Gary. end -----------------------------------}} */ c->setSubGate(mGlobalSubGate); // 2012-03-12, add the global interfaces to control the subtitle gate wp<Client> w = c; { Mutex::Autolock lock(mLock); mClients.add(w); } return c;}到這裡為止,Server處理完了事務,接下來將處理結果返回給client,看這裡:
if ((tr.flags & TF_ONE_WAY) == 0) {LOG_ONEWAY("Sending reply to %d!", mCallingPid);sendReply(reply, 0);} else {LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);}status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags){ status_t err; status_t statusBuffer; err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer); if (err < NO_ERROR) return err; return waitForResponse(NULL, NULL);}調用sendReply將結果寫回Binder驅動,從而得以返回client進程。通訊完成。