当前位置: 代码迷 >> 综合 >> Android 源码 Camera2 openCamera 流程分析
  详细解决方案

Android 源码 Camera2 openCamera 流程分析

热度:52   发布时间:2024-03-06 10:09:21.0

打开相机的起点从 CameraManager 类 openCamera(…) 方法开始。

在这里插入图片描述
打开具有给定 ID 的相机连接。

使用 getCameraIdList 获取可用相机设备的列表。请注意,即使列出了 ID,但如果在对 getCameraIdList 和 openCamera 的调用之间断开了设备的连接,或者如果优先级更高的相机 API 客户端开始使用相机设备,则打开可能会失败。

从 API 级别 23 开始,由于优先级较低的后台相机 API 客户端正在使用该设备,因此已调用 AvailabilityCallback#onCameraUnavailable(String) 回调的设备仍可以通过调用此方法,来打开当调用相机 API 客户端的优先级高于使用此设备的当前相机 API 客户端时。通常,如果最顶层的前台活动正在您的应用程序进程中运行,则在访问相机时,将为您的进程赋予最高优先级,并且即使另一个相机 API 客户端正在使用相机设备,此方法也会成功。以此方式失去控制权的所有低优先级应用程序都将收到 android.hardware.camera2.CameraDevice.StateCallback#onDisconnected 回调。

成功打开相机后,将使用新打开的 CameraDevice 调用 CameraDevice.StateCallback#onOpened。然后可以通过调用 CameraDevice#createCaptureSession 和 CameraDevice#createCaptureRequest 设置相机设备进行操作。

由于相机设备将以异步方式打开,因此对返回的 CameraDevice 实例执行的所有异步操作都将排队,直到设备启动完成并调用回调的 CameraDevice.StateCallback#onOpened 方法为止。然后按顺序处理挂起的操作。

如果在此函数调用返回后初始化期间相机断开连接,则 CameraDevice.StateCallback#onDisconnected 的 CameraDevice 处于断开状态(并且 CameraDevice.StateCallback#onOpened 将被跳过)。

如果打开相机设备失败,则将调用设备回调的 CameraDevice.StateCallback#onError 方法,并且在相机设备上进行的后续调用将引发 CameraAccessException。

@param cameraId 要打开的相机设备的唯一标识符

@param callback 打开相机后调用的回调

@param handler 应该在其上调用回调的 Handler,或者是 null 以使用当前线程的 android.os.Looper

openCamera(…) 首先做了必要的参数检查,最后直接调用 openCameraDeviceUserAsync(…) 处理真正的打开相机流程。

frameworks/base/core/java/android/hardware/camera2/CameraManager.java

public final class CameraManager {
    ......@RequiresPermission(android.Manifest.permission.CAMERA)public void openCamera(@NonNull String cameraId,@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)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);}......
}

帮助打开与给定 ID 的相机连接。

  1. 创建 CameraDeviceImpl 对象,它继承自 CameraDevice
  2. 假设支持 Camera2Api,获取 CameraService
  3. 调用 CameraService connectDevice 方法连接相机设备
  4. 获取 CameraDeviceUser
  5. CameraDeviceImpl 对象上调用 setRemoteDevice(…) 方法
  6. 返回 CameraDeviceImpl 对象

frameworks/base/core/java/android/hardware/camera2/CameraManager.java

public final class CameraManager {
    ......private CameraDevice openCameraDeviceUserAsync(String cameraId,CameraDevice.StateCallback callback, Handler handler)throws CameraAccessException {
    CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);CameraDevice device = null;try {
    synchronized (mLock) {
    ICameraDeviceUser cameraUser = null;android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =new android.hardware.camera2.impl.CameraDeviceImpl(cameraId,callback,handler,characteristics);BinderHolder holder = new BinderHolder();ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();int id = Integer.parseInt(cameraId);try {
    if (supportsCamera2ApiLocked(cameraId)) {
    // 使用 cameraservice 的 cameradeviceclient 实现 HAL3.2+ 设备ICameraService cameraService = CameraManagerGlobal.get().getCameraService();if (cameraService == null) {
    throw new CameraRuntimeException(CameraAccessException.CAMERA_DISCONNECTED,"Camera service is currently unavailable");}cameraService.connectDevice(callbacks, id,mContext.getOpPackageName(), USE_CALLING_UID, holder);cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());} else {
    // 对 HAL1 设备使用旧版相机实现Log.i(TAG, "Using legacy camera HAL.");cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);}} catch (CameraRuntimeException e) {
    ......} catch (RemoteException e) {
    ......}// TODO: factor out callback to be non-nested, then move setter to constructor// 目前,调用 setRemoteDevice 将触发初始的 onOpened/onUnconfigured 回调。deviceImpl.setRemoteDevice(cameraUser);device = deviceImpl;}} catch (NumberFormatException e) {
    ......} catch (CameraRuntimeException e) {
    ......}return device;}    ......
}

HAL2.1+ CameraDevice 实现。使用 CameraManager#open 实例化。

  1. 获取 TAG
  2. 获取 partialCount

