博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android_JellyBean 4.2.1 Camera Service 请求过程分析
阅读量:7174 次
发布时间:2019-06-29

本文共 11235 字,大约阅读时间需要 37 分钟。

  hot3.png

Camera子系统采用C/S架构,客户端和服务端在两个不同的进程当中,它们使用android中的binder机制进行通信,本系列文章将从Android Camera应用程序到硬件抽象的实现一步一步对照相机系统进行分析,首先从CameraService初始化过程着手,然后从上层APP打开照相机->进行preview->拍照以及聚焦等功能的实现全面的学习照相机子系统

1 CameraService初始化过程

    frameworks/av/media/mediaserverMain_mediaserver.cpp,

    CameraService在MediaServer中初始化,下面代码是MediaServer的main函数,在该函数中初始化照相机服务

int main(int argc, char** argv){    sp
proc(ProcessState::self());    sp
sm = defaultServiceManager();   .................    CameraService::instantiate();  ............    IPCThreadState::self()->joinThreadPool();}

CameraService中的instantiate方法用来创建CameraService实例,并进行相应的初始化,这个函数定义在它的父类BinderService中:frameworks/native/include/binder/BinderService.h,替换之后见如下代码:

class BinderService{public:    static status_t publish(bool allowIsolated = false) {        sp
sm(defaultServiceManager());     return sm->addService(String16(CameraService::getServiceName()), new CameraService(), allowIsolated); } ................... static void instantiate() { publish(); } ...................};
相机服务的初始化过程首先是创建CameraService实例,然后将其注册到ServiceManager中,关于它的启动是发生在init.rc中,通过media_server来启动CameraService,具体代码如下:

system/rootdir/init.rc

service servicemanager /system/bin/servicemanager    class core    user system    group system    critical    onrestart restart zygote    onrestart restart media    onrestart restart surfaceflinger    onrestart restart drmservice media /system/bin/mediaserver    class main    user media    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc    ioprio rt 4
在cameraService注册以及启动过程中cameraService自身会执行一些初始化的工作,主要涉及到如下工作

