sc7731 Android 5.1 Camera 學習之二 framework 到 HAL接口整理


前面已經分析過,Client端發起遠程調用,而實際完成處理任務的,是Server端的 CameraClient 實例。遠程client 和 server是兩個不同的進程,它們使用binder作為通信工具,完成進程間的通信。

注:CameraClient定義如下:

1 class CameraClient : public CameraService::Client
2 {
3 //...
4 };

App需要對Camera進行各種操作,framework-java 和framework-c++ 都有對應的操作接口。而JNI是framework-java 和framework-c++ 中間的通信橋梁。
在framework-c++ 這邊,或者說在 CameraClient 實例里面,會和 HAL層進行溝通。

本篇筆記將就 framework-java、framework-c++ 、HAL相關接口作一個簡要筆記。App層屬於攝像頭應用功能邏輯部分,尚未研究。

一、JNI 封裝接口
1. JNI method 表注冊
framework-c++ 為 framework-java實現了對應的接口,具體在 android_hardware_Camera.cpp 文件中:

 1 static JNINativeMethod camMethods[] = {
 2   { "getNumberOfCameras",
 3     "()I",
 4     (void *)android_hardware_Camera_getNumberOfCameras },
 5   { "_getCameraInfo",
 6     "(ILandroid/hardware/Camera$CameraInfo;)V",
 7     (void*)android_hardware_Camera_getCameraInfo },
 8   { "native_setup",
 9     "(Ljava/lang/Object;IILjava/lang/String;)I",
10     (void*)android_hardware_Camera_native_setup },
11   { "native_release",
12     "()V",
13     (void*)android_hardware_Camera_release },
14   { "setPreviewSurface",
15     "(Landroid/view/Surface;)V",
16     (void *)android_hardware_Camera_setPreviewSurface },
17   { "setPreviewTexture",
18     "(Landroid/graphics/SurfaceTexture;)V",
19     (void *)android_hardware_Camera_setPreviewTexture },
20   { "setPreviewCallbackSurface",
21     "(Landroid/view/Surface;)V",
22     (void *)android_hardware_Camera_setPreviewCallbackSurface },
23   { "startPreview",
24     "()V",
25     (void *)android_hardware_Camera_startPreview },
26   { "_stopPreview",
27     "()V",
28     (void *)android_hardware_Camera_stopPreview },
29   { "previewEnabled",
30     "()Z",
31     (void *)android_hardware_Camera_previewEnabled },
32   { "setHasPreviewCallback",
33     "(ZZ)V",
34     (void *)android_hardware_Camera_setHasPreviewCallback },
35   { "_addCallbackBuffer",
36     "([BI)V",
37     (void *)android_hardware_Camera_addCallbackBuffer },
38   { "native_autoFocus",
39     "()V",
40     (void *)android_hardware_Camera_autoFocus },
41   { "native_cancelAutoFocus",
42     "()V",
43     (void *)android_hardware_Camera_cancelAutoFocus },
44   { "native_takePicture",
45     "(I)V",
46     (void *)android_hardware_Camera_takePicture },
47   { "native_setParameters",
48     "(Ljava/lang/String;)V",
49     (void *)android_hardware_Camera_setParameters },
50   { "native_getParameters",
51     "()Ljava/lang/String;",
52     (void *)android_hardware_Camera_getParameters },
53   { "reconnect",
54     "()V",
55     (void*)android_hardware_Camera_reconnect },
56   { "lock",
57     "()V",
58     (void*)android_hardware_Camera_lock },
59   { "unlock",
60     "()V",
61     (void*)android_hardware_Camera_unlock },
62   { "startSmoothZoom",
63     "(I)V",
64     (void *)android_hardware_Camera_startSmoothZoom },
65   { "stopSmoothZoom",
66     "()V",
67     (void *)android_hardware_Camera_stopSmoothZoom },
68   { "setDisplayOrientation",
69     "(I)V",
70     (void *)android_hardware_Camera_setDisplayOrientation },
71   { "_enableShutterSound",
72     "(Z)Z",
73     (void *)android_hardware_Camera_enableShutterSound },
74   { "_startFaceDetection",
75     "(I)V",
76     (void *)android_hardware_Camera_startFaceDetection },
77   { "_stopFaceDetection",
78     "()V",
79     (void *)android_hardware_Camera_stopFaceDetection},
80   { "enableFocusMoveCallback",
81     "(I)V",
82     (void *)android_hardware_Camera_enableFocusMoveCallback},
83 };

