深入理解Camera 四(相機服務(wù)層)

和你一起終身學習,這里是程序員Android
經(jīng)典好文推薦,通過閱讀本文,您將收獲以下知識點:
一、簡介
二、Camera AIDL 接口
三、Camera Service 主程序
相機服務(wù)層
一、簡介
Camera Service被設(shè)計成一個獨立進程,作為一個服務(wù)端,處理來自Camera Framework 客戶端的跨進程請求,并在內(nèi)部進行一定的操作,隨后作為客戶端將請求再一次發(fā)送至作為服務(wù)端的Camera Provider,整個流程涉及到了兩個跨進程操作,前者通過AIDL機制實現(xiàn),后者通過HIDL機制實現(xiàn),由于在于Camera Provider通信的過程中,Service是作為客戶端存在的,所以此處我們重點關(guān)注AIDL以及Camera Service 主程序的實現(xiàn)。

程序Android 轉(zhuǎn)于網(wǎng)絡(luò)圖片
二、Camera AIDL 接口
在介紹Camera AIDL之前,不妨來簡單了解下何為AIDL,谷歌為什么要實現(xiàn)這么一套機制?
在Android系統(tǒng)中,兩個進程通常無法相互訪問對方的內(nèi)存,為了解決該問題,谷歌提出了Messager/廣播以及后來的Binder,來解決這個問題,但是如果某個進程需要對另一個進程中進行多線程的并發(fā)訪問,Messager和廣播效果往往不是很好,所以Binder會作為主要實現(xiàn)方式,但是Binder的接口使用起來比較復雜,對開發(fā)者特別是初學者并不是很友好,所以為了降低跨進程開發(fā)門檻,谷歌開創(chuàng)性地提出了AIDL(自定義語言)機制,主動封裝了Binder的實現(xiàn)細節(jié),提供給開發(fā)者較為簡單的使用接口,極大地提升了廣大開發(fā)者的開發(fā)效率。
按照谷歌的針對AIDL機制的要求,需要服務(wù)端創(chuàng)建一系列*.aidl文件,并在其中定義需要提供給客戶端的公共接口,并且予以實現(xiàn),接下來我們來看下幾個主要的aidl文件。

程序Android 轉(zhuǎn)于網(wǎng)絡(luò)圖片
ICameraService.aidl定義了ICameraService 接口,實現(xiàn)主要通過CameraService類來實現(xiàn),主要接口如下:
getNumberOfCameras:獲取系統(tǒng)中支持的Camera 個數(shù)
connectDevice():打開一個Camera 設(shè)備
addListener(): 添加針對Camera 設(shè)備以及閃光燈的監(jiān)聽對象
ICameraDeviceCallbacks.aidl文件中定義了ICameraDeviceCallbacks接口,其實現(xiàn)主要由Framework中的CameraDeviceCallbacks類進行實現(xiàn),主要接口如下:
onResultReceived:一旦Service收到結(jié)果數(shù)據(jù),便會調(diào)用該接口發(fā)送至Framework
onCaptureStarted():一旦開始進行圖像的采集,便調(diào)用該接口將部分信息以及時間戳上傳至Framework
onDeviceError(): 一旦發(fā)生了錯誤,通過調(diào)用該接口通知Framework
ICameraDeviceUser.aidl定義了ICameraDeviceUser接口,由CameraDeviceClient最終實現(xiàn),主要接口如下:
disconnect:關(guān)閉Camera 設(shè)備
submitRequestList:發(fā)送request
beginConfigure:開始配置Camera 設(shè)備,需要在所有關(guān)于數(shù)據(jù)流的操作之前
endConfigure:結(jié)束關(guān)于Camera 設(shè)備的配置,該接口需要在所有Request下發(fā)之前被調(diào)用
createDefaultRequest:創(chuàng)建一個具有默認配置的Request
ICameraServiceListener.aidl定義了ICameraServiceListener接口,由Framework中的CameraManagerGlobal類實現(xiàn),主要接口如下:
onStatusChanged:用于告知當前Camera 設(shè)備的狀態(tài)的變更
三、Camera Service 主程序
Camera Service 主程序,是隨著系統(tǒng)啟動而運行,主要目的是向外暴露AIDL接口給Framework進行調(diào)用,同時通過調(diào)用Camera Provider的HIDL接口,建立與Provider的通信,并且在內(nèi)部維護從Framework以及Provider獲取到的資源,并且按照一定的框架結(jié)構(gòu)保持整個Service在穩(wěn)定高效的狀態(tài)下運行,所以接下來我們主要通過幾個關(guān)鍵類、初始化過程以及處理來自App的請求三個部分來詳細介紹下。
1. 關(guān)鍵類解析
首先我們來看下幾個關(guān)鍵類,Camera Service中主要包含了以下幾個類,用于提供AIDL接口,并負責內(nèi)部一系列邏輯的控制,并且通過HIDL接口保持與Provider的通信。

