前面已经分析过,Client端发起远程调用,而实际完成处理任务的,是Server端的 CameraClient 实例。远程client 和 server是两个不同的进程,它们使用binder作为通信工具,完成进程间的通信。

注:CameraClient定义如下:

 class CameraClient : public CameraService::Client
{
//...
};

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 文件中:

 static JNINativeMethod camMethods[] = {
{ "getNumberOfCameras",
"()I",
(void *)android_hardware_Camera_getNumberOfCameras },
{ "_getCameraInfo",
"(ILandroid/hardware/Camera$CameraInfo;)V",
(void*)android_hardware_Camera_getCameraInfo },
{ "native_setup",
"(Ljava/lang/Object;IILjava/lang/String;)I",
(void*)android_hardware_Camera_native_setup },
{ "native_release",
"()V",
(void*)android_hardware_Camera_release },
{ "setPreviewSurface",
"(Landroid/view/Surface;)V",
(void *)android_hardware_Camera_setPreviewSurface },
{ "setPreviewTexture",
"(Landroid/graphics/SurfaceTexture;)V",
(void *)android_hardware_Camera_setPreviewTexture },
{ "setPreviewCallbackSurface",
"(Landroid/view/Surface;)V",
(void *)android_hardware_Camera_setPreviewCallbackSurface },
{ "startPreview",
"()V",
(void *)android_hardware_Camera_startPreview },
{ "_stopPreview",
"()V",
(void *)android_hardware_Camera_stopPreview },
{ "previewEnabled",
"()Z",
(void *)android_hardware_Camera_previewEnabled },
{ "setHasPreviewCallback",
"(ZZ)V",
(void *)android_hardware_Camera_setHasPreviewCallback },
{ "_addCallbackBuffer",
"([BI)V",
(void *)android_hardware_Camera_addCallbackBuffer },
{ "native_autoFocus",
"()V",
(void *)android_hardware_Camera_autoFocus },
{ "native_cancelAutoFocus",
"()V",
(void *)android_hardware_Camera_cancelAutoFocus },
{ "native_takePicture",
"(I)V",
(void *)android_hardware_Camera_takePicture },
{ "native_setParameters",
"(Ljava/lang/String;)V",
(void *)android_hardware_Camera_setParameters },
{ "native_getParameters",
"()Ljava/lang/String;",
(void *)android_hardware_Camera_getParameters },
{ "reconnect",
"()V",
(void*)android_hardware_Camera_reconnect },
{ "lock",
"()V",
(void*)android_hardware_Camera_lock },
{ "unlock",
"()V",
(void*)android_hardware_Camera_unlock },
{ "startSmoothZoom",
"(I)V",
(void *)android_hardware_Camera_startSmoothZoom },
{ "stopSmoothZoom",
"()V",
(void *)android_hardware_Camera_stopSmoothZoom },
{ "setDisplayOrientation",
"(I)V",
(void *)android_hardware_Camera_setDisplayOrientation },
{ "_enableShutterSound",
"(Z)Z",
(void *)android_hardware_Camera_enableShutterSound },
{ "_startFaceDetection",
"(I)V",
(void *)android_hardware_Camera_startFaceDetection },
{ "_stopFaceDetection",
"()V",
(void *)android_hardware_Camera_stopFaceDetection},
{ "enableFocusMoveCallback",
"(I)V",
(void *)android_hardware_Camera_enableFocusMoveCallback},
};

其中,双引号里的名字,对应着 framework-java 层Camera.java 文件中相关的API;以 "android_hardware_Camera_"为前缀的名字,代表着 framework-c++ 中的实现。至于其中返回值和参数类型的表示,此处略去。
可以看出,一个java API 就对应着一个 C++ API实现。
camMethods[] 这个表会被注册到 const RegJNIRec gRegJNI[] 这个表中,而这个表将会被系统进行native注册,大致如下:

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

 int register_android_hardware_Camera(JNIEnv *env)
{
//...
// Register native functions
return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
camMethods, NELEM(camMethods));
};

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

 extern int register_android_hardware_Camera(JNIEnv *env);

 static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_hardware_Camera),
}; /*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
//...
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < ) {
env->PopLocalFrame(NULL);
return -;
}
//...
} void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
//...
/*
* Register android functions.
*/
if (startReg(env) < ) {
ALOGE("Unable to register all android natives\n");
return;
}
//...
}

