Android 4.x_Camera新架构分析

起源

        Camera 在android framework 设计中是遵循着 Binder 机制所设计的. 详细设计分析在网络上很多高手有在讨论, 在这里只是点出在android4.x 之后, camera 的架构流程有了哪些变化? 在这里就以 Camera的开机流程来做说明.

一般要android app要开始使用 camera都会由 android.hardware. Camera 对象中的 open函数来会得一个instance (实体).然后再用这个实体来控制相机已达到我们的需求. (ex预览,拍照,录像等).

        现在就从android.hardware. Camera 对象中的 open函数开始分析:

//Camera.java
public static Camera open(int cameraId) {
        return new Camera(cameraId);  //自从android 2.3以来, android 装置
                                   //就有分前后镜头, 所以在此需要指
                                   //定一个id来表示前后镜头.
}
 
Camera(int cameraId) {
        mShutterCallback = null;
        mRawImageCallback = null;
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mZoomListener = null;
       
        //用来接收来自底层的讯息
        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<Camera>(this), cameraId);
}


Google在android的framework设计中有分为javalayer跟native layer. 最主要是因为java 拥有一个特点, 就是开发效率会比用 nativecode来开发还快. 所以Google在android的 framework 设计就希望可以藉由java这项特点让开发app的程序员, 可以很方便也很快速的开发出一套app. 而javalayer 跟 native layer的沟通接口就是 JNI, 这是一条将 nativelayer (c/c++) 中的函数/变量转化给javalayer看得懂的接口, 当然也是一条将 javalayer 中的函数/变量转化给 nativelayer 看得懂的界面. 转化过程不是这里的重点, 因此不在这里做分析. 在androidframework中的source code 只要有 native相关字眼的函数名, 就属于 jni layer. 由上面的程序代码可以知道native_setup 函数是一个JNI的函数.

// android_hardware_Camera.cpp
// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId)
{
    // 与Camera service 做联机.
    sp<Camera> camera = Camera::connect(cameraId);
 
    // 检查是否联机成功
    // 检查 Camera Hardware 的状态是否可用
    // 检查 java layer 呼叫者 Camera 对象是否存在
    // register listener for callback function
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this,
                               clazz, camera);
    context->incStrong(thiz);
    camera->setListener(context);
}
由上面的程序代码一开始就可以发现, 要启动Camera 就要先跟CameraService联机. 理由是一开始说的Binder机制.Binder机制是简单的一个 Client 和Service的架构. 要做任何需求前,Client 是要先跟 Service 做联机. 继续分析与CameraService的联机流程.

// Camera.cpp
sp<Camera> Camera::connect(int cameraId)
{
    ALOGV("connect");
    // 1. new 一个 camera 的物件.
    sp<Camera> c = new Camera();
    // 2. 跟 system service 要一个 Camera Service 的 proxy handler.
    const sp<ICameraService>& cs = getCameraService();
    if (cs != 0) {
        //3. 利用 Camera service 的 proxy handler 将 camera 对象跟由
        // 上层传下来的id 一起往下传.
        c->mCamera = cs->connect(c, cameraId);
    }
    if (c->mCamera != 0) {
        //4. 用来注册IBinder.DeathRecipient物件.
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        c.clear();
    }
    return c;
}
由上面的程序代码可以发现, 藉由 getCameraService 函数可以得到一个cameraservice的hanlder proxy, 这个proxy 就是一个代理人的意思. 在androidframework的设计中, 很多控制硬件的process都会由一个service的process来控制,Camera Service 正是其中之一. 在一开机的时候, ServiceManager就会去注册 android 每一个 service 以便之后统一管理. 等到需要用到某个系统的service时, 就可以藉由ServiceManger去要某个特定的service. ServiceManager在注册每一个service时, 都会有Handlerid, 这个handler id 就会对应到Handler proxy. 继续往下分析到了第三步就利用 Camera service Handler proxy 去做连结的动作. 到了第四步就去注册 IBinder.DeathRecipient物件. 这一步是属于errorhandler的动作. 类似对象里提到的例外机制.凡事都需要例外处理,Google 在设计 android framework时考虑还蛮周到的.Google 在设计 Binder 这个机制便加了例外处理. 一旦Client 跟Service之间的 Binder联机时, 只要有注册 IBinder.DeathRecipient物件. 会有一个callback函数 binderDied 会被触发. 触发流程不在这个范围. 所以点到为止. 回到第三步继续分析. 刚刚有说到是利用 CameraService handler proxy来做连结的动作, 这个链接的动作 connect函数到底是在哪个类别中定义的呢? 在这里只是介绍如何去tarcecode, 其原理是跟Binder机制有关, 哪是属于binder的原理, 所以不在这里分析. 由第三步会发现 connect函数是由 cs 带出来的. 这个cs 对象的宣告在上一行程序.

const sp<ICameraService>& cs = getCameraService();


const sp<ICameraService>& cs = getCameraService();

这一行程序代码的解读如下, 宣告一个为ICameraService数据型态strongpointer,这个strong pointer是一个指向常数的参考对象指针. 这里的strongpointer 跟 c++里的smartpointer有异曲同工之妙, 都是具有资源回收的效果. 其结构详细分析也不在这个范围内, 所以也是点到为止. 这行程序代码在这里的重点是ICameraService这个数据型态. 在android framework中,Binder的类别定义分为BnXXX, BpXXX这两个类别, 只要看到有对象是IXXX数据型态宣告, 就去找跟BnXXX类别相关的数据定义. 实作则会出现在衍生自BnXXX类别的衍生类别.所以会发现BnCameraService类别的衍生类别就是 CameraService 类别.而被呼叫的connect函数便实作在 CameraService 类别中.

