sc7731 Android 5.1 Camera 学习之二 framework 到 HAL接口整理

前面已经分析过,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

上一篇:JAVA调用C语言写的SO文件


下一篇:[SinGuLaRiTy] Nescafe 24杯模拟赛