此处注册流程,大致这样,不再赘述jvm native注册细节。

2. JNI method 表中c++接口的实现

android_hardware_Camera.cpp 文件中,这些c++ 接口只是一层空壳,可以简单的看成是一些环境变量、字符串类型的转换而已。
(此处截取部分接口的封装实现进行展示)

 static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz)
{
//调用了 Camera.cpp 文件中的接口。
return Camera::getNumberOfCameras();
} // connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
sp<Camera> camera;
//调用了 Camera.cpp 文件中的接口
camera = Camera::connect(cameraId, clientName,Camera::USE_CALLING_UID);
} static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
ALOGV("startPreview");
sp<Camera> camera = get_native_camera(env, thiz, NULL); //获取一个Camera 实例
if (camera == ) return; //调用了 Camera.cpp 文件中 Camera::startPreview()
if (camera->startPreview() != NO_ERROR) {
jniThrowRuntimeException(env, "startPreview failed");
return;
}
}
....

而真正的封装,在 Camera.cpp 文件中实现。

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

 sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,int clientUid);
status_t Camera::reconnect();
status_t Camera::lock();
status_t Camera::unlock();
// pass the buffered IGraphicBufferProducer to the camera service
status_t Camera::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer);
// start preview mode
status_t Camera::startPreview();
status_t Camera::storeMetaDataInBuffers(bool enabled);
// start recording mode, must call setPreviewTarget first
status_t Camera::startRecording();
// stop preview mode
void Camera::stopPreview();
// stop recording mode
void Camera::stopRecording();
// release a recording frame
void Camera::releaseRecordingFrame(const sp<IMemory>& mem);
// get preview state
bool Camera::previewEnabled();
// get recording state
bool Camera::recordingEnabled();
status_t Camera::autoFocus();
status_t Camera::cancelAutoFocus();
// take a picture
status_t Camera::takePicture(int msgType);
// set preview/capture parameters - key/value pairs
status_t Camera::setParameters(const String8& params);
// send command to camera driver
status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
.....

上面的这些接口,会被android_hardware_Camera.cpp 文件中的对应名字的接口进行调用,以完成jni的封装。

三、server 端 CameraClient 的实例接口
在前一篇笔记里已经分析过, Camera Client远端的操作,其实质是通过binder,然后调用到了Camera server端对应的接口。而具体就落实到了 CameraService::Client 内部类的 继承类 CameraClient 的实例上去了。
CameraClient.cpp文件中,server端为远程client端实现了对应的接口:

 status_t CameraClient::lock();
status_t CameraClient::unlock(); // connect a new client to the camera
status_t CameraClient::connect();
void CameraClient::disconnect() ; status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,const sp<ANativeWindow>& window);
// set the buffer consumer that the preview will use
status_t CameraClient::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer); // start preview mode
status_t CameraClient::startPreview() ;
// start recording mode
status_t CameraClient::startRecording();
// start preview or recording
status_t CameraClient::startCameraMode(camera_mode mode);
status_t CameraClient::startPreviewMode();
status_t CameraClient::startRecordingMode() ;
// stop preview mode
void CameraClient::stopPreview();
// stop recording mode
void CameraClient::stopRecording(); bool CameraClient::previewEnabled(); status_t CameraClient::initialize(camera_module_t *module); .....

以上仅贴出部分常见的接口。
在上面贴出来的接口中,CameraClient::initialize() 是最重要的。在 CameraService::connect() 对 CameraClient::connect() 完成调用后,会立即对CameraClient::initialize() 进行调用,去操作HAL层,已完成一个Camera实例的最终创建。
(CameraClient::initialize()被调用流程,在上篇笔记已经分析过,此处不赘述)

CameraClient::initialize()被调用后,将会去调用 HAL 层的 open 函数。换句话说,它会打开HAL模块。

 status_t CameraClient::initialize(camera_module_t *module)
{
//...
mHardware = new CameraHardwareInterface(camera_device_name);
res = mHardware->initialize(&module->common);
//....
}

mHardware->initialize() 的实现在 CameraHardwareInterface.h 文件中:

 class CameraHardwareInterface : public virtual RefBase {
public:
status_t initialize(hw_module_t *module)
{ camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module); int rc = OK;
if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 && info.device_version > CAMERA_DEVICE_API_VERSION_1_0)
//....
} else {
rc = CameraService::filterOpenErrorCode(module->methods->open(
module, mName.string(), (hw_device_t **)&mDevice));
}
//...
}
};