frameworks/av/services/camera/libcameraservice/CameraService.cppstatic CameraService *gCameraService;CameraService::CameraService():mSoundRef(0), mModule(0){    ALOGI("CameraService started (pid=%d)", getpid());    gCameraService = this;}void CameraService::onFirstRef(){    BnCameraService::onFirstRef();    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&mModule) < 0) {        ALOGE("Could not load camera HAL module");        mNumberOfCameras = 0;     } else {/*最大支持两个摄像头*/        mNumberOfCameras = mModule->get_number_of_cameras();        if (mNumberOfCameras > MAX_CAMERAS) {            ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",mNumberOfCameras, MAX_CAMERAS);            mNumberOfCameras = MAX_CAMERAS;         }        for (int i = 0; i < mNumberOfCameras; i++) {             setCameraFree(i);        }     }}

在上述初始化代码中,先通过调用HAL硬件抽象层库,获取支持的摄像头个数并保存到mNumberOfCameras

2 应用程序链接相机服务过程

     在camera应用程序启动的时候首先会和CameraService建立连接,camera应用程序代码就不分析了,下面这副图是一个简单的流程图,画得有点丑

图2-1:照相机应用程序启动流程图

    从上面的流程图我们可以看出在请求服务的过程中多出用到了应用框架层的camera类,该类定义在 frameworks/base/core/java/android/hardware/Camera.java文件当中,这一个类正是Camera子系统中APP层和JNI层交换的接口,它对上为应用程序提供了各种操作Camera的方法,向下访问JNI实现它自身的接口Camera类定义如下:
public class Camera {    public static Camera open(int cameraId) {         return new Camera(cameraId);    }    Camera(int cameraId) {        .................        Looper looper;        if ((looper = Looper.myLooper()) != null) {            mEventHandler = new EventHandler(this, looper);        } else if ((looper = Looper.getMainLooper()) != null) {            mEventHandler = new EventHandler(this, looper);        } else {             mEventHandler = null;        }        native_setup(new WeakReference
(this), cameraId); }}
在分析框架源码之前,先让我们了解一下应用程序请求服务以及服务处理示意图:

图2-2:照相机服务请求示意图

接下来按照上面5个步骤来分析具体的源码,其中地一个步骤的源码在上一步中已解释(2)Camera open(int cameraId)方法调用native_setup本地方法,其中native_setup本地方法在JNI层被注册成如下方法:
frameworks/base/core/jni/android_hardware_Camera.cppstatic JNINativeMethod camMethods[] = {{ "native_setup","(Ljava/lang/Object;I)V", (void*)android_hardware_Camera_native_setup },/*通过Camera.cpp连接CameraService*/    …...};

(3)native_setup函数通过JNI调用android_hardware_Camera_native_setup函数,该函数的实现如下://通过android_hardware_Camera_native_setup请求CameraService

static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,jobject weak_this, jint cameraId){    sp
camera = Camera::connect(cameraId); if (camera == NULL) { jniThrowRuntimeException(env, "Fail to connect to camera service"); return; } // make sure camera hardware is alive 还记得前面的初始化? if (camera->getStatus() != NO_ERROR) { jniThrowRuntimeException(env, "Camera initialization failed"); return; } jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { jniThrowRuntimeException(env, "Can't find android/hardware/Camera"); return; } // We use a weak reference so the Camera object can be garbage collected. // The reference is only used as a proxy for callbacks. sp
context = new JNICameraContext(env, weak_this, clazz, camera); context->incStrong(thiz); camera->setListener(context); //将这一步骤返回的BpCameraClient返回到JAVA应用程序框架 // save context in opaque field env->SetIntField(thiz, fields.context, (int)context.get());}

(4)android_hardware_Camera_native_setup通过调用Camera::connect(int cameraId)函数请求连接服务。frameworks/av/camera/camera.cpp

sp
Camera::connect(int cameraId){ ALOGV("connect"); sp
c = new Camera();//BnCameraClient const sp
& cs = getCameraService();//return BpCameraService if (cs != 0) {//Used for processing all kinds of events c->mCamera = cs->connect(c, cameraId);//return } if (c->mCamera != 0) { c->mCamera->asBinder()->linkToDeath(c); c->mStatus = NO_ERROR; } else { c.clear(); } return c;}

(5)Camera::connect(int cameraId)函数首先向ServiceManager获取Camera服务信息,并生成CameraService服务代理BpCameraService,然后通过Binder通信发送CONNECT命令,当BnCameraService收到CONNECT命令后调用CameraService的connect()成员函数来做相应的处理,接下来我们就分析CameraService的connect()成员函数,注意在这一步骤中首先new了一个Camera本地实例,这个Camera类是BnCameraClient的子类,在调用BpCameraService::connect的时候我们将新生成的Camera做为参数传递给了CameraService.我们先来看BpCameraService的connect函数

class BpCameraService: public BpInterface
{public: // connect to camera service virtual sp
connect(const sp
& cameraClient, int cameraId) { Parcel data, reply;      data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeStrongBinder(cameraClient->asBinder());//转换成IBinder类型 data.writeInt32(cameraId); remote()->transact(BnCameraService::CONNECT, data, &reply); return interface_cast
(reply.readStrongBinder());//BpCamera }};
首先将我们传递过来的Camera对象转换成IBinder类型,然后由BnCameraService去响应该连接,最后就是等待服务端返回,如果成功这里为我们生成一个BpCamera实例,怎么来的下面继续分析,接收服务命令的代码段如下:

status_t BnCameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    switch(code) {    case CONNECT: {        CHECK_INTERFACE(ICameraService, data, reply);//        sp
cameraClient =//(a) interface_cast
(data.readStrongBinder()); //return Client 继承BnCamera sp
camera = connect(cameraClient, data.readInt32());//(b) reply->writeStrongBinder(camera->asBinder());//(c) return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); }}
服务端接到CONNECT命令之后开始进行一系列的类型转换,先看代码段(a)还记得之前我们传递过来的是Camera实例,Camera继承了BnCameraClient,所以在(a)中,使用Camera的Binder对象为我们生成了Camera服务代理BpCameraClient实例

    (b)将生成的BpCameraClient对象作为参数打包到CameraService的connect()函数中,至于这个connect函数做了什么,先不管.先看(c)

    (c)将在(b)中返回的实例对象以IBinder的形式返回,现在再回到BpCameraService::connect函数的最后一句return interface_cast<ICamera>(reply.readStrongBinder()),是不是明白了?如果在(c)中成功创建了一个Client实例对象,(Client是BnCamera的子类),那么在BpCameraService::connect函数中是不是会为我们返回一个BpCamera对象?yes!为了验证我们来分析CameraService的connect()成员函数frameworks/av/services/camera/libcameraservice/CameraService.cpp

sp
CameraService::connect( const sp
& cameraClient, int cameraId) { int callingPid = getCallingPid(); LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId); if (!mModule) {/*在服务初始化的时候就已经获得了*/ ALOGE("Camera HAL module not loaded"); return NULL; } sp
client; if (cameraId < 0 || cameraId >= mNumberOfCameras) { ALOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",callingPid, cameraId); return NULL; } char value[PROPERTY_VALUE_MAX]; /*策略相关*/ property_get("sys.secpolicy.camera.disabled", value, "0"); if (strcmp(value, "1") == 0) { // Camera is disabled by DevicePolicyManager. ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid); return NULL; } Mutex::Autolock lock(mServiceLock); /*这是CameraService类中的一个成员变量是用来记录摄像头设备的,并且 *它是一个数组wp
mClient[MAX_CAMERAS];每一个设备都对应一个Client */ if (mClient[cameraId] != 0) {//第一次来的是应该是为空的,所以不会走这条分支 client = mClient[cameraId].promote(); if (client != 0) { if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) { LOG1("CameraService::connect X (pid %d) (the same client)", callingPid); return client; } else { ALOGW("CameraService::connect X (pid %d) rejected (existing client).",callingPid); return NULL; } } mClient[cameraId].clear(); } if (mBusy[cameraId]) {/*如果这设备ID处于忙状态*/ ALOGW("CameraService::connect X (pid %d) rejected" " (camera %d is still busy).", callingPid, cameraId); return NULL; } /*这个结构是硬件抽象范畴的,里面包含了一些基本信息 * 其中facing描述前置还是后置 * orientation 用来描述image方向 * device_version用来描述HAL的版本 */ struct camera_info info; if (mModule->get_camera_info(cameraId, &info) != OK) { ALOGE("Invalid camera id %d", cameraId); return NULL; } int deviceVersion; if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) { deviceVersion = info.device_version; } else { deviceVersion = CAMERA_DEVICE_API_VERSION_1_0; } /*根据HAL不同API的版本创建不同的client实例,在之前版本中不是这样的,这是4.2的变化*/ switch(deviceVersion) { case CAMERA_DEVICE_API_VERSION_1_0: client = new CameraClient(this, cameraClient, cameraId,info.facing, callingPid, getpid()); break; case CAMERA_DEVICE_API_VERSION_2_0://for 4.2 client = new Camera2Client(this, cameraClient, cameraId, info.facing, callingPid, getpid()); break; default: ALOGE("Unknown camera device HAL version: %d", deviceVersion); return NULL; } /*初始化camera_module_t *module*/ if (client->initialize(mModule) != OK) { return NULL; } cameraClient->asBinder()->linkToDeath(this); //最后将创建的CameraClient或Camera2Client实例保存到mClient[MAX_CAMERAS]数组当中去 //mClient[MAX_CAMERAS]数组是CameraService类中的成员变量 mClient[cameraId] = client;//every camera is a Client class LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid()); return client;/*最后返回*/}

首先通过该函数我们可以验证上面的(c)观点,通过CameraService生成CameraService::Client服务代理BpCamera,下面看看Client类之间的关系图

图2-2:照相机服务请求示意图2

转载于:https://my.oschina.net/jerikc/blog/112639

你可能感兴趣的文章
servlet容器与web容器的概念
查看>>
网络请求 http get post 一
查看>>
《计算机问题求解》总结——2014年CCF计算机课程改革导教班(2014.07.11)
查看>>
Google Chrome Plus——绿色便携多功能谷歌浏览器
查看>>
Instant Run
查看>>
史上最详细的iOS之事件的传递和响应机制
查看>>
Subsequence(两个单调队列)
查看>>
一行代码实现iOS序列化与反序列化
查看>>
Xamarin提示Build-tools版本过老
查看>>
一次Win10安装体验
查看>>
主流界面搭建原理(类似百思不得姐主界面)
查看>>
LogViewer - 方便的日志查看工具
查看>>
Spring依赖注入:注解注入总结
查看>>
Java正则表达式的语法与示例
查看>>
Batch
查看>>
取消Eclipse SVN的自动链接方式
查看>>
Lamda表达式,map和集合操作
查看>>
discuz的php7版本号
查看>>
Hibernate中的session和load延迟载入矛盾问题,怎样解决?
查看>>
MACD判断定背离,底背离
查看>>