Android5.0 Camera Framework 简介

CameraService启动

CameraService是在MediaServer启动过程中进行的
main_mediaserver.cpp (frameworks\av\media\mediaserver)

......AudioFlinger::instantiate(); //audioflinger服务,音频相关MediaPlayerService::instantiate(); //mediaplayerservice,媒体播放相关CameraService::instantiate();//CameraServiceAudioPolicyService::instantiate(); //音频相关......

在 main函数中会执行到CameraService::instantiate(), CameraService 本身并没有实现这个方法
CameraService.cpp (frameworks\av\services\camera\libcameraservice)
CameraService.h (frameworks\av\services\camera\libcameraservice)
BinderService.h (frameworks\native\include\binder)

class CameraService :    public BinderService<CameraService>,    public BnCameraService,    public IBinder::DeathRecipient,    public camera_module_callbacks_t{    ......}

在其父类中寻找instantiate()函数,BinderService是一个模板类

template<typename SERVICE>class BinderService{public:    static status_t publish(bool allowIsolated = false) { //BinderService::publish        sp<IServiceManager> sm(defaultServiceManager()); //拿到ServiceManager的Bp        return sm->addService(                String16(SERVICE::getServiceName()),                new SERVICE(), allowIsolated);           //这里的SERVICE就是CameraService    }    .....    static void instantiate() { publish(); }      //BinderService::instantiate    .....};

这里会new CameraService(),

CameraService::CameraService()    :mSoundRef(0), mModule(0){    ALOGI("CameraService started (pid=%d)", getpid());    gCameraService = this;    //保存一个本地指针    for (size_t i = 0; i < MAX_CAMERAS; ++i) {        mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;    }    this->camera_device_status_change = android::camera_device_status_change;}

到这里,CameraService就启动了。

Camera连接过程

Camera.java (frameworks\base\core\java\android\hardware)
Camera.cpp (frameworks\av\camera)
android_hardware_Camera.cpp (frameworks\base\core\jni)
从java->jni->CPP的典型过程
首先从Camera.java入手,这里通过open()方法,创建Camera

    public static Camera open(int cameraId) {        return new Camera(cameraId);    }    public static Camera open() {        int numberOfCameras = getNumberOfCameras();        CameraInfo cameraInfo = new CameraInfo();        for (int i = 0; i < numberOfCameras; i++) {            getCameraInfo(i, cameraInfo);            if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {                return new Camera(i);            }        }        return null;    }

两个open()方法,默认打开后置摄像头,new Camera()对象,

    Camera(int cameraId) {        int err = cameraInitNormal(cameraId);//做事的主要地方        if (checkInitErrors(err)) {            switch(err) {                    //通过返回的错误信息,抛不同的异常信息                case EACCESS:                    throw new RuntimeException("Fail to connect to camera service");                case ENODEV:                    throw new RuntimeException("Camera initialization failed");                default:                    // Should never hit this.                    throw new RuntimeException("Unknown camera error");            }        }    }

接下来看下代码,最后会落脚到哪一块呢?

    private int cameraInitNormal(int cameraId) {        //这里的CAMERA_HAL_API_VERSION_NORMAL_CONNECT后面会提到用来区别不同的connect        return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);    }    ......    private int cameraInitVersion(int cameraId, int halVersion) {        mShutterCallback = null;                   mRawImageCallback = null;        mJpegCallback = null;        mPreviewCallback = null;        mPostviewCallback = null;        mUsingPreviewAllocation = false;        mZoomListener = null;             //初始化几个callback和一些变量        Looper looper;            //mEventHandler后面会讲到是对底层上报内容的处理handler        if ((looper = Looper.myLooper()) != null) {            mEventHandler = new EventHandler(this, looper);        } else if ((looper = Looper.getMainLooper()) != null) {            mEventHandler = new EventHandler(this, looper);        } else {            mEventHandler = null;        }        String packageName = ActivityThread.currentPackageName();        return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);    }

可以看到native_setup是一个native方法,具体实现在
android_hardware_Camera.cpp (frameworks\base\core\jni)

static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName){    ......    sp<Camera> camera;    //之前在创建Camera对象的时候设置的一个常量,此时走到connect方法    if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {        // Default path: hal version is don't care, do normal camera connect.        camera = Camera::connect(cameraId, clientName,                Camera::USE_CALLING_UID);    } else {        jint status = Camera::connectLegacy(cameraId, halVersion, clientName,                Camera::USE_CALLING_UID, camera);        if (status != NO_ERROR) {            return status;        }    }    ......    // We use a weak reference so the Camera object can be garbage collected.    // The reference is only used as a proxy for callbacks.    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);    context->incStrong((void*)android_hardware_Camera_native_setup);    camera->setListener(context);//listener用于处理底层数据上报    // save context in opaque field    env->SetLongField(thiz, fields.context, (jlong)context.get());    return NO_ERROR;}

从JNI往下就是CPP,继续探寻Camera连接过程
Camera.cpp (frameworks\av\camera)
CameraBase.cpp (frameworks\av\camera)

sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,        int clientUid){   //CameraBaseT为模板类    return CameraBaseT::connect(cameraId, clientPackageName, clientUid);}

CameraBase中connect函数模板替换成

sp<Camera> CameraBase<Camera, CameraTraits<Camera>>::connect(int cameraId,                                               const String16& clientPackageName,                                               int clientUid){    ALOGV("%s: connect", __FUNCTION__);    sp<Camera> c = new Camera(cameraId);    sp<ICameraClient> cl = c;    status_t status = NO_ERROR;    const sp<ICameraService>& cs = getCameraService();//获取CameraService的Bp    if (cs != 0) {        //这里TCamConncectService是一个函数指针,指向的是ICameraService中的connect方法        TCamConnectService fnConnectService = TCamTraits::fnConnectService;        status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, /*out*/ c->mCamera); status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, /*out*/ c->mCamera); } if (status == OK && c->mCamera != 0) { c->mCamera->asBinder()->linkToDeath(c);        c->mStatus = NO_ERROR;    } else {        ALOGW("An error occurred while connecting to camera: %d", cameraId);        c.clear();    }    return c;}

这里可能有点绕,稍微讲解一下,模板上
template

template <typename TCam>struct CameraTraits {};template <typename TCam, typename TCamTraits = CameraTraits<TCam> >

然后我们再到Camera.h中看
template <>
struct CameraTraits
{
typedef CameraListener TCamListener;
typedef ICamera TCamUser;
typedef ICameraClient TCamCallbacks;
typedef status_t (ICameraService::*TCamConnectService)(const sp&,
int, const String16&, int,
/out/
sp&);
static TCamConnectService fnConnectService;
};
中间有些过程,应该好理解了,这里绕了一下,最后落脚到ICameraService.cpp中的connect方法,这一部分涉及到Binder机制比较多,暂时先不讲解具体内容,注意调用的地方即可。
ICameraService.cpp (frameworks\av\camera)

    // connect to camera service (android.hardware.Camera)    virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,                             const String16 &clientPackageName, int clientUid,                             /*out*/                             sp<ICamera>& device)    {        Parcel data, reply;        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());        data.writeStrongBinder(cameraClient->asBinder());        data.writeInt32(cameraId);        data.writeString16(clientPackageName);        data.writeInt32(clientUid);        remote()->transact(BnCameraService::CONNECT, data, &reply);//通过binder远端调用传入的code为BnCameraservice::CONNECT        if (readExceptionCode(reply)) return -EPROTO;        status_t status = reply.readInt32();        if (reply.readInt32() != 0) {            device = interface_cast<ICamera>(reply.readStrongBinder());//转换为BpCamera        }        return status;    }

接下来或执行到BnCameraService的onTransact()方法,主要就是switch_case,上面传入的是CONNECT

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<ICameraClient> cameraClient =                    interface_cast<ICameraClient>(data.readStrongBinder());            int32_t cameraId = data.readInt32();            const String16 clientName = data.readString16();            int32_t clientUid = data.readInt32();            sp<ICamera> camera;            status_t status = connect(cameraClient, cameraId,                    clientName, clientUid, /*out*/camera);                    //这里BnCameraService并没有实现connect函数,实际实现在CameraService中            reply->writeNoException();            reply->writeInt32(status);            if (camera != NULL) {                reply->writeInt32(1);                reply->writeStrongBinder(camera->asBinder());            } else {                reply->writeInt32(0);            }            return NO_ERROR;        } break;    ......    } }

我们来看一下CameraService中的connect方法到底做了哪些事情

status_t CameraService::connect(        const sp<ICameraClient>& cameraClient,        int cameraId,        const String16& clientPackageName,        int clientUid,        /*out*/        sp<ICamera>& device) {    String8 clientName8(clientPackageName);    int callingPid = getCallingPid();    LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,            clientName8.string(), cameraId);    //对当前连接请求合法性的判断    status_t status = validateConnect(cameraId, /*inout*/clientUid);    if (status != OK) {        return status;    }    //Client类继承BnCamera BasicClient    sp<Client> client;    {        Mutex::Autolock lock(mServiceLock);        sp<BasicClient> clientTmp;        //判断当前设备是否被占有或者是重复请求        if (!canConnectUnsafe(cameraId, clientPackageName,                              cameraClient->asBinder(),                              /*out*/clientTmp)) {            return -EBUSY;//从返回结果可以看出这个函数的用途        } else if (client.get() != NULL) {            device = static_cast<Client*>(clientTmp.get());            return OK;        }        //考虑当前没有其他程序占用摄像头,走到下一步        status = connectHelperLocked(/*out*/client,                                     cameraClient,                                     cameraId,                                     clientPackageName,                                     clientUid,                                     callingPid);        if (status != OK) {            return status;        }    }    // important: release the mutex here so the client can call back    // into the service from its destructor (can be at the end of the call)    //赋值给device作为传出参数    device = client;    return OK;}

继续跟踪到connectHelperLocked()函数中

status_t CameraService::connectHelperLocked(        /*out*/        sp<Client>& client,        /*in*/        const sp<ICameraClient>& cameraClient,        int cameraId,        const String16& clientPackageName,        int clientUid,        int callingPid,        int halVersion,        bool legacyMode) {    int facing = -1;    int deviceVersion = getDeviceVersion(cameraId, &facing);    if (halVersion < 0 || halVersion == deviceVersion) {        // Default path: HAL version is unspecified by caller, create CameraClient        // based on device version reported by the HAL.        switch(deviceVersion) {          case CAMERA_DEVICE_API_VERSION_1_0:            //创建CameraClient对象            client = new CameraClient(this, cameraClient,                    clientPackageName, cameraId,                    facing, callingPid, clientUid, getpid(), legacyMode);            break;          case CAMERA_DEVICE_API_VERSION_2_0:          case CAMERA_DEVICE_API_VERSION_2_1:          case CAMERA_DEVICE_API_VERSION_3_0:          case CAMERA_DEVICE_API_VERSION_3_1:          case CAMERA_DEVICE_API_VERSION_3_2:            client = new Camera2Client(this, cameraClient,                    clientPackageName, cameraId,                    facing, callingPid, clientUid, getpid(), legacyMode);            break;          case -1:            ALOGE("Invalid camera id %d", cameraId);            return BAD_VALUE;          default:            ALOGE("Unknown camera device HAL version: %d", deviceVersion);            return INVALID_OPERATION;        }    } else {        // A particular HAL version is requested by caller. Create CameraClient        // based on the requested HAL version.        if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&            halVersion == CAMERA_DEVICE_API_VERSION_1_0) {            // Only support higher HAL version device opened as HAL1.0 device.            client = new CameraClient(this, cameraClient,                    clientPackageName, cameraId,                    facing, callingPid, clientUid, getpid(), legacyMode);        } else {            // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.            ALOGE("Invalid camera HAL version %x: HAL %x device can only be"                    " opened as HAL %x device", halVersion, deviceVersion,                    CAMERA_DEVICE_API_VERSION_1_0);            return INVALID_OPERATION;        }    }    //主要是对CameraClient的初始化过程    status_t status = connectFinishUnsafe(client, client->getRemote());    if (status != OK) {        // this is probably not recoverable.. maybe the client can try again        return status;    }    //保存CameraClient对象到本地数组中,以备CameraService使用    mClient[cameraId] = client;    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,         getpid());    return OK;}

这里的client创建成功后会赋值给device,而device就是之前连接过程中的传入参数,到这里Camera的连接过程就基本完成了。

本文主要顺着代码理了一下过程,具体细节地方可能有所忽略。主要的流程图如下,欢迎交流指正。

本文中代码使用的是Android5.1原始代码

版权声明:本文为博主原创文章,未经博主允许不得转载。

更多相关文章

  1. android 五种Toast显示方法
  2. MTK android 下载及启动过程
  3. 关于AlertDialog中EditText不能弹出输入法解决方法
  4. android实现圆角矩形背景的方法
  5. Android RadioButton【单选按钮】的点击事件的两种方法
  6. android 跳转到系统相关应用的方法
  7. android屏幕信息获取的两种方法
  8. android os编译全过程
  9. Android中new Notification创建实例的最佳方法

随机推荐

  1. Flink1.8.0重大更新-Flink中State的自动
  2. golang核心原理-协程栈
  3. 数据不撒谎,Flink-Kafka性能压测全记录!
  4. golang核心原理-协程调度时机
  5. 《MySQL》系列 - 十张图详解 MySQL 日志(
  6. 【腾讯二面】5s内建立多少个mysql连接?
  7. Java异常与调优一站式解决方案
  8. 昨天面试别人说他熟悉Flink,结果我问了他F
  9. js作业一常识类
  10. 2021-04-04:给定一个非负数组arr,和一个正