这其中的 module->methods->open(module, mName.string(), (hw_device_t **)&mDevice) ; 就是HAL模块的入口处了。
那么,camera_module_t *module 这个参数是怎么传进来的呢?或者说,Camera HAL模块式怎么加载到内存的呢?
对代码稍作回朔,可以知道,在 CameraService::onFirstRef() 这个接口里面,有加载Camera HAL的操作,在 CameraService.cpp 文件中:

 void CameraService::onFirstRef()
{
//..
BnCameraService::onFirstRef();
//..
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,(const hw_module_t **)&mModule) < ) {
}else {
//...
}
}

大名鼎鼎的 hw_get_module() 接口在这里现身了。那么,CameraService::onFirstRef()又是在什么时候被调用的呢?
简而言之,在远端client发起连接的时候,在文件 CameraBase.cpp 中:

 template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid)
{
sp<TCam> c = new TCam(cameraId); //通过SM获取CameraService在本地的一个引用。调用connect函数后最终调用CameraService侧的connect()函数
const sp<ICameraService>& cs = getCameraService();
//...
}

这里, const sp<ICameraService>& cs = getCameraService(); 这行代码其实可以被分解成两行代码:

 ICameraService *A =  getCameraService(); //不考虑c++ 实际语法
const sp<ICameraService>& cs = A; //不考虑c++ 实际语法

在第二行代码执行的时候,在构造强指针的过程中,最终会调用到 CameraService::onFirstRef() 这个玩意. 其具体调用处,在 RefBase.cpp 文件中:

 void RefBase::incStrong(const void* id) const
{
//...
refs->mBase->onFirstRef();
}

其具体调用流程略掉了。(这里涉及到Android 中sp wp 所谓的强指针弱指针构造的过程)

啰嗦了一长段,回头看看 CameraClient::initialize() 会为其他接口提供什么样的帮助:

 status_t CameraClient::initialize(camera_module_t *module)
{
//...
mHardware = new CameraHardwareInterface(camera_device_name);
//....
}

mHardware 是 CameraClient 的一个成员,在CameraClient.h文件中:

 class CameraClient : public CameraService::Client
{
private:
// these are initialized in the constructor.
sp<CameraHardwareInterface> mHardware;
};

根据定义可以看见, mHardware 就是一个 CameraHardwareInterface 的 sp 对象----也就是HAL层的东西了。
而CameraClient中的大部分成员函数,都会借助 mHardware 成员,操作HAL层。(什么叫操作?!总是很邪恶的感觉到,它们是在推卸责任,把责任一层层的推卸,最后就到了HAL,HAL又会推到最终的driver上)

贴停止预览和照相的代码做为一个展示:

 // take a picture - image is returned in callback
status_t CameraClient::takePicture(int msgType) {
//...
return mHardware->takePicture(); //告诉HAL层,进行拍照操作
} // stop preview mode
void CameraClient::stopPreview() {
//...
mHardware->stopPreview(); //告诉HAL层,停止预览
}

四、HAL 接口
在 CameraClient::initialize()中,会产生一个 HAL 的 sp 对象:

 mHardware = new CameraHardwareInterface(camera_device_name);

这里, CameraHardwareInterface 类,就对HAL层做了一个接口抽象,其定义在 CameraHardwareInterface.h 文件中。

 class CameraHardwareInterface : public virtual RefBase {
public:
CameraHardwareInterface(const char *name)
{
mDevice = ;
mName = name;
} status_t initialize(hw_module_t *module)
{
rc = CameraService::filterOpenErrorCode(module->methods->open(
module, mName.string(), (hw_device_t **)&mDevice));
} /**
* Start preview mode.
*/
status_t startPreview()
{
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (mDevice->ops->start_preview)
return mDevice->ops->start_preview(mDevice);
return INVALID_OPERATION;
} /**
* Stop a previously started preview.
*/
void stopPreview()
{
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (mDevice->ops->stop_preview)
mDevice->ops->stop_preview(mDevice);
} //.....省略 private:
camera_device_t *mDevice;
String8 mName;
//... 省略
};