// CameraService.cpp
sp<ICamera> CameraService::connect(
        const sp<ICameraClient>& 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> 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);
    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]) {
        ALOGW("CameraService::connect X (pid %d) rejected"
                " (camera %d is still busy).", callingPid, cameraId);
        return NULL;
    }
 
    struct camera_info info;
    if (mModule->get_camera_info(cameraId, &info) != OK) {
        ALOGE("Invalid camera id %d", cameraId);
        return NULL;
    }
    //检查 Hal module api version
    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;
    }
 
    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:
        client = new Camera2Client(this, cameraClient, cameraId,
                info.facing, callingPid, getpid());
        break;
      default:
        ALOGE("Unknown camera device HAL version: %d", deviceVersion);
        return NULL;
    }
    //初始化Camera device driver
    if (client->initialize(mModule) != OK) {
        return NULL;
    }
    //注册IBinder.DeathRecipient物件.
    cameraClient->asBinder()->linkToDeath(this);
 
    mClient[cameraId] = client;
    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
    return client;
}
在函数一开头便判断 mModule对象是否存在, 这个 mModule对象到底是甚么东西呢, 为何一开头就需要去做判断. 代表是一个很重要的对象. 搜寻了一下整个程序代码, 发现在 onFirstRef 函数有 mModule 的足迹.

// CameraService.cpp
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);
        }
    }
}
这个onFirstRef函数算是overwrite函数, 只要有继承RefBase 类别的衍生类别都会去 overwrite onFirstRef函数来做初始化的动作. 这个onFirstRef函数初始化的动作会比建构子的初始化还更前面. 这算是strongpointer设计的功能之一. 从一开头会发现 mModule 的信息是由 hw_get_module函数提供的. 由此可知, 在camera这一块, 从android4.x开始终于有了自己的HAL module了. 在android 2.3的时候, 仍然是由一个抽象类 CameraHardwareInterface 去衍生出CameraHAL 类别. 这两个差别在于前者只要利用一个HALmodule ID CAMERA_HARDWARE_MODULE_ID 就可以跟cameradriver 沟通了, 无需要跟driverlayer 的 function 绑在一起. 后者则是还需要利用衍生的CameraHAL类别去跟 driver layer的function绑在一起才能运作, 无法达到抽换更新的流程. 而原本的抽象类 CameraHardwareInterface 在android4.x之后就变成一般的类别了.

总结

        由此可以做个总结,Android 4.x 的camera 架构跟Android2.3的camera架构有以下的差异:

1. 新增了一个 CameraHAL module来取代原本的架构.

2. 原本的 CameraHardwareInterface 抽象类演变成实体类别, 是给 CAMERA_DEVICE_API_VERSION_1_0的CameraClient 对象使用.CAMERA_DEVICE_API_VERSION_1_0 CAMERA_DEVICE_API_VERSION_2_0 的差别在于前者算是过渡期..CAMERA_DEVICE_API_VERSION_1_0 CAMERA_DEVICE_API_VERSION_2_0的定义如下:

// camera_common.h
#define CAMERA_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
#define CAMERA_MODULE_API_VERSION_2_0 HARDWARE_MODULE_API_VERSION(2, 0)
 

3. HAL 的结构进板, 这算是属于在HALmodule design的范围内, 不过既然CameraService的connect 函数有用到Hal module,

// CameraService.cpp
    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;
    }

所以这里就把进板的新数据型态贴出来.

/**
 * Every hardware module must have a data structure named
 * HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;
 
    /**
     * The API version of the implemented module. The module owner is
     * responsible for updating the version when a module interface has
     * changed.
     *
     * The derived modules such as gralloc and audio own and manage this field.
     * The module user must interpret the version field to decide whether or
     * not to inter-operate with the supplied module implementation.
     * For example, SurfaceFlinger is responsible for making sure that
     * it knows how to manage different versions of the gralloc-module API,
     * and AudioFlinger must know how to do the same for audio-module API.
     *
     * The module API version should include a major and a minor component.
     * For example, version 1.0 could be represented as 0x0100. This format
     * implies that versions 0x0100-0x01ff are all API-compatible.
     *
     * In the future, libhardware will expose a hw_get_module_version()
     * (or equivalent) function that will take minimum/maximum supported
     * versions as arguments and would be able to reject modules with
     * versions outside of the supplied range.
     */
    uint16_t module_api_version;
#define version_major module_api_version
    /**
     * version_major/version_minor defines are supplied here for temporary
     * source code compatibility. They will be removed in the next version.
     * ALL clients must convert to the new version format.
     */
 
    /**
     * The API version of the HAL module interface. This is meant to
     * version the hw_module_t, hw_module_methods_t, and hw_device_t
     * structures and definitions.
     *
     * The HAL interface owns this field. Module users/implementations
     * must NOT rely on this value for version information.
     *
     * Presently, 0 is the only valid value.
     */
    uint16_t hal_api_version;
#define version_minor hal_api_version
 
    /** Identifier of module */
    const char *id;
 
    /** Name of this module */
    const char *name;
 
    /** Author/owner/implementor of the module */
    const char *author;
 
    /** Modules methods */
    struct hw_module_methods_t* methods;
 
    /** module's dso */
    void* dso;
 
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
 
} hw_module_t;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值