1. 程式人生 > >Android Camera架構分層及程式碼結構(MTK version)

Android Camera架構分層及程式碼結構(MTK version)

Android的Camera包含取景器(viewfinder)和拍攝照片(takepicture)的功能。目前MTKAndroid Camera程式的架構分成客戶端和伺服器兩個部分,它們建立在Android的程序間通訊Binder的結構上。Camera模組同樣遵循Android的框架,如下圖所示。

Camera 架構主要分為以下幾個層次:

1.應用層

Camera的應用層在Android上表現為直接呼叫SDK API開發的一個Camera 應用APK包。程式碼在\packages\apps\Camera下。主要是Java寫的基於android.hardware.Camera類呼叫的封裝,並且實現Camera應用的業務邏輯和UI顯示。android.hardware.Camera就是Android提供給上層呼叫的Camera類。這個類用來連線或斷開一個Camera服務,設定拍攝引數,開始、停止預覽,拍照等。它也是Android Camera應用框架封裝暴露出來的介面。一個Android應用中若要使用這個類,需要在Manifest檔案宣告Camera的許可權,另外還需要新增一些<uses-feature>元素來宣告應用中的Camera特性,如自動對焦等。具體做法可如下:

<uses-permissionandroid:name="android.permission.CAMERA" />
<uses-featureandroid:name="android.hardware.camera" />
<uses-featureandroid:name="android.hardware.camera.autofocus" />


2.應用框架層

Camera框架層將應用與底層的實現隔離開來,實現了一套Android定義的對上對下介面規範,方便應用及底層硬體的開發和移植。這一層對上以Java類的形式包裝出android.hardware.Camera,提供給應用層呼叫;對下在CameraHardwareInterface.h標頭檔案中定義了Camera硬體抽象層的介面,這是一個包含純虛擬函式的類,必須被實現類繼承才能使用。這個實現類也即是下層中將講到的使用者庫層,它繼承CameraHardwareInterface介面,例項化對底層硬體驅動的封裝,最終生成libcamera.so供框架的libcameraservice.so呼叫。這樣做的好處是讓Camera的應用框架程式碼獨立,不受底層硬體驅動改變的影響,方便在不同平臺上porting 驅動程式碼,而保持上層的程式碼不用變化。

從程式碼上看,這一層包含Java到JNI到C++的程式碼。原始碼主要在以下路徑:

\android\frameworks\base\core\java\android\hardware\Camera.java

這個類作為Android SDK Camera部分提供給上層應用,並通過JNI的方式呼叫本地C++程式碼。

\android\frameworks\base\core\jni\android_hardware_Camera.cpp是Camera 的JAVA本地呼叫部分,是承接JAVA程式碼到C++程式碼的橋樑。編譯生成libandroid_runtime.so。

\android\frameworks\base\libs\ui 包含檔案:

Camera.cpp

CameraParameters.cpp

ICamera.cpp

ICameraClient.cpp

ICameraService.cpp

它們的標頭檔案在\android\frameworks\base\include\ui目錄下。這部分的內容編譯生成libui.so。在Camera模組的各個庫中,libui.so位於核心的位置,作為Camera框架的Client客戶端部分,與另外一部分內容服務端libcameraservice.so通過程序間通訊(即Binder機制)的方式進行通訊。\android\frameworks\base\camera\libcameraservice  CameraService是Camera服務,Camera框架的中間層,用於連結CameraHardwareInterface和 Client,它通過呼叫實際的Camera硬體介面來實現功能。這部分內容被編譯成庫libcameraservice.so。

libandroid_runtime.so和libui.so兩個庫是公用的,其中除了Camera還有其他方面的功能。整個Camera在執行的時候,可以大致上分成Client和Server兩個部分,它們分別在兩個程序中執行,它們之間使用Binder機制實現程序間通訊。這樣在client呼叫介面,功能則在server中實現,但是在client中呼叫就好像直接呼叫server中的功能,程序間通訊的部分對上層程式不可見。

當Camera Client端通過Binder機制與CameraServer端通訊,Server端的實現傳遞到Client端。而Server端的實現又是呼叫硬體介面來實現。

3.HAL層