程序Android 轉(zhuǎn)于網(wǎng)絡(luò)圖片
首先我們看下CameraService的這個類,它主要實現(xiàn)了AIDL中ICameraService 接口,并且暴露給Camera Framework進行調(diào)用,這個類在初始化的時候會去實例化一個CameraProviderManager對象,而在實例化的過程中,該對象會去獲取系統(tǒng)中所有的Camera Provider,并且在其內(nèi)部實例化了對應Provider個數(shù)的ProviderInfo對象,并且隨著每一個ProviderInfo的實例化,將一個Camera Provider作為參數(shù)存入ProviderInfo中,并且最終將所有的ProviderInfo存入一個vec容器中進行統(tǒng)一管理,就這樣,CameraProviderManager便達到了管理所有的Camera Provider的目的。
而對于單個ProviderInfo而言,內(nèi)部會維護一個Camera Provider代理,而在系統(tǒng)運行初期,ProviderInfo會去向Camera Provider獲取當前這設(shè)備所支持的Camera 設(shè)備,拿到Camera Provider中的ICameraDevice代理,并且依次存入提前實例化好的DeviceInfo3對象中,最后會將所有的DeviceInfo3存入一個內(nèi)部容器,進行統(tǒng)一管理,而DeviceInfo3維護著Camera Provider中的ICameraDevice代理,保持了對Camera Provider的控制。
另外,Camera Service 中還包含了CameraDeviceClient類,該類在打開設(shè)備的時候被實例化,一次打開設(shè)備的操作對應一個該類對象,它實現(xiàn)了ICameraDeviceUser接口,以AIDL方式暴露接口給Camera Framework進行調(diào)用,于此同時,該類在打開設(shè)備的過程中,獲取了來自Camera Framework對于ICameraDeviceCallback接口的實現(xiàn)代理,通過該代理可以將結(jié)果上傳至Camera Framework中,其中還包含了一個Camera3Device以及FrameProcessorBase,Camera3Device主要實現(xiàn)了對Camera Provider 的ICameraDeviceCallbacks會調(diào)接口的實現(xiàn),通過該接口接收來自Provider的結(jié)果上傳,進而傳給CameraDeviceClient以及FrameProcessBase,其中,Camera3Device會將事件通過notify方法給到CameraDeviceClient,而meta data以及image data 會給到FrameProcessBase,進而給到CameraDeviceClient,所以FrameProcessBase主要用于metadata以及image data的中轉(zhuǎn)處理。而Camera3Device中RequestThread主要用于處理Request的接收與下發(fā)工作。
對于Camera Service而言,主要包括了兩個階段,一個是系統(tǒng)剛啟動的時候,會通過運行其主程序?qū)⑵銫amera Service 服務(wù)運行起來,等待Camera Framework的下發(fā)圖像需求,另一個階段就是當用戶打開相機應用的時候,會去獲取相機設(shè)備,進而開始圖像采集過程,接下來我們就主要以這兩個階段分別來詳細介紹下內(nèi)部運行邏輯。
2. 啟動初始化
當系統(tǒng)啟動的時候,會首先運行Camera Service的主程序,將整個進程運行起來,這里我們首先來看下Camera Service 是怎樣運行起來的。

