來(lái)說(shuō)說(shuō)Looper的副業(yè)
epoll_wait返回后茵汰,下面處理事件廊勃,總共eventCount個(gè)事件,每個(gè)事件都有一個(gè)fd经窖,
fd == mWakeEventFd: 表示有新消息坡垫,另外的一個(gè)線程往這個(gè)線程的queue里發(fā)送消息時(shí)會(huì)往eventFd里寫(xiě)東西
fd != mWaveEventFd: Looper的副業(yè), 別的FD有事件
別的FD是上面時(shí)候添加到epoll的呢画侣?
Looper的 addFd允許添加別的fd冰悠,Looper的epoll統(tǒng)一監(jiān)聽(tīng)他們的事件,這就是Looper的副業(yè)
參數(shù) fd: Fd本身
參數(shù) events: 監(jiān)聽(tīng)這個(gè)fd的什么事件
參數(shù) callback: 事件觸發(fā)了的話回調(diào)這個(gè)callback
addOnFileDescriptorEventListener: java層的方法配乱,MessageQueue里
framework里有哪些地方用到了這個(gè)副業(yè)
這個(gè)fd是SurfaceFlinger創(chuàng)建的溉卓,將讀的fd跨進(jìn)程傳到應(yīng)用,在Choreographer所在的線程里將fd添加到Looper的epoll里搬泥,SurfaceFlinger通過(guò)這個(gè)Fd通知(往fd里寫(xiě)東西)應(yīng)用VSync信號(hào)來(lái) 了
系統(tǒng)服務(wù)通知應(yīng)用進(jìn)程的兩種方案:
epoll_wait+fd方案:
應(yīng)用端通過(guò)epoll_wait桑寨,系統(tǒng)服務(wù)發(fā)消息通知,消息發(fā)出去后忿檩,應(yīng)用端什么時(shí)候處理尉尾,在什么線程處理完全有應(yīng)用端自己決定,這樣就很靈活燥透,整個(gè)過(guò)程對(duì)兩方來(lái)說(shuō)都是異步的沙咏,
binder調(diào)用:
????openConnection連到系統(tǒng)服務(wù)并將binder對(duì)象(bpBinder)傳到SurfaceFlinger, surfaceFlinger有什么需要通知應(yīng)用端就通過(guò)bpBinder發(fā)起binder調(diào)用,在應(yīng)用端的班套,整個(gè)過(guò)程的處理都是在binder線程里肢藐,如果這個(gè)binder調(diào)用不是oneway的話,會(huì)阻塞系統(tǒng)服務(wù)吱韭,是oneway的話系統(tǒng)服務(wù)就不會(huì)阻塞吆豹,對(duì)系統(tǒng)服務(wù)來(lái)說(shuō)是異步的過(guò)程,但是對(duì)應(yīng)用端來(lái)說(shuō)就是一個(gè)同步的過(guò)程,因?yàn)樵趹?yīng)用端痘煤,一個(gè)binder請(qǐng)求完成后binder驅(qū)動(dòng)才會(huì)將下一個(gè)binder請(qǐng)求給到應(yīng)用端鸳吸。
結(jié)論:
對(duì)于簡(jiǎn)單的通知,epoll_wait+fd方案比較好速勇,對(duì)于跨進(jìn)程函數(shù)調(diào)用還是binder調(diào)用比較好。
demo工程坎拐,TestPipeFd烦磁,測(cè)試Looper的副業(yè)
MainActivity和MyService運(yùn)行在不同進(jìn)程
MainActivity bindService -> MyService onServiceConnected 將binder返回給MainActivity -> MainActiviy 創(chuàng)建一個(gè) 管道, 這個(gè)管道有一對(duì)描述符(讀寫(xiě))哼勇, MainActivity通過(guò) binder調(diào)用 pushlishReadFd將 讀描述符 傳到 MyService進(jìn)程 -> MyService 通過(guò)epoll_wait? 監(jiān)聽(tīng)這個(gè) 讀 FD -> MainActivity往這個(gè)FD里寫(xiě)了個(gè)消息 -> MyService epoll_wait 就監(jiān)聽(tīng)到了 讀Fd事件都伪,將消息讀出來(lái) 通過(guò) binder調(diào)用 sendReply 返回給MainActivity ->? MainActivity將其顯示出來(lái)
Demo代碼部分
mFds[0]: 讀描述符, mFds[1]: 寫(xiě)描述符积担, 往寫(xiě)描述符里寫(xiě)一個(gè)消息陨晶,讀描述符就能收到事件,并將消息讀出來(lái)
這里通過(guò)bindService回調(diào)binder調(diào)用publish將mFds[0]發(fā)送到MyService帝璧,而不是startService通過(guò)Intent 將 mFds[0]傳給MyService先誉,是因?yàn)镮ntent不能傳遞Fd
點(diǎn)擊MainActivity的一個(gè)按鈕觸發(fā)writePipe,
MyService 端的代碼
queue.addOnFileDescriptorEventListener(fd, EVENT_INPUT, this):? 監(jiān)聽(tīng)fd的可讀事件的烁,當(dāng)這個(gè)描述符有可讀事件時(shí)褐耳,就會(huì)回調(diào)
this(onFileDescriptorEvents方法, MessageQueue類(lèi)里)
mCallback.onRecv: binder調(diào)用將消息返回給MainActivity
總結(jié):
????1. Looper里可以監(jiān)聽(tīng)其他描述符
????????Looper不僅可以監(jiān)聽(tīng)MessageQueue里的描述符,還可以監(jiān)聽(tīng)?wèi)?yīng)用端傳給他的描述符渴庆,這個(gè)描述符可以是文件铃芦,管道,Socket襟雷, 監(jiān)聽(tīng)方法: MessageQueue.addOnFileDescriptorEventListener
2. 創(chuàng)建管道刃滓,跨進(jìn)程傳數(shù)據(jù),用looper監(jiān)聽(tīng)描述符事件
????????可以在應(yīng)用層創(chuàng)建管道耸弄,?ParcelFileDescriptor.createPipe 返回 描述符數(shù)組fd[0]:讀咧虎,fd[1]:寫(xiě), 將其中一個(gè)描述符傳到另外一個(gè)進(jìn)程(通過(guò)binder調(diào)用)计呈,在另外一個(gè)進(jìn)程監(jiān)聽(tīng)這個(gè)描述符的事件老客,在一個(gè)進(jìn)程往fd寫(xiě)消息,另外一個(gè)進(jìn)程就能讀到這個(gè)消息