這個層次其實就是使用者空間的驅動程式碼。前面有介紹過框架層對下在CameraHardwareInterface.h標頭檔案中定義了Camera硬體抽象層的介面,它是包含純虛擬函式的類,必須被實現類繼承才能使用。HAL層正好繼承CameraHardwareInterface介面,依據V4l2規範例項化底層硬體驅動,使用ioctl方式呼叫驅動,最終生成libcamera.so供框架的libcameraservice.so呼叫。

這層的程式碼在\android\hardware\XXX\libcamera目錄下(也有可能在vendor目錄中對應的libcamera下)。注意這裡的XXX是不同廠商為不同產品(板子)而建的目錄,以高通msm平臺為例,這裡XXX用msm7k表示,這樣高通msm平臺下這個HAL的目錄即為\android\hardware\msm7k\libcamera。不難看出,如果要在某硬體平臺上執行Android,也就主要在這一層進行修改,因為它是直接和底層硬體驅動相關的。上面也講過,應用框架層對上對下都定義的標準介面,這樣做的目的也就是使上層的程式碼獨立,在porting中不受影響。所以我們現在可以基本確定,如果要改Camera的硬體,框架層以上的部分都可以不動,要改就改HAL到核心層的部分,這也是Android底層開發的主要工作。

4.核心層

這一層主要是基於Linux的裝置驅動。對Camera來說,一般是按V4l2規範將Camera原子功能以ioctl的形式暴露出來供HAL層呼叫的實現。主要功能的實現程式碼在\android\kernel\drivers\media\video\XXX下。跟HAL層目錄一樣,XXX是不同廠商不同平臺的目錄,以高通msm平臺為例,這個目錄就是\android\kernel\drivers\media\video\msm。所以要在Android平臺上新增硬體功能,首先考慮將它的驅動加到Android的Linux核心中。

5.Camera庫檔案

前面已提到Camera模組主要包含libandroid_runtime.so、libcamera_client.s0(libui.so)、libcameraservice.so和一個與Camera硬體相關的硬體庫libcamera.so。其中libandroid_runtime.so、libcamera_client.s0(libui.so)是與android系統構架相關的, 不需要對進行其修改,libameraservice.so和libcamera.so則是和硬體裝置相關聯的,而cameralib.so實際上就是裝置的linxu驅動,所以Camera裝置的系統繼承主要是通過移植CameraLinux驅動和修改libcameraservice.so庫來完成。

Libcameraservice.so構建規則中使用巨集USE_CAMERA_STUB決定 是否使用真的Camera,如果巨集為真,則使用CameraHardwareStub.cpp和FakeCamera.cpp構造一個假的Camera,如果為假則使用libcamera來構造一個實際上的Camera服務。

在CameraHardwareStub.cpp中定義了CameraHardwareStub類,它繼承並實現了抽象類CameraHardwareInterface中定義的真正操作Camera裝置的所有的純虛擬函式。通過openCameraHardware()將返回一個CameraHardwareInterface類的物件,但由於CameraHardwareInterface類是抽象類所以它並不能建立物件,而它的派生類CameraHardwareStub完全實現了其父類的純虛擬函式所以openCameraHardware()返回一個指向派生類物件的基類指標用於底層裝置的操作。由於CameraHardwareStub類定義的函式是去操作一個假的Camera,故通過openCameraHardware返回的指標主要用於模擬環境對Camera的模擬操作,要想通過openCameraHardware返回的指標操作真正的硬體裝置則需完成以下步驟:

⑴CameraHardwareInterface類中的所有純虛擬函式的宣告改為虛擬函式的宣告(即去掉虛擬函式聲明後的“=0”);

⑵編寫一個原始檔去定義CameraHardwareInterface類中宣告的所有虛擬函式;

⑶編寫Android.mk檔案用於生成一個包含步驟⑵編寫的原始檔和其他相關檔案的libcamera.so檔案;

⑷將巨集USE_CAMERA_STUB改成false,這樣生成libcameraservice.so時就會包含libcamera.so庫。(注:如果CameraHardwareInterface類的成員函式並沒有直接操作硬體而是呼叫Camera的linux驅動來間接對硬體操作,那麼包含這樣的CameraHardwareInterface類的libcamera.so庫就相當於一個HAL)。

以上Camera的結構層次可以簡單的概括成如下流程圖: