Binder機制分析(2)——從MediaService中看Binder的實現和使用(2)

yangxi_001發表於2016-12-27

本文是對《Android技術內幕-系統卷》第三章的摘抄和整理。


1. 如果我們要使用MediaPlayerService服務,那麼MediaPlayerService客戶端就需要與MediaPlayerService(即BnMediaPlayerService)互動。互動的過程需要建立一個迴圈,然後讀寫Binder裝置。注意,在BnMediaPlayerService中並沒有開啟Binder裝置和建立一個迴圈監聽,這裡實際上是借用ProcessState來完成了MediaPlayerService的一些功能,下面我們繼續分析。


    前面說過,ProcessState會維護一個程式中的所有服務(Server)代理,每個程式中只能有一個;當然,也包括需要維護這裡的MediaPlayerService服務的代理。因此,在main_mediaserver.cpp的main函式中,緊接著由“ProcessState::self()->startThreadPool();”來建立一個執行緒池並啟動,而執行緒池PoolThread又繼承自執行緒Thread。因此,當PoolThread在執行run函式啟動時,會執行Thread的run函式(位於“framework\base\libs\utils\thread.cpp中”),如程式碼所示。

    Thread::run的實現
    status_t Thread::run(const char  
    name, int32_t priority, size_t stack)  
    {  
        //省略部分程式碼  
        if (mCanCallJava) {  
            res = createThreadEtc(_threadLoop,  
                    this, name, priority, stack, &mThread);  
        } else {  
            res = AndroidCreateRawThreadEtc(_threadLoop,  
                    this, name, priority, stack, &mThread);  
        }  
        //省略部分程式碼  
        return NO_ERROR;  
    } 

2. 這裡通過createThreadEtc建立了一個執行緒,執行緒函式為_threadLoop,因此,在_threadLoop函式中又呼叫了IPCThreadState::self()->joinThreadPool。注意,在main_mediaserver.cpp的main函式中也會呼叫IPCThreadState::self()->joinThreadPool,也就是說,主執行緒和工作執行緒都會執行joinThreadPool;在該函式中通過talkWithDriver函式操作Binder驅動程式,executeCommand函式來執行命令。檢視executeCommand的程式碼可以得知,實際上會根據不同的命令進行不同的解析,但是最終的解析還是呼叫BBinder::transact函式,而transact又呼叫了自己的BBinder::onTransact函式。這裡的BnMediaPlayerService繼承自BBinder,所以會呼叫到它自己的BnMediaPlayerService::onTransact函式。

3. 最後,如果我們需要使用MediaPlayerService,那麼首先就需要建立一個BpMediaPlayer Service,建立過程大致如程式碼清單3-62所示。
    建立BpMediaPlayerService的過程
    sp<IServiceManager> sm = defaultServiceManager();  
    sp<IBinder> binder;  
    do {  
        //查詢MediaPlayerService,返回Binder  
        binder = sm->getService(String16("media.player"));  
        if (binder != 0) {  
                    break;  
        }  
        usleep(500000); // 0.5 s  
     } while(true);  
    sMediaPlayerService = interface_cast<IMediaPlayerService>(binder); 

    其過程為:首先通過defaultServiceManager函式獲得ServiceManager物件,然後呼叫Service Manager::getService查詢指定名稱(media.player)的MediaPlayerService服務,再通過interface_cast將查詢得到的Binder轉化成BpMediaPlayerService物件。這樣,BpMediaPlayerService就可以與BnMediaPlayerService進行通訊了。


轉自:http://blog.csdn.net/ljsbuct/article/details/7106858

相關文章