显而易见,这里是对 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

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

  1. sc7731 Android 5.1 Camera 学习之一Camera 两个对象

    众所周知,在Android中Camera采用了C/S架构,其中Camera server 与 Camera client之间通过Android Binder IPC机制进行通信.在Camera实现的框 ...

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

    一.序列化类实现Serializable接口 Serializable接口没有方法,更像是个标记.有了这个标记的Class就能被序列化机制处理. ObjectOutputStream只能对Serial ...

  3. Android开源项目SlidingMenu学习(二)

    前一篇SlidingMenu学习(一)文章中了解了导入SlidingMenu到我们项目经常出现的问题,下面我们正式学习. 先看一个效果: 看到两幅图片的差别了吗,左边的一栏时可以滑动的,可以隐藏掉,现 ...

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

    <?php //定义接口 //接口可以定义属性,但必须是常量而且是public //接口的所有方法必须是public interface Iusb{ public function start( ...

  5. Android(java)学习笔记66:实现Runnable接口创建线程 和 使用Callable和Future创建线程

    1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...

  6. Android(java)学习笔记6:实现Runnable接口创建线程 和 使用Callable和Future创建线程

    1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...

  7. sc7731 Android 5.1 LCD驱动简明笔记之二

    此篇笔记基于sc7731 - android 5.1,对lcd的framebuffer做一个简明笔记. 一共分为两大部分:第一部分,关于LCD的硬件方面的:第二部分,关于lcd核心处理(framebu ...

  8. Android Animation学习(二) ApiDemos解析:基本Animators使用

    Android Animation学习(二) ApiDemos解析:基本Animatiors使用 Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.O ...

  9. Android 5.1 Camera 架构学习之Camera初始化

    Android Camera 采用C/S架构,client 与server两个独立的线程之间(CameraService)使用Binder通信. 一 CameraService的注册. 1.手机开机后 ...

随机推荐

  1. 如何脱离SDK,使用DW5.5和phonegap以及JQMobile搭建开发环境

    也许有些人是学C++出身,对于Java几乎不了解.一时心血来潮想学学android开发,于是下载了Eclipse,安装了SDK,有模有样的学习起来.也许是懒惰了,对于java一直总是提不起精神.于是确 ...

  2. [转] Asp.Net 导出 Excel 数据的9种方案

    湛刚 de BLOG 原文地址 Asp.Net 导出 Excel 数据的9种方案 简介 Excel 的强大之处在于它不仅仅只能打开Excel格式的文档,它还能打开CSV格式.Tab格式.website ...

  3. Spring工厂方式创建Bean实例

    创建Bean实例的方式: 1) 通过构造器(有参或无参) 方式: <bean id="" class=""/> 2) 通过静态工厂方法 方式: &l ...

  4. atoi()函数的实现

    atoi()函数的功能:将字符串转换成整型数:atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负号才开始做转换,而再遇到非数字或字符串时('\0')才结束转化,并将结果返回( ...

  5. Bluebird-Core API (三)

    Promise.join Promise.join( Promise<any>|any values..., function handler ) – -> Promise For ...

  6. UNIX环境下用C语言写静态库与动态库

    静态库,动态库用UNIX 的术语来说,或者叫做归档文件(archive 常以.a 结尾)和共享对象(share object 常以lib 开头.so 结尾)更为准确.静态库,动态库可能是WINDOWS ...

  7. NServiceBus教程-持久化配置

    当配置在NServiceBus v5持久性,秩序是非常重要的.最后赢得持久性配置选项.我们看看一些例子. 示例1 在本例中最后一个配置选项将会覆盖前面的所有选项. v5.2 v5.0 编辑 var c ...

  8. 让git忽略ignore所有文件,只对某些文件进行版本控制

    *.c !frob_*.c !custom.c 或者:*!*/ # 这个的意思是不忽略目录.否则目录被忽略了之后,它里面的所有文件都忽略了!*.c!*.cc!*.cpp!*.cxx 也就是先忽略所有文 ...

  9. 转】MyEclipse使用总结——MyEclipse去除网上复制下来的来代码带有的行号

    原博文出自于: http://www.cnblogs.com/xdp-gacl/p/3544208.html 感谢! 一.正则表达式去除代码行号 作为开发人员,我们经常从网上复制一些代码,有些时候复制 ...

  10. 排序之希尔排序(shell sort)

    前言 本篇博客是在伍迷兄的博客基础上进行的,其博客地址点击就可以进去,里面好博客很多,我的排序算法都来自于此:一些数据结构方面的概念我就不多阐述了,伍迷兄的博客中都有详细讲解,而我写这些博客只是记录自 ...