REQUEST_PARTIAL_RESULT_COUNT 定义结果将由多少个子组件组成。

为了消除流水线延迟,可以在部分结果可用时立即将其从相机设备传递到应用程序层。

可选的; 默认值为 1。值 1 表示不支持部分结果,并且相机设备将仅生成最终的 TotalCaptureResult。一个典型的用例可能是:请求自动对焦(AF)锁定后,新的 AF 状态在整个管道中可能有 50% 可用。然后,相机设备可以通过部分结果立即将状态分发给应用程序,其余的元数据则通过以后的部分结果进行分发。

frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java

public class CameraDeviceImpl extends CameraDevice {
    ......public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler,CameraCharacteristics characteristics) {
    if (cameraId == null || callback == null || handler == null || characteristics == null) {
    throw new IllegalArgumentException("Null argument given");}mCameraId = cameraId;mDeviceCallback = callback;mDeviceHandler = handler;mCharacteristics = characteristics;final int MAX_TAG_LEN = 23;String tag = String.format("CameraDevice-JV-%s", mCameraId);if (tag.length() > MAX_TAG_LEN) {
    tag = tag.substring(0, MAX_TAG_LEN);}TAG = tag;Integer partialCount =mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);if (partialCount == null) {
    // 1 means partial result is not supported.mTotalPartialCount = 1;} else {
    mTotalPartialCount = partialCount;}}    ......
}

现在了解一下 CameraDevice 类。

CameraDevice 类代表连接到 Android 设备的单个相机的表示形式,允许以高帧率对图像捕获和后处理进行细粒度控制。

应用必须在其清单中声明 android.Manifest.permission#CAMERA Camera 权限,才能访问相机设备。

给定的相机设备可以提供以下两个级别之一的支持:受限或完全支持。 如果设备仅支持有限级别,则 Camera2 会公开一个功能集,该功能集与旧版 android.hardware.Camera Camera API 大致相同,尽管接口更加简洁高效。与旧版相机 API 相比,实现全面支持的设备提供了显着改进的功能。 针对有限级别设备的应用程序将在完整级别设备上保持不变;如果应用程序需要完整级别的设备才能正常运行,请在清单中声明 “ android.hardware.camera.level.full” 功能。

frameworks/base/core/java/android/hardware/camera2/CameraDevice.java

public abstract class CameraDevice implements AutoCloseable {
    ......
}

获取 CameraService 相机服务具体可以参见《Android 源码 Camera2 获取 CameraId 列表》一节。继续分析调用 CameraService connectDevice 方法。这会调到 BpCameraService 同名方法。

frameworks/av/camera/ICameraService.cpp

class BpCameraService: public BpInterface<ICameraService>
{
    
public:virtual status_t connectDevice(const sp<ICameraDeviceCallbacks>& cameraCb,int cameraId,const String16& clientPackageName,int clientUid,/*out*/sp<ICameraDeviceUser>& device){
    Parcel data, reply;data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());data.writeStrongBinder(IInterface::asBinder(cameraCb));data.writeInt32(cameraId);data.writeString16(clientPackageName);data.writeInt32(clientUid);status_t status;status = remote()->transact(BnCameraService::CONNECT_DEVICE, data, &reply);if (status != OK) return status;if (readExceptionCode(reply)) return -EPROTO;status = reply.readInt32();if (reply.readInt32() != 0) {
    device = interface_cast<ICameraDeviceUser>(reply.readStrongBinder());}return status;}    
}

接着在 BnCameraService onTransact(…) 方法中接收 Client 发来的消息,调用它的 connectDevice(…) 具体实现。

frameworks/av/camera/ICameraService.cpp

status_t BnCameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
    ......case CONNECT_DEVICE: {
    CHECK_INTERFACE(ICameraService, data, reply);sp<ICameraDeviceCallbacks> cameraClient =interface_cast<ICameraDeviceCallbacks>(data.readStrongBinder());int32_t cameraId = data.readInt32();const String16 clientName = data.readString16();int32_t clientUid = data.readInt32();sp<ICameraDeviceUser> camera;status_t status = connectDevice(cameraClient, cameraId,clientName, clientUid, /*out*/camera);reply->writeNoException();reply->writeInt32(status);if (camera != NULL) {
    reply->writeInt32(1);reply->writeStrongBinder(IInterface::asBinder(camera));} else {
    reply->writeInt32(0);}return NO_ERROR;} break;......}......
}

CameraService::connectDevice(…) 主要调用了 connectHelper(…) 方法。

frameworks/av/services/camera/libcameraservice/CameraService.cpp

status_t CameraService::connectDevice(const sp<ICameraDeviceCallbacks>& cameraCb,int cameraId,const String16& clientPackageName,int clientUid,/*out*/sp<ICameraDeviceUser>& device) {
    ATRACE_CALL();status_t ret = NO_ERROR;String8 id = String8::format("%d", cameraId);sp<CameraDeviceClient> client = nullptr;ret = connectHelper<ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, API_2, false, false,/*out*/client);if(ret != NO_ERROR) {
    logRejected(id, getCallingPid(), String8(clientPackageName),String8::format("%s (%d)", strerror(-ret), ret));return ret;}device = client;return NO_ERROR;
}