其中,雙引號里的名字,對應着 framework-java 層Camera.java 文件中相關的API;以 "android_hardware_Camera_"為前綴的名字,代表着 framework-c++ 中的實現。至於其中返回值和參數類型的表示,此處略去。
可以看出,一個java API 就對應着一個 C++ API實現。
camMethods[] 這個表會被注冊到 const RegJNIRec gRegJNI[] 這個表中,而這個表將會被系統進行native注冊,大致如下:

(1).在android_hardware_Camera.cpp文件中:

1 int register_android_hardware_Camera(JNIEnv *env)
2 {
3 //...
4     // Register native functions
5     return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
6                                               camMethods, NELEM(camMethods));
7 };

(2).在AndroidRuntime.cpp 文件中:

 1 extern int register_android_hardware_Camera(JNIEnv *env);
 2 
 3 static const RegJNIRec gRegJNI[] = {
 4     REG_JNI(register_android_hardware_Camera),
 5 };
 6 
 7 /*
 8  * Register android native functions with the VM.
 9  */
10 /*static*/ int AndroidRuntime::startReg(JNIEnv* env)
11 {
12 //...
13     if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
14         env->PopLocalFrame(NULL);
15         return -1;
16     }
17 //...    
18 }
19 
20 
21 void AndroidRuntime::start(const char* className, const Vector<String8>& options)
22 {
23 //...
24     /*
25      * Register android functions.
26      */
27     if (startReg(env) < 0) {
28         ALOGE("Unable to register all android natives\n");
29         return;
30     }
31 //...
32 }

此處注冊流程,大致這樣,不再贅述jvm native注冊細節。

2. JNI method 表中c++接口的實現

android_hardware_Camera.cpp 文件中,這些c++ 接口只是一層空殼,可以簡單的看成是一些環境變量、字符串類型的轉換而已。
(此處截取部分接口的封裝實現進行展示)

 1 static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz)
 2 {
 3     //調用了 Camera.cpp 文件中的接口。
 4     return Camera::getNumberOfCameras(); 
 5 }
 6 
 7 // connect to camera service
 8 static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
 9     jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
10 {
11     sp<Camera> camera;
12     //調用了 Camera.cpp 文件中的接口
13     camera = Camera::connect(cameraId, clientName,Camera::USE_CALLING_UID);
14 }
15 
16 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
17 {
18     ALOGV("startPreview");
19     sp<Camera> camera = get_native_camera(env, thiz, NULL); //獲取一個Camera 實例
20     if (camera == 0) return;
21 
22     //調用了 Camera.cpp 文件中 Camera::startPreview()
23     if (camera->startPreview() != NO_ERROR) {
24         jniThrowRuntimeException(env, "startPreview failed");
25         return;
26     }
27 }
28 ....

而真正的封裝,在 Camera.cpp 文件中實現。

二、遠端 Camera client
Camera.cpp文件中,部分接口如下:

 1 sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,int clientUid);
 2 status_t Camera::reconnect();
 3 status_t Camera::lock();
 4 status_t Camera::unlock();
 5 // pass the buffered IGraphicBufferProducer to the camera service
 6 status_t Camera::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer);
 7 // start preview mode
 8 status_t Camera::startPreview();
 9 status_t Camera::storeMetaDataInBuffers(bool enabled);
10 // start recording mode, must call setPreviewTarget first
11 status_t Camera::startRecording();
12 // stop preview mode
13 void Camera::stopPreview();
14 // stop recording mode
15 void Camera::stopRecording();
16 // release a recording frame
17 void Camera::releaseRecordingFrame(const sp<IMemory>& mem);
18 // get preview state
19 bool Camera::previewEnabled();
20 // get recording state
21 bool Camera::recordingEnabled();
22 status_t Camera::autoFocus();
23 status_t Camera::cancelAutoFocus();
24 // take a picture
25 status_t Camera::takePicture(int msgType);
26 // set preview/capture parameters - key/value pairs
27 status_t Camera::setParameters(const String8& params);
28 // send command to camera driver
29 status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
30 .....


上面的這些接口,會被android_hardware_Camera.cpp 文件中的對應名字的接口進行調用,以完成jni的封裝。

