Android Camera API和HAL版本对应关系

前言

Android在版本更新和迭代过程中, Camera相关代码也经历了几个版本的更新, 主要表现为Camera HAL版本更新(HAL1 -> HAL2 -> HAL3), Camera API版本更新(Camera API1 -> Camera API2), 由于Android版本是向后兼容的, 所以为了解决兼容问题, 势必要做一些特殊的处理来保证不同版本调用问题, 本文主要说明 Camera HAL1, Camera HAL3, API1, API2之间的调用关系, 由于Camera HAL2只是一个过渡版本, 并且实际上并没有使用, 所以不做讨论.

说明: Camera API1泛指 android.hardware.camera 包下的相关API, Camera API2泛指
android.hardware.camera2 包下的相关API.

HAL版本和Java API版本是否能交叉调用?

由于HAL版本有HAL1和HAL3, Java API有 API1和API2. 两两组合调用就要4种方式, 那么这4种方式在Android中是否都有其使用场景呢?
答案是肯定的, 即4种组合(API1 -> HAL1, API1 -> HAL3, API2 -> HAL1, API2 -> HAL3)在Android系统中都能正常调用, 根据Android系统HAL层支持情况和API使用情况不同, 就会出现上述四种组合的使用场景, 下面就具体介绍一下4种组合是在那种情况下使用到的, 以及基本实现原理.

版本转换以及代码位置

对于Google最初的设计初衷, Camera API1就是用来调用HAL1的, Camera API2则是用来调用HAL3的, 但由于Android碎片化严重, 加上要兼容版本, 所以API1也可以调用HAL3, API2也可以调用HAL1,转换原理如下:

说明: 以下所有代码片段为高通平台, Android 7.1.1源码中的代码

API1调用HAL3

API1调用HAL3是在CameraService中完成转换, 使用了不同的Client(Client泛指CameraService和HAL层之间的接口, 有三个版本), 代码如下:

源码位置: frameworks/av/services/camera/libcameraservice/CameraService.cpp

代码:

Status CameraService::makeClient(const sp& cameraService,
        const sp& cameraCb, const String16& packageName, int cameraId,
        int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
        int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
        /*out*/sp* client) {

    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:
            if (effectiveApiLevel == API_1) {  // Camera1 API route
                sp tmp = static_cast(cameraCb.get());
                *client = new CameraClient(cameraService, tmp, packageName, cameraId, facing,
                        clientPid, clientUid, getpid(), legacyMode);
            } else { // Camera2 API route
                ALOGW("Camera using old HAL version: %d", deviceVersion);
                return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
                        "Camera device \"%d\" HAL version %d does not support camera2 API",
                        cameraId, deviceVersion);
            }
            break;
          case CAMERA_DEVICE_API_VERSION_3_0:
          case CAMERA_DEVICE_API_VERSION_3_1:
          case CAMERA_DEVICE_API_VERSION_3_2:
          case CAMERA_DEVICE_API_VERSION_3_3:
          case CAMERA_DEVICE_API_VERSION_3_4:
            if (effectiveApiLevel == API_1) { // Camera1 API route
                sp tmp = static_cast(cameraCb.get());
                *client = new Camera2Client(cameraService, tmp, packageName, cameraId, facing,
                        clientPid, clientUid, servicePid, legacyMode);
            } else { // Camera2 API route
                sp tmp =
                        static_cast(cameraCb.get());
                *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
                        facing, clientPid, clientUid, servicePid);
            }
            break;
          default:
            // Should not be reachable
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                    "Camera device \"%d\" has unknown HAL version %d",
                    cameraId, deviceVersion);
        }
    } 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.
            sp tmp = static_cast(cameraCb.get());
            *client = new CameraClient(cameraService, tmp, packageName, cameraId, facing,
                    clientPid, clientUid, servicePid, 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 STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                    "Camera device \"%d\" (HAL version %d) cannot be opened as HAL version %d",
                    cameraId, deviceVersion, halVersion);
        }
    }
    return Status::ok();
}

上述代码中基本判断逻辑是:

  1. 打开HAL版本没有特殊指定(即正常调用Camera.open()),或者指定的HAL版本和要打开的Camera默认的HAL版本相同, 则根据要打开的Camera的默认HAL版本创建Client, 此时,如果HAL层默认使用HAL1,则创建 CameraClient, 如果HAL层默认使用HAL3, 根据使用API进行判断, 使用API1则创建 Camera2Client, 使用API2则创建 CameraDeviceClient.
  2. 如果指定了一个特殊的HAL版本, 并且不是默认的HAL版本, 此时只会创建 CameraClient, 其他情况不支持, 原因注释里面也说明了.

上述几个Client代码位置为:

frameworks/av/services/camera/libcameraservice/api1/
frameworks/av/services/camera/libcameraservice/api2/