下面重点关注获取 BasicClient 和 从 HAL 模块初始化客户端。

frameworks/av/services/camera/libcameraservice/CameraService.h

template<class CALLBACK, class CLIENT>
status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,int halVersion, const String16& clientPackageName, int clientUid,apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,/*out*/sp<CLIENT>& device) {
    status_t ret = NO_ERROR;String8 clientName8(clientPackageName);int clientPid = getCallingPid();ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and ""Camera API version %d", clientPid, clientName8.string(), cameraId.string(),(halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),static_cast<int>(effectiveApiLevel));sp<CLIENT> client = nullptr;{
    // 获取 AutoConditionLock 并阻止其他客户端连接std::unique_ptr<AutoConditionLock> lock =AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);if (lock == nullptr) {
    ALOGE("CameraService::connect X (PID %d) rejected (too many other clients connecting).", clientPid);return -EBUSY;}// 强制执行客户端权限并进行基本的健全性检查if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
    return ret;}// 在获取锁后检查 shim 参数,如果它们已经被更新并且我们正在进行 shim 更新,立即返回if (shimUpdateOnly) {
    auto cameraState = getCameraState(cameraId);if (cameraState != nullptr) {
    if (!cameraState->getShimParams().isEmpty()) return NO_ERROR;}}sp<BasicClient> clientTmp = nullptr;std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;if ((ret = handleEvictionsLocked(cameraId, clientPid, effectiveApiLevel,IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,/*out*/&partial)) != NO_ERROR) {
    return ret;}if (clientTmp.get() != nullptr) {
    // 处理 API1 MediaRecorder 的特殊情况,其中返回了现有客户端device = static_cast<CLIENT*>(clientTmp.get());return NO_ERROR;}// 如果有必要,让手电筒有机会关闭设备。mFlashlight->prepareDeviceOpen(cameraId);// TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDsint id = cameraIdToInt(cameraId);if (id == -1) {
    ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,cameraId.string());return BAD_VALUE;}int facing = -1;int deviceVersion = getDeviceVersion(id, /*out*/&facing);sp<BasicClient> tmp = nullptr;// 获取 BasicClientif((ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,/*out*/&tmp)) != NO_ERROR) {
    return ret;}client = static_cast<CLIENT*>(tmp.get());LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",__FUNCTION__);// 从 HAL 模块初始化客户端if ((ret = client->initialize(mModule)) != OK) {
    ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);return ret;}// 更新旧版客户端的 shim 参数if (effectiveApiLevel == API_1) {
    // 假设我们一直收到 API1 的 Client 子类sp<Client> shimClient = reinterpret_cast<Client*>(client.get());String8 rawParams = shimClient->getParameters();CameraParameters params(rawParams);auto cameraState = getCameraState(cameraId);if (cameraState != nullptr) {
    cameraState->setShimParams(params);} else {
    ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",__FUNCTION__, cameraId.string());}}if (shimUpdateOnly) {
    // 如果仅更新旧的 shim 参数,请立即断开客户端连接mServiceLock.unlock();client->disconnect();mServiceLock.lock();} else {
    // 否则,将客户端添加到活动客户端列表finishConnectLocked(client, partial);}} // 锁被销毁,允许进一步连接调用// 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 = client;return NO_ERROR;
}

假设走分支 Camera2 API 路由,这会创建 CameraDeviceClient 对象。

frameworks/av/services/camera/libcameraservice/CameraService.cpp

status_t CameraService::makeClient(const sp<CameraService>& cameraService,const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,int halVersion, int deviceVersion, apiLevel effectiveApiLevel,/*out*/sp<BasicClient>* client) {
    // TODO: Update CameraClients + HAL interface to use strings for Camera IDsint id = cameraIdToInt(cameraId);if (id == -1) {
    ALOGE("%s: Invalid camera ID %s, cannot convert to integer.", __FUNCTION__,cameraId.string());return BAD_VALUE;}if (halVersion < 0 || halVersion == deviceVersion) {
    // 默认路径:调用者未指定 HAL 版本,根据 HAL 报告的设备版本创建 CameraClient。switch(deviceVersion) {
    case CAMERA_DEVICE_API_VERSION_1_0:if (effectiveApiLevel == API_1) {
      // Camera1 API routesp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());*client = new CameraClient(cameraService, tmp, packageName, id, facing,clientPid, clientUid, getpid(), legacyMode);} else {
     // Camera2 API routeALOGW("Camera using old HAL version: %d", deviceVersion);return -EOPNOTSUPP;}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:case CAMERA_DEVICE_API_VERSION_3_3:if (effectiveApiLevel == API_1) {
     // Camera1 API 路由sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());*client = new Camera2Client(cameraService, tmp, packageName, id, facing,clientPid, clientUid, servicePid, legacyMode);} else {
     // Camera2 API 路由sp<ICameraDeviceCallbacks> tmp =static_cast<ICameraDeviceCallbacks*>(cameraCb.get());*client = new CameraDeviceClient(cameraService, tmp, packageName, id,facing, clientPid, clientUid, servicePid);}break;default:// Should not be reachableALOGE("Unknown camera device HAL version: %d", deviceVersion);return INVALID_OPERATION;}} else {
    // 调用者要求特定的 HAL 版本。根据请求的 HAL 版本创建 CameraClient。if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
    // 只支持高 HAL 版本设备打开为 HAL1.0 设备。sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());*client = new CameraClient(cameraService, tmp, packageName, id, facing,clientPid, clientUid, servicePid, legacyMode);} else {
    // 目前尚不支持其他组合(例如,以HAL2.x 打开的 HAL3.x)。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;}}return NO_ERROR;
}

CameraDeviceClient 构造函数中创建了 Camera2ClientBase 对象。

frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp

CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,const sp<ICameraDeviceCallbacks>& remoteCallback,const String16& clientPackageName,int cameraId,int cameraFacing,int clientPid,uid_t clientUid,int servicePid) :Camera2ClientBase(cameraService, remoteCallback, clientPackageName,cameraId, cameraFacing, clientPid, clientUid, servicePid),mInputStream(),mRequestIdCounter(0) {
    ATRACE_CALL();ALOGI("CameraDeviceClient %d: Opened", cameraId);
}