三、server 端 CameraClient 的實例接口
在前一篇筆記里已經分析過, Camera Client遠端的操作,其實質是通過binder,然后調用到了Camera server端對應的接口。而具體就落實到了 CameraService::Client 內部類的 繼承類 CameraClient 的實例上去了。
CameraClient.cpp文件中,server端為遠程client端實現了對應的接口:

 1 status_t CameraClient::lock();
 2 status_t CameraClient::unlock();
 3 
 4 // connect a new client to the camera
 5 status_t CameraClient::connect();
 6 void CameraClient::disconnect() ;
 7 
 8 status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,const sp<ANativeWindow>& window);
 9 // set the buffer consumer that the preview will use
10 status_t CameraClient::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer);
11 
12 // start preview mode
13 status_t CameraClient::startPreview() ;
14 // start recording mode
15 status_t CameraClient::startRecording();
16 // start preview or recording
17 status_t CameraClient::startCameraMode(camera_mode mode);
18 status_t CameraClient::startPreviewMode();
19 status_t CameraClient::startRecordingMode() ;
20 // stop preview mode
21 void CameraClient::stopPreview();
22 // stop recording mode
23 void CameraClient::stopRecording();
24 
25 bool CameraClient::previewEnabled();
26 
27 status_t CameraClient::initialize(camera_module_t *module);
28 
29 .....


以上僅貼出部分常見的接口。
在上面貼出來的接口中,CameraClient::initialize() 是最重要的。在 CameraService::connect() 對 CameraClient::connect() 完成調用后,會立即對CameraClient::initialize() 進行調用,去操作HAL層,已完成一個Camera實例的最終創建。
(CameraClient::initialize()被調用流程,在上篇筆記已經分析過,此處不贅述)

CameraClient::initialize()被調用后,將會去調用 HAL 層的 open 函數。換句話說,它會打開HAL模塊。

1 status_t CameraClient::initialize(camera_module_t *module)
2 {
3     //...
4     mHardware = new CameraHardwareInterface(camera_device_name);
5     res = mHardware->initialize(&module->common);
6     //....
7 }

mHardware->initialize() 的實現在 CameraHardwareInterface.h 文件中:

 1 class CameraHardwareInterface : public virtual RefBase {
 2 public:
 3     status_t initialize(hw_module_t *module)
 4     {
 5         
 6         camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module);
 7 
 8 
 9         int rc = OK;
10         if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 && info.device_version > CAMERA_DEVICE_API_VERSION_1_0)
11            //....
12         } else {
13             rc = CameraService::filterOpenErrorCode(module->methods->open(
14                 module, mName.string(), (hw_device_t **)&mDevice));
15         }
16         //...
17     }
18 };

這其中的 module->methods->open(module, mName.string(), (hw_device_t **)&mDevice) ; 就是HAL模塊的入口處了。
那么,camera_module_t *module 這個參數是怎么傳進來的呢?或者說,Camera HAL模塊式怎么加載到內存的呢?
對代碼稍作回朔,可以知道,在 CameraService::onFirstRef() 這個接口里面,有加載Camera HAL的操作,在 CameraService.cpp 文件中:

 1 void CameraService::onFirstRef()
 2 {
 3     //..
 4     BnCameraService::onFirstRef();
 5     //..
 6     if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,(const hw_module_t **)&mModule) < 0) {
 7     }else {
 8         //...
 9     }
10 }

大名鼎鼎的 hw_get_module() 接口在這里現身了。那么,CameraService::onFirstRef()又是在什么時候被調用的呢?
簡而言之,在遠端client發起連接的時候,在文件 CameraBase.cpp 中:

 1 template <typename TCam, typename TCamTraits>
 2 sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
 3                                                const String16& clientPackageName,
 4                                                int clientUid)
 5 {
 6     sp<TCam> c = new TCam(cameraId);
 7     
 8     //通過SM獲取CameraService在本地的一個引用。調用connect函數后最終調用CameraService側的connect()函數
 9     const sp<ICameraService>& cs = getCameraService();
10   //...
11 }

這里, const sp<ICameraService>& cs = getCameraService(); 這行代碼其實可以被分解成兩行代碼:

1 ICameraService *A =  getCameraService(); //不考慮c++ 實際語法
2 const sp<ICameraService>& cs = A; //不考慮c++ 實際語法