其中 CameraClient.cpp 是API调用HAL1的接口, Camera2Client.cpp 是API1调用HAL3接口, CameraDeviceClient 是API2调用HAL3接口, 是不是发现没有API2调用HAL1接口? 接下来就会讲这个了, 和上述转换有区别.

API2调用HAL1

在4种调用组合里面, 有3种是通过在CameraService中创建不同的Client来实现的, 只有API2调用HAL1是在API层面实现的,即把Camera API2的API调用转为Camera API1, 下面通过源码来看下使用API2调用HAL1时打开Camera操作是如何转换的.

Camera API2 打开Camera流程
frameworks/base/core/java/android/hardware/camera2/CameraManager.java

 public void openCamera(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
            throws CameraAccessException {

        openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
    }

调用 openCameraForUid

public void openCameraForUid(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler,
            int clientUid)
            throws CameraAccessException {

        if (cameraId == null) {
            throw new IllegalArgumentException("cameraId was null");
        } else if (callback == null) {
            throw new IllegalArgumentException("callback was null");
        } else if (handler == null) {
            if (Looper.myLooper() != null) {
                handler = new Handler();
            } else {
                throw new IllegalArgumentException(
                        "Handler argument is null, but no looper exists in the calling thread");
            }
        }

        openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
    }

调用 openCameraDeviceUserAsync

 private CameraDevice openCameraDeviceUserAsync(String cameraId,
            CameraDevice.StateCallback callback, Handler handler, final int uid)
            throws CameraAccessException {
//部分源码省略......
 ICameraDeviceUser cameraUser = null;
try {
    if (supportsCamera2ApiLocked(cameraId)) {
        // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
        ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
        if (cameraService == null) {
            throw new ServiceSpecificException(
                ICameraService.ERROR_DISCONNECTED,
                "Camera service is currently unavailable");
        }
        cameraUser = cameraService.connectDevice(callbacks, id,
                mContext.getOpPackageName(), uid);
    } else {
        // Use legacy camera implementation for HAL1 devices
        Log.i(TAG, "Using legacy camera HAL.");
        cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
    }
}
//部分源码省略......

上面的 supportsCamera2ApiLocked(cameraId) 就是判断是否支持HAL3, 如果不支持, 就调用
CameraDeviceUserShim.connectBinderShim(callbacks, id); 来获取
ICameraDeviceUser, 最后看下函数 connectBinderShim() 代码:

import android.hardware.Camera;

public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
                                                     int cameraId) {
    //部分代码省略...
    // TODO: Make this async instead of blocking
    int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
    Camera legacyCamera = init.getCamera();
    //部分代码省略...
    LegacyCameraDevice device = new LegacyCameraDevice(
            cameraId, legacyCamera, characteristics, threadCallbacks);
    return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
}

从上面import语句和 Camera legacyCamera = init.getCamera(); 就能看出来,此处是调用Camera API1接口来实现的, 所以Camera API2调用HAL1其实是在Framework层将API2接口转为了API1, 对CameraService来说, 就是使用API1来调用. 转换代码路径在: frameworks/base/core/java/android/hardware/camera2/legacy/, 有兴趣的可以看下.

各种版本调用使用场景

从上面的分析大家都了解了API和HAL之间不同版本转换关系, 之所以有这么多转换, 就是为了实现兼容, 因此下面简单说一下各个版本在什么场景下有用武之地.

  1. API1 调用 HAL1
    Android 5.0之前, 几乎所有手机都使用的场景,也是最开始Camera API1设计的初衷
  2. API1 调用 HAL3
    对于支持HAL3手机,并默认使用HAL3作为HAL的版本, 此种类型是手机想使用HAL3和Camera API2, 单由于没法限制第三方应用也使用Camera API2,而做出的一种兼容方式.
  3. API2 调用 HAL1
    手机不支持HAL3, 但应用使用了Camera API2, 常见于中低端手机, Android版本是5.0以上, 但底层不支持HAL3.
  4. API2 调用 HAL3
    Camera API2设计初衷就是调用HAL3的, 现在大多数中高端手机基本都是API2调用HAL3, 最大限度使用Camera提供的功能

总结

  • 不同API和HAL版本直接调用可简单总结为以下几点:
    API1 -> HAL1, 原始Camera流程, CameraService中使用的Client为 CameraClient
    API1 -> HAL3, 兼容使用API1的应用, CameraService中使用的Client为 Camera2Client
    API2 -> HAL1, 底层只支持HAL1, 为了兼容API2应用, 通过Framework层将API2转为API1实现
    API2 -> HAL3, 未来趋势, 提供更好的Camera控制能力, CameraService使用的Client为CameraDeviceClient
  • API1调用HAL3和API2调用HAL1对于应用来说, 都没有发挥HAL3和API2的功能, 只是一个兼容方案.

最后通过一张图片来直观明了的说明版本直接关系:


Android Camera API和HAL版本对应关系_第1张图片
camera_api_hal_version.JPG

你可能感兴趣的:(Android Camera API和HAL版本对应关系)