Camera2ClientBase 构造器是一个模板函数,TClientBase 会被 CameraDeviceClientBase 替换,会先构造一个 CameraDeviceClientBase 对象。

frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp

template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(const sp<CameraService>& cameraService,const sp<TCamCallbacks>& remoteCallback,const String16& clientPackageName,int cameraId,int cameraFacing,int clientPid,uid_t clientUid,int servicePid):TClientBase(cameraService, remoteCallback, clientPackageName,cameraId, cameraFacing, clientPid, clientUid, servicePid),mSharedCameraCallbacks(remoteCallback),mDeviceVersion(cameraService->getDeviceVersion(cameraId)),mDeviceActive(false)
{
    ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId,String8(clientPackageName).string(), clientPid, clientUid);mInitialClientPid = clientPid;mDevice = CameraDeviceFactory::createDevice(cameraId);LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}

CameraDeviceClientBase 构造器中又构造了一个 BasicClient 对象。

frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp

CameraDeviceClientBase::CameraDeviceClientBase(const sp<CameraService>& cameraService,const sp<ICameraDeviceCallbacks>& remoteCallback,const String16& clientPackageName,int cameraId,int cameraFacing,int clientPid,uid_t clientUid,int servicePid) :BasicClient(cameraService,IInterface::asBinder(remoteCallback),clientPackageName,cameraId,cameraFacing,clientPid,clientUid,servicePid),mRemoteCallback(remoteCallback) {
    
}

BasicClient 定义在 CameraService.cpp 中。

frameworks/av/services/camera/libcameraservice/CameraService.cpp

CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,const sp<IBinder>& remoteCallback,const String16& clientPackageName,int cameraId, int cameraFacing,int clientPid, uid_t clientUid,int servicePid):mClientPackageName(clientPackageName), mDisconnected(false)
{
    mCameraService = cameraService;mRemoteBinder = remoteCallback;mCameraId = cameraId;mCameraFacing = cameraFacing;mClientPid = clientPid;mClientUid = clientUid;mServicePid = servicePid;mOpsActive = false;mDestructionStarted = false;
}

回到 Camera2ClientBase 构造器,CameraDeviceFactory::createDevice(…) 会创建 CameraDevice。

  1. 由 CameraService 弱引用提升为强引用
  2. 根据 HAL 版本去创建不同的 Camera2Device 或 Camera3Device 对象

frameworks/av/services/camera/libcameraservice/CameraDeviceFactory.cpp

sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) {
    sp<CameraService> svc = sService.promote();if (svc == 0) {
    ALOGE("%s: No service registered", __FUNCTION__);return NULL;}int deviceVersion = svc->getDeviceVersion(cameraId, /*facing*/NULL);sp<CameraDeviceBase> device;switch (deviceVersion) {
    case CAMERA_DEVICE_API_VERSION_2_0:case CAMERA_DEVICE_API_VERSION_2_1:device = new Camera2Device(cameraId);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:device = new Camera3Device(cameraId);break;default:ALOGE("%s: Camera %d: Unknown HAL device version %d",__FUNCTION__, cameraId, deviceVersion);device = NULL;break;}ALOGV_IF(device != 0, "Created a new camera device for version %d",deviceVersion);return device;
}

假设工厂方法创建了 Camera3Device。

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

Camera3Device::Camera3Device(int id):mId(id),mIsConstrainedHighSpeedConfiguration(false),mHal3Device(NULL),mStatus(STATUS_UNINITIALIZED),mStatusWaiters(0),mUsePartialResult(false),mNumPartialResults(1),mNextResultFrameNumber(0),mNextReprocessResultFrameNumber(0),mNextShutterFrameNumber(0),mNextReprocessShutterFrameNumber(0),mListener(NULL)
{
    ATRACE_CALL();camera3_callback_ops::notify = &sNotify;camera3_callback_ops::process_capture_result = &sProcessCaptureResult;ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
}