在第二行代碼執行的時候,在構造強指針的過程中,最終會調用到 CameraService::onFirstRef() 這個玩意. 其具體調用處,在 RefBase.cpp 文件中:

1 void RefBase::incStrong(const void* id) const
2 {
3     //...
4     refs->mBase->onFirstRef();                                                                                             
5 }

其具體調用流程略掉了。(這里涉及到Android 中sp wp 所謂的強指針弱指針構造的過程)

啰嗦了一長段,回頭看看 CameraClient::initialize() 會為其他接口提供什么樣的幫助:

1 status_t CameraClient::initialize(camera_module_t *module)
2 {
3     //...
4     mHardware = new CameraHardwareInterface(camera_device_name);
5     //....
6 }

mHardware 是 CameraClient 的一個成員,在CameraClient.h文件中:

1 class CameraClient : public CameraService::Client
2 {
3 private:
4     // these are initialized in the constructor.
5     sp<CameraHardwareInterface>     mHardware;  
6 };

根據定義可以看見, mHardware 就是一個 CameraHardwareInterface 的 sp 對象----也就是HAL層的東西了。
而CameraClient中的大部分成員函數,都會借助 mHardware 成員,操作HAL層。(什么叫操作?!總是很邪惡的感覺到,它們是在推卸責任,把責任一層層的推卸,最后就到了HAL,HAL又會推到最終的driver上)

貼停止預覽和照相的代碼做為一個展示:

 1 // take a picture - image is returned in callback
 2 status_t CameraClient::takePicture(int msgType) {
 3     //...
 4     return mHardware->takePicture();  //告訴HAL層,進行拍照操作
 5 }
 6 
 7 // stop preview mode
 8 void CameraClient::stopPreview() {
 9     //...
10     mHardware->stopPreview(); //告訴HAL層,停止預覽
11 }

四、HAL 接口
在 CameraClient::initialize()中,會產生一個 HAL 的 sp 對象:

1 mHardware = new CameraHardwareInterface(camera_device_name);

這里, CameraHardwareInterface 類,就對HAL層做了一個接口抽象,其定義在 CameraHardwareInterface.h 文件中。

 1 class CameraHardwareInterface : public virtual RefBase {
 2 public:
 3     CameraHardwareInterface(const char *name)
 4     {
 5         mDevice = 0;
 6         mName = name;
 7     }
 8     
 9     status_t initialize(hw_module_t *module)
10     {
11         rc = CameraService::filterOpenErrorCode(module->methods->open(
12                 module, mName.string(), (hw_device_t **)&mDevice));
13     }
14     
15     /**
16      * Start preview mode.
17      */
18     status_t startPreview()
19     {
20         ALOGV("%s(%s)", __FUNCTION__, mName.string());
21         if (mDevice->ops->start_preview)
22             return mDevice->ops->start_preview(mDevice);
23         return INVALID_OPERATION;
24     }
25 
26     /**
27      * Stop a previously started preview.
28      */
29     void stopPreview()
30     {
31         ALOGV("%s(%s)", __FUNCTION__, mName.string());
32         if (mDevice->ops->stop_preview)
33             mDevice->ops->stop_preview(mDevice);
34     }
35 
36    //.....省略
37    
38 private:
39     camera_device_t *mDevice;
40     String8 mName;
41     //... 省略
42 };

顯而易見,這里是對 Camera HAL 的一個抽象封裝,畢竟,各種廠商的Camera HAL 具體模塊,其實現細節可能不同。於是這里就再抽了一層。
其扮演的角色,其實和 android_hardware_Camera.cpp 文件中,jni那部分接口一樣。為了好看(更清晰),包裝了一層而已。
只要CameraService::onFirstRef()中對Camera HAL模塊加載成功,這里就可以開始告訴Camera HAL 做什么。至於怎么做,那將是HAL層的事---話說,這是面向對象的基本原理吧:只能告訴別人做什么,具體怎么做,就管不了了。

 

全文總結:
App ---> framework-java ---> jni ---> framework-c++(Camera) ---> binder ---> framework-c++(CameraService) --> framework-c++(CameraService::Client) ---> framework-c++(CameraClient) --->(CameraHardwareInterface) ---> HAL
由於未對 framework-java 以上的東西進行分析,筆記中直接從 jni 開始的。

 

(over)

2016-1-22

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM