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

时间: 2024-10-11 05:15:36

sc7731 Android 5.1 Camera 学习之二 framework 到 HAL接口整理的相关文章

Java序列化与反序列化学习(二):序列化接口说明

一.序列化类实现Serializable接口 Serializable接口没有方法,更像是个标记.有了这个标记的Class就能被序列化机制处理. ObjectOutputStream只能对Serializable接口的类的对象进行序列化.默认情况下,ObjectOutputStream按照默认方式序列化,这种序列化方式仅仅对对象的非transient的实例变量进行序列化,而不会序列化对象的transient的实例变量,也不会序列化静态变量. 当ObjectOutputStream按照默认方式反序

高通camera学习笔记二

高通camera daemon进程 1.概述 高通在Android的camera架构中,依旧沿用了其传统的方式,将其自身的一些处理放在一个daemon进程中.这部分内容出于应用于driver之间,是为了保护自身及硬件厂商的利益而专门弄出来的一个东东.其它各家平台也采用类似的方式将这部分的处理放在HAL层处理. 2.进程的入口    做为一个单独的进程,那肯定是有其main函数入口的.在vendor\qcom\proprietary\mm-camera\mm-camera2\server-imag

Android第一行代码学习笔记二---在活动中使用Toast

Toast:是Android系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,这些信息会在一段时间后自动消失,并且不会占用任何屏幕空间. 首先需要定义一个弹出Toast触发点,接着笔记一的程序,正好上面有个按钮,我们就点击这个按钮的时候弹出来一个Toast,在onCreate()方法中添加如下代码: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceStat

PHP学习笔记二十九【接口】

<?php //定义接口 //接口可以定义属性,但必须是常量而且是public //接口的所有方法必须是public interface Iusb{ public function start(); public function stop(); } //手机类实现接口关键字implements,必须实现这个所有方法 //类可以同时实现多个接口 //一个类可以实现多个接口 implements 接口1,接口2,接口 class Phone implements Iusb{ public func

Android学习Scroller(二)——ViewGroup调用scrollTo()

MainActivity如下: package cc.ac; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.app.Activity; /** * Demo描述: * 对ViewGroup调用sc

Android学习Scroller(二)

MainActivity如下: package cc.testscroller1; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.view.View.OnClick

Android 5.1 Camera 架构学习(一)——Camera初始化

Android Camera 采用C/S架构,client 与server两个独立的线程之间(CameraService)使用Binder通信. 一 CameraService的注册. 1.手机开机后,会走init.rc流程,init.rc会启动MediaServer Service. service media /system/bin/mediaserver class main user root #### # google default #### # user media #### gr

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout.RecyclerView和CardView 前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框.DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框.这一节我们介绍几个新的API控件SwipeRefreshLayout.RecyclerView和CardView,这几个API控件都是google在Android5.0推出的.下面我们来学

Android学习笔记二十二.使用ContentProvider实现数据共享(五).监听ContentProvider的数据改变

一.使用ContentProvider管理多媒体内容 Android提供了Camera程序来支持拍照.拍摄视频,用户拍摄的相片.视频都将存放在固定的位置.Android同样为这些多媒体内容提供了ContentProvider,所以我们可以通过使用ContentProvider实现其他应用直接访问Camera所拍摄的照片.视频等. 1.多媒体ContentProvider的Uri (1)MediaStore.Audio.Media.EXTERNAL_CONTENT_URI:存储在外部存储器(SD卡