现在来回看从 HAL 模块初始化客户端。这会首先调用 CameraDeviceClient::initialize(…) 方法。

  1. 调用 Camera2ClientBase::initialize(…) 方法进一步初始化
  2. 创建 FrameProcessorBase 对象,并 run 起来,然后注册一些 RangeListener。FrameProcessorBase 类代表输出帧元数据处理线程。这个线程等待来自设备的新帧,并在必要时分析它们。

RangeListener 为一系列 ID [minId,maxId)注册一个监听器。多个监听者可以监听同一范围。使用相同范围的 ID 注册相同的监听器无效。sendPartials 控制是否发送部分结果。

frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp

status_t CameraDeviceClient::initialize(CameraModule *module)
{
    ATRACE_CALL();status_t res;res = Camera2ClientBase::initialize(module);if (res != OK) {
    return res;}String8 threadName;mFrameProcessor = new FrameProcessorBase(mDevice);threadName = String8::format("CDU-%d-FrameProc", mCameraId);mFrameProcessor->run(threadName.string());mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,FRAME_PROCESSOR_LISTENER_MAX_ID,/*listener*/this,/*sendPartials*/true);return OK;
}

Camera2ClientBase 类 initialize(…) 方法最终调用了 Camera3Device initialize(…) 方法。

frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp

template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::initialize(CameraModule *module) {
    ATRACE_CALL();ALOGV("%s: Initializing client for camera %d", __FUNCTION__,TClientBase::mCameraId);status_t res;// 验证操作权限res = TClientBase::startCameraOps();if (res != OK) {
    return res;}if (mDevice == NULL) {
    ALOGE("%s: Camera %d: No device connected",__FUNCTION__, TClientBase::mCameraId);return NO_INIT;}res = mDevice->initialize(module);if (res != OK) {
    ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",__FUNCTION__, TClientBase::mCameraId, strerror(-res), res);return res;}res = mDevice->setNotifyCallback(this);return OK;
}

初始化的时候和 camera HAL 关联了起来。

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

status_t Camera3Device::initialize(CameraModule *module)
{
    ATRACE_CALL();Mutex::Autolock il(mInterfaceLock);Mutex::Autolock l(mLock);ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);if (mStatus != STATUS_UNINITIALIZED) {
    CLOGE("Already initialized!");return INVALID_OPERATION;}/** 打开 HAL device */status_t res;String8 deviceName = String8::format("%d", mId);camera3_device_t *device;ATRACE_BEGIN("camera3->open");res = module->open(deviceName.string(),reinterpret_cast<hw_device_t**>(&device));ATRACE_END();if (res != OK) {
    SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);return res;}/** 交叉检查设备版本 */if (device->common.version < CAMERA_DEVICE_API_VERSION_3_0) {
    SET_ERR_L("Could not open camera: ""Camera device should be at least %x, reports %x instead",CAMERA_DEVICE_API_VERSION_3_0,device->common.version);device->common.close(&device->common);return BAD_VALUE;}camera_info info;res = CameraService::filterGetInfoErrorCode(module->getCameraInfo(mId, &info));if (res != OK) return res;if (info.device_version != device->common.version) {
    SET_ERR_L("HAL reporting mismatched camera_info version (%x)"" and device version (%x).",info.device_version, device->common.version);device->common.close(&device->common);return BAD_VALUE;}/** 使用回调函数初始化设备 */ATRACE_BEGIN("camera3->initialize");res = device->ops->initialize(device, this);ATRACE_END();if (res != OK) {
    SET_ERR_L("Unable to initialize HAL device: %s (%d)",strerror(-res), res);device->common.close(&device->common);return BAD_VALUE;}/** 启动状态跟踪器线程 */mStatusTracker = new StatusTracker(this);res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string());if (res != OK) {
    SET_ERR_L("Unable to start status tracking thread: %s (%d)",strerror(-res), res);device->common.close(&device->common);mStatusTracker.clear();return res;}bool aeLockAvailable = false;camera_metadata_ro_entry aeLockAvailableEntry;res = find_camera_metadata_ro_entry(info.static_camera_characteristics,ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailableEntry);if (res == OK && aeLockAvailableEntry.count > 0) {
    aeLockAvailable = (aeLockAvailableEntry.data.u8[0] ==ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE);}/** 启动请求队列线程 */mRequestThread = new RequestThread(this, mStatusTracker, device, aeLockAvailable);res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());if (res != OK) {
    SET_ERR_L("Unable to start request queue thread: %s (%d)",strerror(-res), res);device->common.close(&device->common);mRequestThread.clear();return res;}mPreparerThread = new PreparerThread();/** Everything is good to go */mDeviceVersion = device->common.version;mDeviceInfo = info.static_camera_characteristics;mHal3Device = device;internalUpdateStatusLocked(STATUS_UNCONFIGURED);mNextStreamId = 0;mDummyStreamId = NO_STREAM;mNeedConfig = true;mPauseStateNotify = false;// HAL是否会发送早期的部分结果元数据?if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
    camera_metadata_entry partialResultsCount =mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);if (partialResultsCount.count > 0) {
    mNumPartialResults = partialResultsCount.data.i32[0];mUsePartialResult = (mNumPartialResults > 1);}} else {
    camera_metadata_entry partialResultsQuirk =mDeviceInfo.find(ANDROID_QUIRKS_USE_PARTIAL_RESULT);if (partialResultsQuirk.count > 0 && partialResultsQuirk.data.u8[0] == 1) {
    mUsePartialResult = true;}}camera_metadata_entry configs =mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);for (uint32_t i = 0; i < configs.count; i += 4) {
    if (configs.data.i32[i] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&configs.data.i32[i + 3] ==ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
    mSupportedOpaqueInputSizes.add(Size(configs.data.i32[i + 1],configs.data.i32[i + 2]));}}return OK;
}

CameraModule::open(…) 方法内部调用了 camera_module 结构体 common 成员,这是一个 hw_module_t 结构体,其内部定义了 hw_module_methods_t 结构体,hw_module_methods_t 结构体内部又定义了 open 函数指针。这部分需要遵守 HAL 层定义。

frameworks/av/services/camera/libcameraservice/common/CameraModule.cpp

int CameraModule::open(const char* id, struct hw_device_t** device) {
    int res;ATRACE_BEGIN("camera_module->open");res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));ATRACE_END();return res;
}

我们以 moto Nexus 6 HAL device/moto/shamu/camera/QCamera2/ 为例进行分析。QCamera2Hal.cpp 中给 hw_module_t 结构体 camera_common 进行了赋值,methods 中定义了 open(…) 方法。

device/moto/shamu/camera/QCamera2/QCamera2Hal.cpp

#include "QCamera2Factory.h"
#include "HAL3/QCamera3VendorTags.h"static hw_module_t camera_common = {
    tag: HARDWARE_MODULE_TAG,module_api_version: CAMERA_MODULE_API_VERSION_2_4,hal_api_version: HARDWARE_HAL_API_VERSION,id: CAMERA_HARDWARE_MODULE_ID,name: "QCamera Module",author: "Qualcomm Innovation Center Inc",methods: &qcamera::QCamera2Factory::mModuleMethods,dso: NULL,reserved:  {
    0},
};

open 函数指针实际指向 QCamera2Factory::camera_device_open(…) 函数。

device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp

struct hw_module_methods_t QCamera2Factory::mModuleMethods = {
    open: QCamera2Factory::camera_device_open,
};

QCamera2Factory::camera_device_open(…) 方法内部做了入参检查,然后调用 QCamera2Factory::cameraDeviceOpen(…) 方法。gQCamera2Factory 是在 QCamera2Factory::get_number_of_cameras() 方法中构造的。

device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp

int QCamera2Factory::camera_device_open(const struct hw_module_t *module, const char *id,struct hw_device_t **hw_device)
{
    if (module != &HAL_MODULE_INFO_SYM.common) {
    ALOGE("Invalid module. Trying to open %p, expect %p",module, &HAL_MODULE_INFO_SYM.common);return INVALID_OPERATION;}if (!id) {
    ALOGE("Invalid camera id");return BAD_VALUE;}return gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device);
}

假设我们走 HAL3 分支,这里会创建 QCamera3HardwareInterface 对象,接着调用其 openCamera(…) 方法。

device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp

int QCamera2Factory::cameraDeviceOpen(int camera_id,struct hw_device_t **hw_device)
{
    int rc = NO_ERROR;if (camera_id < 0 || camera_id >= mNumOfCameras)return -ENODEV;if ( NULL == mHalDescriptors ) {
    ALOGE("%s : Hal descriptor table is not initialized!", __func__);return NO_INIT;}if ( mHalDescriptors[camera_id].device_version == CAMERA_DEVICE_API_VERSION_3_0 ) {
    QCamera3HardwareInterface *hw = new QCamera3HardwareInterface(mHalDescriptors[camera_id].cameraId,mCallbacks);if (!hw) {
    ALOGE("Allocation of hardware interface failed");return NO_MEMORY;}rc = hw->openCamera(hw_device);if (rc != 0) {
    delete hw;}} else if (mHalDescriptors[camera_id].device_version == CAMERA_DEVICE_API_VERSION_1_0) {
    ......} else {
    ALOGE("%s: Device version for camera id %d invalid %d",__func__,camera_id,mHalDescriptors[camera_id].device_version);return BAD_VALUE;}return rc;
}

QCamera3HardwareInterface 构造函数如下:

device/moto/shamu/camera/QCamera2/HAL3/QCamera3HWI.cpp