程序Android 轉(zhuǎn)于網(wǎng)絡(luò)圖片
當系統(tǒng)啟動的時候會首先運行main_cameraserver程序,緊接著調(diào)用了CameraService的instantiate方法,該方法最終會調(diào)用到CameraService的onFirstRef方法,在這個方法里面便開始了整個CameraService的初始化工作。
而在onFirstRef方法內(nèi)又調(diào)用了enumerateProviders方法,該方法中主要做了兩個工作:
一個是實例化一個CameraProviderManager對象,該對象管理著有關(guān)Camera Provider的一些資源。
一個是調(diào)用CameraProviderManager的initialize方法對其進行初始化工作。
而在CameraProviderManager初始化的過程中,主要做了三件事:
首先通過getService方法獲取ICameraProvider代理。
隨后實例化了一個ProviderInfo對象,之后調(diào)用其initialize方法進行初始化。
最后將ProviderInfo加入到一個內(nèi)部容器中進行管理。
而在調(diào)用ProviderInfo的initialize方法進行初始化過程中存在如下幾個動作:
首先接收了來自CameraProviderManager獲取的ICameraProvider代理并將其存入內(nèi)部成員變量中。
其次由于ProviderInfo實現(xiàn)了ICameraProviderCallback接口,所以緊接著調(diào)用了ICameraProvider的setCallback將自身注冊到Camera Provider中,接收來自Provider的事件回調(diào)。
再然后,通過調(diào)用ICameraProvider代理的getCameraDeviceInterface_V3_X接口,獲取Provider端的ICameraDevice代理,并且將這個代理作為參數(shù)加入到DeviceInfo3對象實例化方法中,而在實例化DeviceInfo3對象的過程中會通過ICameraDevice代理的getCameraCharacteristics方法獲取該設(shè)備對應的屬性配置,并且保存在內(nèi)部成員變量中。
最后ProviderInfo會將每一個DeviceInfo3存入內(nèi)部的一個容器中進行統(tǒng)一管理,至此整個初始化的工作已經(jīng)完成。
通過以上的系列動作,Camera Service進程便運行起來了,獲取了Camera Provider的代理,同時也將自身關(guān)于Camera Provider的回調(diào)注冊到了Provider中,這就建立了與Provider的通訊,另一邊,通過服務(wù)的形式將AIDL接口也暴露給了Framework,靜靜等待來自Framework的請求。
3. 處理App請求
一旦用戶打開了相機應用,便會去調(diào)用CameraManager的openCamera方法進而走到Framework層處理,F(xiàn)ramework通過內(nèi)部處理,最終將請求下發(fā)到Camera Service中,而在Camera Service主要做了獲取相機設(shè)備屬性、打開相機設(shè)備,然后App通過返回的相機設(shè)備,再次下發(fā)創(chuàng)建Session以及下發(fā)Request的操作,接下來我們來簡單梳理下這一系列請求在Camera Service中是怎么進行處理的。
a) 獲取屬性
對于獲取相機設(shè)備屬性動作,邏輯比較簡單,由于在Camera Service啟動初始化的時候已經(jīng)獲取了相應相機設(shè)備的屬性配置,并存儲在DeviceInfo3中,所以該方法就是從對應的DeviceInfo3中取出屬性返回即可。
b) 打開相機設(shè)備
對于打開相機設(shè)備動作,主要由connectDevice來實現(xiàn),內(nèi)部實現(xiàn)比較復雜,接下來我們詳細梳理下。
當CameraFramework通過調(diào)用ICameraService的connectDevice接口的時候,主要做了兩件事情:
一個是創(chuàng)建CameraDeviceClient。
一個是對CameraDeviceClient進行初始化,并將其給Framework。
而其中創(chuàng)建CameraDevcieClient的工作是通過makeClient方法來實現(xiàn)的,在該方法中首先實例化一個CameraDeviceClient,并且將來自Framework針對ICameraDeviceCallbacks的實現(xiàn)類CameraDeviceImpl.CameraDeviceCallbacks存入CameraDeviceClient中,這樣一旦有結(jié)果產(chǎn)生便可以將結(jié)果通過這個回調(diào)回傳給Framework,其次還實例化了一個Camera3Device對象。
其中的CameraDeviceClient的初始化工作是通過調(diào)用其initialize方法來完成的,在該方法中:
首先調(diào)用父類Camera2ClientBase的initialize方法進行初始化。
其次實例化FrameProcessorBase對象并且將內(nèi)部的Camera3Device對象傳入其中,這樣就建立了FrameProcessorBase和Camera3Device的聯(lián)系,之后將內(nèi)部線程運行起來,等待來自Camera3Device的結(jié)果。
最后將CameraDeviceClient注冊到FrameProcessorBase內(nèi)部,這樣就建立了與CameraDeviceClient的聯(lián)系。
而在Camera2ClientBase的intialize方法中會調(diào)用Camera3Device的intialize方法對其進行初始化工作,并且通過調(diào)用Camera3Device的setNotifyCallback方法將自身注冊到Camera3Device內(nèi)部,這樣一旦Camera3Device有結(jié)果產(chǎn)生就可以發(fā)送到CameraDeviceClient中。
而在Camera3Device的初始化過程中,首先通過調(diào)用CameraProviderManager的openSession方法打開并獲取一個Provider中的ICameraDeviceSession代理,其次實例化一個HalInterface對象,將之前獲取的ICameraDeviceSession代理存入其中,最后將RequestThread線程運行起來,等待Request的下發(fā)。
而對于CameraProviderManager的openSession方法,它會通過內(nèi)部的DeviceInfo保存的ICameraDevice代理,調(diào)用其open方法從Camera Provider中打開并獲取一個ICameraDeviceSession遠程代理,并且由于Camera3Device實現(xiàn)了Provider中ICameraDeviceCallback方法,會通過該open方法傳入到Provider中,接收來自Provider的結(jié)果回傳。
至此,整個connectDevice方法已經(jīng)運行完畢,此時App已經(jīng)獲取了一個Camera設(shè)備,緊接著,由于需要采集圖像,所以需要再次調(diào)用CameraDevice的createCaptureSession操作,到達Framework,再通過ICameraDeviceUser代理進行了一系列操作,分別包含了cancelRequest/beginConfigure/deleteStream/createStream以及endConfigure方法來進行數(shù)據(jù)流的配置。
c) 配置數(shù)據(jù)流
其中cancelRequest邏輯比較簡單,對應的方法是CameraDeviceClient的cancelRequest方法,在該方法中會去通知Camera3Device將RequestThread中的Request隊列清空,停止Request的繼續(xù)下發(fā)。
beginConfigure方法是空實現(xiàn),這里不進行闡述。
deleteStream/createStream 分別是用于刪除之前的數(shù)據(jù)流以及為新的操作創(chuàng)建數(shù)據(jù)流。
緊接著調(diào)用位于整個調(diào)用流程的末尾–endConfigure方法,該方法對應著CameraDeviceClient的endConfigure方法,其邏輯比較簡單,在該方法中會調(diào)用Camera3Device的configureStreams的方法,而該方法又會去通過ICameraDeviceSession的configureStreams_3_4的方法最終將需求傳遞給Provider。
到這里整個數(shù)據(jù)流已經(jīng)配置完成,并且App也獲取了Framework中的CameraCaptureSession對象,之后便可進行圖像需求的下發(fā)了,在下發(fā)之前需要先創(chuàng)建一個Request,而App通過調(diào)用CameraDeviceImpl中的createCaptureRequest來實現(xiàn),該方法在Framework中實現(xiàn),內(nèi)部會再去調(diào)用Camera Service中的AIDL接口createDefaultRequest,該接口的實現(xiàn)是CameraDeviceClient,在其內(nèi)部又會去調(diào)用Camera3Device的createDefaultRequest方法,最后通過ICameraDeviceSession代理的constructDefaultRequestSettings方法將需求下發(fā)到Provider端去創(chuàng)建一個默認的Request配置,一旦操作完成,Provider會將配置上傳至Service,進而給到App中。
d) 處理圖像需求
在創(chuàng)建Request成功之后,便可下發(fā)圖像采集需求了,這里大致分為兩個流程,一個是預覽,一個拍照,兩者差異主要體現(xiàn)在Camera Service中針對Request獲取優(yōu)先級上,一般拍照的Request優(yōu)先級高于預覽,具體表現(xiàn)是當預覽Request在不斷下發(fā)的時候,來了一次拍照需求,在Camera3Device 的RequestThread線程中,會優(yōu)先下發(fā)此次拍照的Request。這里我們主要梳理下下發(fā)拍照request的大體流程:
下發(fā)拍照Request到Camera Service,其操作主要是由CameraDevcieClient的submitRequestList方法來實現(xiàn),在該方法中,會調(diào)用Camera3Device的setStreamingRequestList方法,將需求發(fā)送到Camera3Device中,而Camera3Device將需求又加入到RequestThread中的RequestQueue中,并喚醒RequestThread線程,在該線程被喚醒后,會從RequestQueue中取出Request,通過之前獲取的ICameraDeviceSession代理的processCaptureRequest_3_4方法將需求發(fā)送至Provider中,由于谷歌對于processCaptureRequest_3_4的限制,使其必須是非阻塞實現(xiàn),所以一旦發(fā)送成功,便立即返回,在App端便等待這結(jié)果的回傳。
e) 接收圖像結(jié)果
針對結(jié)果的獲取是通過異步實現(xiàn),主要分別兩個部分,一個是事件的回傳,一個是數(shù)據(jù)的回傳,而數(shù)據(jù)中又根據(jù)流程的差異主要分為Meta Data和Image Data兩個部分,接下來我們詳細介紹下:
在下發(fā)Request之后,首先從Provider端傳來的是Shutter Notify,因為之前已經(jīng)將Camera3Device作為ICameraDeviceCallback的實現(xiàn)傳入Provider中,所以此時會調(diào)用Camera3Device的notify方法將事件傳入Camera Service中,緊接著通過層層調(diào)用,將事件通過CameraDeviceClient的notifyShutter方法發(fā)送到CameraDeviceClient中,之后又通過打開相機設(shè)備時傳入的Framework的CameraDeviceCallbacks接口的onCaptureStarted方法將事件最終傳入Framework,進而給到App端。
在Shutter事件上報完成之后,當一旦有Meta Data生成,Camera Provider便會通過ICameraDeviceCallback的processCaptureResult_3_4方法將數(shù)據(jù)給到Camera Service,而該接口的實現(xiàn)對應的是Camera3Device的processCaptureResult_3_4方法,在該方法會通過層層調(diào)用,調(diào)用sendCaptureResult方法將Result放入一個mResultQueue中,并且通知FrameProcessorBase的線程去取出Result,并且將其發(fā)送至CameraDeviceClient中,之后通過內(nèi)部的CameraDeviceCallbacks遠程代理的onResultReceived方法將結(jié)果上傳至Framework層,進而給到App中進行處理。
隨后Image Data前期也會按照類似的流程走到Camera3Device中,但是會通過調(diào)用returnOutputBuffers方法將數(shù)據(jù)給到Camera3OutputStream中,而該Stream中會通過BufferQueue這一生產(chǎn)者消費者模式中的生產(chǎn)者的queue方法通知消費者對該buffer進行消費,而消費者正是App端的諸如ImageReader等擁有Surface的類,最后App便可以將圖像數(shù)據(jù)取出進行后期處理了。
初代Android相機框架中,Camera Service層就已經(jīng)存在了,主要用于向上與Camera Framework保持低耦合關(guān)聯(lián),承接其圖像請求,內(nèi)部封裝了Camera Hal Module模塊,通過HAL接口對其進行控制,所以該層從一開始就是谷歌按照分層思想,將硬件抽象層抽離出來放入Service中進行管理,這樣的好處顯而易見,將平臺廠商實現(xiàn)的硬件抽象層與系統(tǒng)層解耦,獨立進行控制。之后隨著谷歌將平臺廠商的實現(xiàn)放入vendor分區(qū)中,徹底將系統(tǒng)與平臺廠商在系統(tǒng)分區(qū)上保持了隔離,此時,谷歌便順勢將Camera HAL Moudle從Camera Service中解耦出來放到了vendor分區(qū)下的獨立進程Camera Provider中,所以之后,Camera Service 的職責便是承接來自Camera Framework的請求,之后將請求轉(zhuǎn)發(fā)至Camera Provider中,作為一個中轉(zhuǎn)站的角色存在在系統(tǒng)中。
原文鏈接:https://blog.csdn.net/u012596975/article/details/107137156
友情推薦:
至此,本篇已結(jié)束。轉(zhuǎn)載網(wǎng)絡(luò)的文章,小編覺得很優(yōu)秀,歡迎點擊閱讀原文,支持原創(chuàng)作者,如有侵權(quán),懇請聯(lián)系小編刪除,歡迎您的建議與指正。同時期待您的關(guān)注,感謝您的閱讀,謝謝!
點個在看,方便您使用時快速查找!
