zoukankan      html  css  js  c++  java
  • 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
    ");
    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

  • 相关阅读:
    使用ueditor实现多图片上传案例——DaoImpl层(BaseDaoUtilImpl)
    使用ueditor实现多图片上传案例——Dao层(IShoppingDao)
    使用ueditor实现多图片上传案例——Dao层(IBaseDaoUtil)
    使用ueditor实现多图片上传案例——Dao层(BaseDao)
    使用ueditor实现多图片上传案例——实体类(Shopping.java)
    使用ueditor实现多图片上传案例
    java实现人脸识别源码【含测试效果图】——前台页面层(login.jsp)
    oracle 使用leading, use_nl, rownum调优(引用)
    oracle 使用leading, use_nl, rownum调优(引用)
    [转载]spring+proxool
  • 原文地址:https://www.cnblogs.com/chineseboy/p/5152485.html
Copyright © 2011-2022 走看看