QCamera3HardwareInterface::QCamera3HardwareInterface(int cameraId,const camera_module_callbacks_t *callbacks): mCameraId(cameraId),mCameraHandle(NULL),mCameraOpened(false),mCameraInitialized(false),mCallbackOps(NULL),mMetadataChannel(NULL),mPictureChannel(NULL),mRawChannel(NULL),mSupportChannel(NULL),mRawDumpChannel(NULL),mFirstRequest(false),mFlush(false),mParamHeap(NULL),mParameters(NULL),m_bIsVideo(false),m_bIs4KVideo(false),mEisEnable(0),mLoopBackResult(NULL),mMinProcessedFrameDuration(0),mMinJpegFrameDuration(0),mMinRawFrameDuration(0),m_pPowerModule(NULL),mMetaFrameCount(0),mCallbacks(callbacks),mCaptureIntent(0)
{
    getLogLevel();mCameraDevice.common.tag = HARDWARE_DEVICE_TAG;mCameraDevice.common.version = CAMERA_DEVICE_API_VERSION_3_3;mCameraDevice.common.close = close_camera_device;mCameraDevice.ops = &mCameraOps;mCameraDevice.priv = this;gCamCapability[cameraId]->version = CAM_HAL_V3;// TODO: hardcode for now until mctl add support for min_num_pp_bufs//TBD - To see if this hardcoding is needed. Check by printing if this is filled by mctl to 3gCamCapability[cameraId]->min_num_pp_bufs = 3;pthread_cond_init(&mRequestCond, NULL);mPendingRequest = 0;mCurrentRequestId = -1;pthread_mutex_init(&mMutex, NULL);for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++)mDefaultMetadata[i] = NULL;#ifdef HAS_MULTIMEDIA_HINTSif (hw_get_module(POWER_HARDWARE_MODULE_ID, (const hw_module_t **)&m_pPowerModule)) {
    ALOGE("%s: %s module not found", __func__, POWER_HARDWARE_MODULE_ID);}
#endifchar prop[PROPERTY_VALUE_MAX];property_get("persist.camera.raw.dump", prop, "0");mEnableRawDump = atoi(prop);if (mEnableRawDump)CDBG("%s: Raw dump from Camera HAL enabled", __func__);
}

QCamera3HardwareInterface::openCamera(…) 在内部调用了无入参的重载方法,实际工作是由 camera_open(…) 函数完成的。mm_camera_vtbl_t 是包含相机句柄和操作表的虚拟表。

device/moto/shamu/camera/QCamera2/HAL3/QCamera3HWI.cpp

int QCamera3HardwareInterface::openCamera(struct hw_device_t **hw_device)
{
    int rc = 0;if (mCameraOpened) {
    *hw_device = NULL;return PERMISSION_DENIED;}rc = openCamera();if (rc == 0) {
    *hw_device = &mCameraDevice.common;} else*hw_device = NULL;#ifdef HAS_MULTIMEDIA_HINTSif (rc == 0) {
    if (m_pPowerModule) {
    if (m_pPowerModule->powerHint) {
    m_pPowerModule->powerHint(m_pPowerModule, POWER_HINT_VIDEO_ENCODE,(void *)"state=1");}}}
#endifreturn rc;
}int QCamera3HardwareInterface::openCamera()
{
    int rc = 0;ATRACE_CALL();if (mCameraHandle) {
    ALOGE("Failure: Camera already opened");return ALREADY_EXISTS;}rc = QCameraFlash::getInstance().reserveFlashForCamera(mCameraId);if (rc < 0) {
    ALOGE("%s: Failed to reserve flash for camera id: %d",__func__,mCameraId);return UNKNOWN_ERROR;}mCameraHandle = camera_open(mCameraId);if (!mCameraHandle) {
    ALOGE("camera_open failed.");return UNKNOWN_ERROR;}mCameraOpened = true;rc = mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle,camEvtHandle, (void *)this);if (rc < 0) {
    ALOGE("%s: Error, failed to register event callback", __func__);/* Not closing camera here since it is already handled in destructor */return FAILED_TRANSACTION;}return NO_ERROR;
}

camera device 打开是由 mm_camera_open(…) 函数完成的。

device/moto/shamu/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c

mm_camera_vtbl_t * camera_open(uint8_t camera_idx)
{
    int32_t rc = 0;mm_camera_obj_t* cam_obj = NULL;CDBG("%s: E camera_idx = %d\n", __func__, camera_idx);if (camera_idx >= g_cam_ctrl.num_cam) {
    CDBG_ERROR("%s: Invalid camera_idx (%d)", __func__, camera_idx);return NULL;}pthread_mutex_lock(&g_intf_lock);/* opened already */if(NULL != g_cam_ctrl.cam_obj[camera_idx]) {
    /* Add reference */g_cam_ctrl.cam_obj[camera_idx]->ref_count++;pthread_mutex_unlock(&g_intf_lock);CDBG("%s: opened alreadyn", __func__);return &g_cam_ctrl.cam_obj[camera_idx]->vtbl;}cam_obj = (mm_camera_obj_t *)malloc(sizeof(mm_camera_obj_t));if(NULL == cam_obj) {
    pthread_mutex_unlock(&g_intf_lock);CDBG("%s: no mem", __func__);return NULL;}/* initialize camera obj */memset(cam_obj, 0, sizeof(mm_camera_obj_t));cam_obj->ctrl_fd = -1;cam_obj->ds_fd = -1;cam_obj->ref_count++;cam_obj->my_hdl = mm_camera_util_generate_handler(camera_idx);cam_obj->vtbl.camera_handle = cam_obj->my_hdl; /* set handler */cam_obj->vtbl.ops = &mm_camera_ops;pthread_mutex_init(&cam_obj->cam_lock, NULL);rc = mm_camera_open(cam_obj);if(rc != 0) {
    CDBG_ERROR("%s: mm_camera_open err = %d", __func__, rc);pthread_mutex_destroy(&cam_obj->cam_lock);g_cam_ctrl.cam_obj[camera_idx] = NULL;free(cam_obj);cam_obj = NULL;pthread_mutex_unlock(&g_intf_lock);return NULL;}else{
    CDBG("%s: Open succeded\n", __func__);g_cam_ctrl.cam_obj[camera_idx] = cam_obj;pthread_mutex_unlock(&g_intf_lock);return &cam_obj->vtbl;}
}

