以本文记录下学习sdm660 camera模块的经验总结。
整体思路:
1 android camera系统架构图
2 opencamera
(1)Bn Bp对象的理解
说明了camera工作时对象之间的关系.
(2)回调函数的注册与监听
为以后camera事件的回调打下基础.
(3)aidl—ICameraService,hidl--ICameraDevice
aidl是app层和framework层进程间通信的接口(CameraClient进程和CameraService进程),hidl是framework层和hal层进程间通信的接口.
3 takepicture(zsl)
4 参考资料
opencamera是preview、takepicture、record的基础,opencamera过程会初始化很多对象,而preview、takepicture、record等操作是围绕着这些对象进行操作的,所以这里用opencamera来理清各个对象间的交互关系,用takepicture作为对象间交互关系的一个实例来讨论。
1 android camera系统架构图
android camera系统架构图
我将Camera模块的系统架构分为四层,从上到下分别是package文件夹下的java层,framework文件夹下的framework层,hardware文件夹下的hal层和kernel文件夹下的driver层。其中framework层下又细分为java framework,jni framework和hardwareinterface framework层;hal层下又细分为hardwareinterface层和mmcamera层。
aidl是发生在jni framework层与hardwareinterface framework层进程间通信的接口,即CameraClient进程与CameraService进程的交互;hidl是发生在frame层和hal层进程间通信的接口。
aidl与hidl的对比:
下面,我会按照java,framework,hal这三层来讲解下opencamera的流程,一直到hal层的mmcamera层。
2 opencamera
2.1 Java layer
我们从java层看下camera模块是如何发送请求,并接收回调的:
Java层是通过AndroidCameraManagerImpl这个类来进行消息发送和数据回调的,其中的CameraHandler子类负责根据不同的消息类型调用不同的framework层接口,我们可以看到不同类型的消息是用宏定义区分的,需要注意的是拍照的请求单独在一个公有接口里。
回调则是通过不同的回调子类处理,previewCallback处理preview回调数据流,ShutterCallback和PictureCallback处理拍照回调,shuttercallback与拍照完成瞬间的声音及动画有关,picturecallback是用来保存jpeg图片的。需要注意的是这里回调的具体实现是在各个Module模块里,比如ShutterCallback的onshutter方法和PictureCallback的onPictureTaken方法具体是在PhotoModule.java里实现的!在之后的回调分析中可以看到每一层都有相应的回调函数,会向上传递事件和数据,而最终处理事件和数据的地方是在Module模块里。
接下来我们顺着OPEN_CAMERA继续向下看:
2.2 Framework layer
2.2.1 Java framework layer
如之前所说,framework层里分为三层,这里先看java framework层:
java framework层主要看的是camera类,sdm660里使用的是camera1接口,所以这里调用的是openLegacy接口,这里要注意的是在创建Camera对象时创建了EventHandler对象,EventHandler对象会在一个线程里轮询事件消息,当有回调上来时,会根据不同的消息类型调用不同的回调函数。
接下来我们顺着native_setup这条线继续往下看,android_hardware_Camera_native_setup就到了Jni framework层!
2.2.2 Jni framework layer
上图说明了opencamera在jni framework层做的事情,分别是
1 请求连接
2 设置监听
3 接收回调
4 转移回调
5 传回上层
native_setup里主要做了两件事:
1 请求连接,这里是调用connectLegacy接口
2 设置监听函数
这里需要注意下设置监听的作用,从hardwareinterface framework层接收到数据或消息回调后,会调用到BnCameraClient相应的回调接口,但并不是由BnCameraClient直接对上层进行数据或消息的回调,而是先进行回调转移到JNICameraContext对象,之后再通过JNICameraContext对象传回上层。这与java层与native层的交互总是要经过Jni层是一个道理。
接下来就是整个framework层的核心了,我们看到这里有个BnCameraClient对象,这个对象到底是什么呢,我们来看下面这张图:
图中6个蓝色对象贯穿了Camera Client进程与Camera Service进程的整个交互过程,我们一行行来看:
1 请求连接,即刚才看到的connectLegacy操作,该操作是通过实现ICameraService的接口而完成的
2 请求预览,拍照和录像等操作,这些操作是通过实现ICamera的接口而完成的
3 通知消息,回调等,这些操作是通过实现ICameraClient接口而完成的
刚开始看到这6个对象时我是晕头转向的,首先是不知道Bn Bp的含义,再者就是我在看代码时只看到了CameraClient进程中的camera对象和CameraService进程中的cameraclient对象,哪里来的这么多对象?为此,我们画一个简化的IInterface类图来慢慢说明!
这张IInerface类图的信息量比较大,主要包含以下几点:
1 看下接口负责的功能:
ICameaClient接口负责定义消息和数据回调等接口;
Icamera接口负责定义请求预览,拍照,录像,自动对焦等接口;
ICameraService接口则负责定义请求连接connectLegacy这个接口;
2 Bp Bn对象的说明:
这里Bn是指Binder native对象,即Binder本地对象;Bp是指Binder proxy对象,即Binder代理对象;Binder本地对象是指实际处理事件的对象,而Binder代理对象的作用是通过Binder机制通知本地对象去处理相应的事件。这里我们以BpCamera和BnCamera为例来说明下:CameraClient进程的BpCamera对象发送startPreview请求后,会通过remote Binder IPC的方式找到CameraService进程的BnCamera对象,进而调用BnCamera的startPreview方法。
3 看下由ICameraClient、ICameraService和ICamera接口派生出来的对象:
首先是ICameraClient接口的派生对象是CameraClient进程的camera对象,但仔细观察camera对象可以看到:camera对象不仅有ICameaClient的回调方法,还有ICamera的预览拍照等方法和ICameraService的connectLegacy方法。这里有疑问的,因为只继承了ICameraClient接口,派生类应该只有回调方法,其他方法哪里来的?原来,这里注意下camera对象的基类,是个模板类,分别有两个成员,一个返回ICameraService对象,另一个是TCamUser成员,而TCamUser实际上是Icamera的类型别名。这时所有疑问就都打开了:原来CameraClient进程中的camera对象就是BnCameraClient对象,而BpCamera对象和BpCameraService对象则是BnCameraClient对象的两个成员!
同理:
CameraService进程中的cameraclient对象就是BnCamera对象,而BpCameraClient对象则是BnCamera对象的一个成员。
CameraService进程中的cameraservice对象就是BnCameraService对象。
总结:
根据如上所说的,其实就是3个对象在相互作用:分别是CameraClient进程中的camera对象、CameraService进程的cameraclient对象和cameraservice对象。
CameraService进程的cameraservice对象是在手机开机过程中创建的,那么现在还剩最后一个问题,CameraClient进程中的camera对象和CameraService进程的cameraclient对象是何时创建的?
其实就是在opencamera中的这个openLegacy!我们来看下openLegacy流程图:
由上图可以看出,CameraClient进程的Camera类的connectLegacy函数会通过aidl调用到CameraService进程的CameraService类的connectLegacy函数。Camera类的connectLegacy的最后一个参数为输出参数,对应BnCameraClient,就是camera对象;CameraService类的connectLegacy的最后一个参数为输出参数,对应BnCamera,就是cameraclient对象。
继续往下讲,CameraService类的的connectLegacy会调用到CameraClient::initialize,到了下一层hardwareinterface framework layer.
2.2.3 Hardwareinterface framework layer
这是Framework层的最后一层hardwareinterface层,hardwareinterface层主要工作有2个:
1 openSession,然后通过hidl实现与Hal层的交互(Hal层进程叫?)
2 设置回调函数
2.3 Hal layer
Hal层也有对应的hardwareinterface层,QCamera2HardwareInterface::openCamera():
首先创建了hardwareinterface类的实例,然后调用到mm_camera_open接口并register_event_notify注册了事件通知器,其中mm_camera_open主要完成一下操作:
打开设备节点,创建socket,起相关线程。
3 takepicture(zsl)
3.1 发送请求流程
Java层,Framework层和Hal层依次下发takepicture请求,主要的流程同之前的分析所描述;
这里主要说下HAL层,从流程图中可以看出两点:
1 zsl takepictre的流程主要分两步:
pre_take_picture
takpicture
2 以消息队列的方式处理消息事件
3.2 接收回调流程
Takepicture涉及到的回调函数主要有两个,分别是shutterCallback、jpepCallback:
从图中我们可以看到:
Hardwareinterface hal layer对应的叫playShuter和processJpegNotify
而之后HAL层向上每个layer会有对应的notifycallback和datacallback。
4 参考资料
1 https://blog.csdn.net/armwind
2 linux_camera_software_design_document.pdf
3 camera_frontend_code_walkthrough_for_msm8974_msm8x26_linux_camera_software.pdf