到这里才真正的打开了设备节点,到此为止,如果继续深入分析,则要进入驱动程序。

device/moto/shamu/camera/QCamera2/stack/mm-camera-interface/src/mm_camera.c

int32_t mm_camera_open(mm_camera_obj_t *my_obj)
{
    char dev_name[MM_CAMERA_DEV_NAME_LEN];int32_t rc = 0;int8_t n_try=MM_CAMERA_DEV_OPEN_TRIES;uint8_t sleep_msec=MM_CAMERA_DEV_OPEN_RETRY_SLEEP;unsigned int cam_idx = 0;CDBG("%s: begin\n", __func__);if (NULL == my_obj) {
    goto on_error;}snprintf(dev_name, sizeof(dev_name), "/dev/%s",mm_camera_util_get_dev_name(my_obj->my_hdl));sscanf(dev_name, "/dev/video%u", &cam_idx);CDBG_HIGH("%s: dev name = %s, cam_idx = %d", __func__, dev_name, cam_idx);do{
    n_try--;errno = 0;// 这里真正打开相机设备节点my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);CDBG("%s: ctrl_fd = %d, errno == %d", __func__, my_obj->ctrl_fd, errno);if((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0 )) {
    CDBG_HIGH("%s: opened, break out while loop", __func__);break;}ALOGE("%s:Failed with %s error, retrying after %d milli-seconds",__func__, strerror(errno), sleep_msec);usleep(sleep_msec * 1000);}while (n_try > 0);if (my_obj->ctrl_fd < 0) {
    CDBG_ERROR("%s: cannot open control fd of '%s' (%s)\n",__func__, dev_name, strerror(errno));rc = -1;goto on_error;}/* 打开 domain socket*/n_try = MM_CAMERA_DEV_OPEN_TRIES;do {
    n_try--;my_obj->ds_fd = mm_camera_socket_create(cam_idx, MM_CAMERA_SOCK_TYPE_UDP);CDBG("%s: ds_fd = %d, errno = %d", __func__, my_obj->ds_fd, errno);if((my_obj->ds_fd >= 0) || (n_try <= 0 )) {
    CDBG("%s: opened, break out while loop", __func__);break;}CDBG("%s:failed with I/O error retrying after %d milli-seconds",__func__, sleep_msec);usleep(sleep_msec * 1000);} while (n_try > 0);if (my_obj->ds_fd < 0) {
    CDBG_ERROR("%s: cannot open domain socket fd of '%s'(%s)\n",__func__, dev_name, strerror(errno));rc = -1;goto on_error;}pthread_mutex_init(&my_obj->msg_lock, NULL);pthread_mutex_init(&my_obj->cb_lock, NULL);pthread_mutex_init(&my_obj->evt_lock, NULL);pthread_cond_init(&my_obj->evt_cond, NULL);CDBG("%s : Launch evt Thread in Cam Open",__func__);mm_camera_cmd_thread_launch(&my_obj->evt_thread,mm_camera_dispatch_app_event,(void *)my_obj);/* 启动事件轮询线程* 我们将在用户首次注册 evt 时将 evt fd 添加到事件轮询线程中*/CDBG("%s : Launch evt Poll Thread in Cam Open", __func__);mm_camera_poll_thread_launch(&my_obj->evt_poll_thread,MM_CAMERA_POLL_TYPE_EVT);mm_camera_evt_sub(my_obj, TRUE);CDBG("%s: end (rc = %d)\n", __func__, rc);/* 我们不需要在返回之前在这里解锁cam_lock,* 因为对于打开,它是在intf_lock中完成的 */return rc;on_error:if (NULL == my_obj) {
    CDBG_ERROR("%s: Invalid camera object\n", __func__);rc = -1;} else {
    if (my_obj->ctrl_fd >= 0) {
    close(my_obj->ctrl_fd);my_obj->ctrl_fd = -1;}if (my_obj->ds_fd >= 0) {
    mm_camera_socket_close(my_obj->ds_fd);my_obj->ds_fd = -1;}}/* 我们不需要在返回之前在这里解锁cam_lock,* 因为对于打开,它是在intf_lock中完成的 */return rc;
}
  相关解决方案