关于android:Camera2HAL3-框架分析

3次阅读

共计 30639 个字符,预计需要花费 77 分钟才能阅读完成。

和你一起一生学习,这里是程序员 Android

本篇文章次要介绍 Android 开发中的局部知识点,通过浏览本篇文章,您将播种以下内容:

一、Android O 上的 Treble 机制
二、Camera HAL3 的框架更新
三、外围概念:Request

一、Android O 上的 Treble 机制

在 Android O 中,系统启动时,会启动一个 CameraProvider 服务,它是从 cameraserver 过程中分离出来,作为一个独立过程 android.hardware.camera.provider@2.4-service 用来管制 camera HAL,cameraserver 通过 HIDL 机制于 camera provider 进行通信。HIDL 源自于 Android O 版本退出的 Treble 机制,它的次要性能是将 service 与 HAL 隔离,以不便 HAL 局部进行独立降级,相似于 APP 与 Framework 之间的 Binder 通信机制,通过引入一个过程间通信机制而针对不同层级进行解耦(从 Local call 变成了 Remote call)。如下图:

 cameraserver 与 provider 这两个过程启动、初始化的调用逻辑,如下图:

二、Camera HAL3 的框架更新

  • Application framework:

用于给 APP 提供拜访 hardware 的 Camera API2,通过 binder 来拜访 camera service。

  • AIDL:

基于 Binder 实现的一个用于让 App fw 代码拜访 natice fw 代码的接口。其实现存在于下述门路:frameworks/av/camera/aidl/android/hardware。其中:

    (1) ICameraService
是相机服务的接口。用于申请连贯、增加监听等。
    (2) ICameraDeviceUser
是已关上的特定相机设施的接口。利用框架可通过它拜访具体设施。
    (3) ICameraServiceListener 和 ICameraDeviceCallbacks
别离是从 CameraService 和 CameraDevice 到利用框架的回调。

  • Natice framework

frameworks/av/。提供了 ICameraService、ICameraDeviceUser、ICameraDeviceCallbacks、ICameraServiceListener 等 aidl 接口的实现。以及 camera server 的 main 函数。

  • Binder IPC interface

提供过程间通信的接口,APP 和 CameraService 的通信、CameraService 和 HAL 的通信。其中,AIDL、HIDL 都是基于 Binder 实现的。

  • Camera Service

frameworks/av/services/camera/。同 APP、HAL 交互的服务,起到了承前启后的作用。

  • HAL:

Google 的 HAL 定义了能够让 Camera Service 拜访的标准接口。对于供应商而言,必须要实现这些接口。

2.1 Camera HAL3 构建连路的过程

如下图(红色虚线是上行路线,彩色虚线则是上行路线):

2.2 从 App 到 CameraService 的调用流程

从 Application 连贯到 CameraService,这波及到 Android 架构中的三个档次:App 层,Framework 层,Runtime 层。其中,App 层间接调用 Framework 层所封装的办法,而 Framework 层须要通过 Binder 近程调用 Runtime 中 CameraService 的函数。
这一部分次要的函数调用逻辑如下图所示:

  在 App 中,须要调用关上相机的 API 如下:

  • CameraCharacteristics:

形容摄像头的各种个性,咱们能够通过 CameraManager 的 getCameraCharacteristics(@NonNull String cameraId)办法来获取。

  • CameraDevice:

形容零碎摄像头,相似于晚期的 Camera。

  • CameraCaptureSession:

Session 类,当须要拍照、预览等性能时,须要先创立该类的实例,而后通过该实例里的办法进行管制(例如:拍照 capture())。

  • CaptureRequest:

形容了一次操作申请,拍照、预览等操作都须要先传入 CaptureRequest 参数,具体的参数管制也是通过 CameraRequest 的成员变量来设置。

  • CaptureResult:

形容拍照实现后的后果。

例如关上 camera 的 java 代码:

mCameraManager.openCamera(currentCameraId, stateCallback, backgroundHandler);

Camera2 拍照流程如下所示:

### 2.2.1 Framework CameraManager
/frameworks/base/core/java/android/hardware/camera2/CameraManager.java

最后的入口就是 CameraManager 的 openCamera 办法,但通过代码能够看到,它仅仅是调用了 openCameraForUid 办法。

@RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String cameraId,
        @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler) throws CameraAccessException {openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
}

上面的代码 疏忽掉了一些参数查看相干操作,最终次要调用了 openCameraDeviceUserAsync 办法。

public void openCameraForUid(@NonNull String cameraId,
        @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler, int clientUid) throws CameraAccessException {/* Do something in*/ ...... /* Do something out*/ openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
}

参考如下正文剖析:

private CameraDevice openCameraDeviceUserAsync(String cameraId,
        CameraDevice.StateCallback callback, Handler handler, final int uid) throws CameraAccessException {CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
    CameraDevice device = null; synchronized (mLock) {

        ICameraDeviceUser cameraUser = null;

        android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =   // 实例化一个 CameraDeviceImpl。结构时传入了 CameraDevice.StateCallback 以及 Handler。new android.hardware.camera2.impl.CameraDeviceImpl(  
                    cameraId,
                    callback,
                    handler,
                    characteristics,
                    mContext.getApplicationInfo().targetSdkVersion);

        ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); // 获取 CameraDeviceCallback 实例,这是提供给远端连贯到 CameraDeviceImpl 的接口。try {if (supportsCamera2ApiLocked(cameraId)) {  //HAL3 中走的是这一部分逻辑,次要是从 CameraManagerGlobal 中获取 CameraService 的本地接口,通过它远端调用(采纳 Binder 机制)connectDevice 办法连贯到相机设施。// 留神返回的 cameraUser 实际上指向的是远端 CameraDeviceClient 的本地接口。// 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, cameraId,
                        mContext.getOpPackageName(), uid);
            } else { // Use legacy camera implementation for HAL1 devices
                int id; try {id = Integer.parseInt(cameraId);
                } catch (NumberFormatException e) { throw new IllegalArgumentException("Expected cameraId to be numeric, but it was:"
                            + cameraId);
                }

                Log.i(TAG, "Using legacy camera HAL.");
                cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
            }
        } catch (ServiceSpecificException e) {/* Do something in */ ...... /* Do something out */} // TODO: factor out callback to be non-nested, then move setter to constructor // For now, calling setRemoteDevice will fire initial // onOpened/onUnconfigured callbacks. // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if // cameraUser dies during setup.
        deviceImpl.setRemoteDevice(cameraUser); // 将 CameraDeviceClient 设置到 CameraDeviceImpl 中进行治理。device = deviceImpl;
    } return device;
}

### 2.2.2 CameraDeviceImpl /frameworks/base/core/java/android/hardware/camera2/Impl/CameraDeviceImpl.java
在持续向下剖析关上相机流程之前,先简略看看调用到的 CameraDeviceImpl 中的setRemoteDevice 办法,次要是将获取到的远端设施保存起来:

/** * Set remote device, which triggers initial onOpened/onUnconfigured callbacks
 *
 * <p>This function may post onDisconnected and throw CAMERA_DISCONNECTED if remoteDevice dies
 * during setup.</p>
 * */
public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {synchronized(mInterfaceLock) { // TODO: Move from decorator to direct binder-mediated exceptions // If setRemoteFailure already called, do nothing
        if (mInError) return;

        mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice); // 通过 ICameraDeviceUserWrapper 给远端设施实例加上一层封装。IBinder remoteDeviceBinder = remoteDevice.asBinder(); // 应用 Binder 机制的一些根本设置。// For legacy camera device, remoteDevice is in the same process, and // asBinder returns NULL.
        if (remoteDeviceBinder != null) { try {remoteDeviceBinder.linkToDeath(this, /*flag*/ 0); // 如果这个 binder 隐没,为标记信息注册一个接收器。} catch (RemoteException e) {CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected); throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, "The camera device has encountered a serious error");
            }
        }

        mDeviceHandler.post(mCallOnOpened); // 需此处触发 onOpened 与 onUnconfigured 这两个回调,每个回调都是通过 mDeviceHandler 启用一个新线程来调用的。mDeviceHandler.post(mCallOnUnconfigured);
    }
}

2.2.3 Runtime

通过 Binder 机制,咱们远端调用了 connectDevice 办法(在 C++ 中称为函数,但说成办法可能更顺口一些),这个办法实现在 CameraService 类中。

2.2.4 CameraService

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

Status CameraService::connectDevice(const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId, const String16& clientPackageName, int clientUid, /*out*/ sp<hardware::camera2::ICameraDeviceUser>* device) {ATRACE_CALL();
    Status ret = Status::ok();
    String8 id = String8(cameraId);
    sp<CameraDeviceClient> client = nullptr; // 此处调用的 connectHelper 办法才真正实现了连贯逻辑(HAL1 时最终也调用到这个办法)。须要留神的是,设定的模板类型是 ICameraDeviceCallbacks 以及 CameraDeviceClient。ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
            clientUid, USE_CALLING_PID, API_2, /*legacyMode*/ false, /*shimUpdateOnly*/ false, /*out*/client); if(!ret.isOk()) {logRejected(id, getCallingPid(), String8(clientPackageName),
                ret.toString8()); return ret;
    } *device = client; //client 指向的类型是 CameraDeviceClient,其实例则是最终的返回后果。return ret;
}

connectHelper 内容较多,疏忽掉咱们还无需关注的中央剖析:

template<class CALLBACK, class CLIENT> Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId, int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
        apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly, /*out*/sp<CLIENT>& device) {binder::Status ret = binder::Status::ok();

    String8 clientName8(clientPackageName); /* Do something in */ ...... /* Do something out */ sp<BasicClient> tmp = nullptr; // 调用 makeClient 生成 CameraDeviceClient 实例。if(!(ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,
                clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel, /*out*/&tmp)).isOk()) {return ret;} // 初始化 CLIENT 实例。留神此处的模板类型 CLIENT 即是 CameraDeviceClient,传入的参数 mCameraProviderManager 则是与 HAL service 无关。client = static_cast<CLIENT*>(tmp.get());

        LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
                __FUNCTION__);

        err = client->initialize(mCameraProviderManager); /* Do something in */ ...... /* Do something out */

    // 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 ret;
} 

makeClient 次要是依据 API 版本以及 HAL 版本来抉择生成具体的 Client 实例,Client 就沿着后面剖析下来的门路返回到 CameraDeviceImpl 实例中,被保留到 mRemoteDevice。

Status 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) {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: /* Do something in */ ...... /* Do something out */
          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<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get()); *client = new Camera2Client(cameraService, tmp, packageName, cameraIdToInt(cameraId),
                        facing, clientPid, clientUid, servicePid, legacyMode);
            } else { // Camera2 API route : 实例化了 CameraDeviceClient 类作为 Client(留神此处结构传入了 ICameraDeviceCallbacks,这是连贯到 CameraDeviceImpl 的远端回调)sp<hardware::camera2::ICameraDeviceCallbacks> tmp = static_cast<hardware::camera2::ICameraDeviceCallbacks*>(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 \"%s\"has unknown HAL version %d",
                    cameraId.string(), deviceVersion);
        }
    } else {/* Do something in */ ...... /* Do something out */} return Status::ok();}

至此,关上相机流程中,从 App 到 CameraService 的调用逻辑基本上就算走完了。

简图总结:

Ps:

  • CameraManagerGlobal 是真正的实现层,它与 JAVA 层的 CameraService 创立连贯,从而创立相机的连路。
  • CameraDeviceImpl 相当于运行上下文,它取代了 Android N 之前的 JNI 层。

2.3 从 CameraService 到 HAL Service

因为 Android O 中退出了 Treble 机制,CameraServer 一端主体为 CameraService,它将会寻找现存的 Provider service,将其退出到外部的 CameraProviderManager 中进行治理,相干操作都是通过远端调用进行的。
而 Provider service 一端的主体为 CameraProvider,它在初始化时就曾经连贯到 libhardware 的 Camera HAL 实现层,并以 CameraModule 来进行治理。
过程的启动后,连路的“载体”就搭建实现了(须要留神,此时 QCamera3HWI 还未创立),可用下图简略示意:

而在关上相机时,该层的残缺连路会被创立进去,次要调用逻辑如下图:

上回讲到,在 CameraService::makeClient 中,实例化了一个 CameraDeviceClient。当初咱们就从它的构造函数开始,持续摸索关上相机的流程。
这一部分次要流动在 Runtime 层,这里分成 CameraService 与 HAL Service 两侧来剖析。

2.3.1 CameraDeviceClient

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

CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService, const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback, const String16& clientPackageName, const String8& cameraId, int cameraFacing, int clientPid,
        uid_t clientUid, int servicePid) :
    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
                cameraId, cameraFacing, clientPid, clientUid, servicePid),  // 继承它的父类 Camera2ClientBase 
    mInputStream(),
    mStreamingRequestId(REQUEST_ID_NONE),
    mRequestIdCounter(0),
    mPrivilegedClient(false) {char value[PROPERTY_VALUE_MAX];
    property_get("persist.camera.privapp.list", value, "");
    String16 packagelist(value); if (packagelist.contains(clientPackageName.string())) {mPrivilegedClient = true;}

    ATRACE_CALL();
    ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
}

CameraService 在创立 CameraDeviceClient 之后,会调用它的初始化函数:

// 对外提供调用的初始化函数接口 initialize。status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager) {return initializeImpl(manager);
} // 初始化的具体实现函数,模板 TProviderPtr 在此处即是 CameraProviderManager 类。template<typename TProviderPtr>
// 首先将父类初始化,留神此处传入了 CameraProviderManager。status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr) {ATRACE_CALL();
    status_t res;

    res = Camera2ClientBase::initialize(providerPtr); if (res != OK) {return res;} // 这里是对于 FrameProcessor 的创立与初始化配置等等
 String8 threadName;
    mFrameProcessor = new FrameProcessorBase(mDevice);
    threadName = String8::format("CDU-%s-FrameProc", mCameraIdStr.string());
    mFrameProcessor->run(threadName.string());

    mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
                                      FRAME_PROCESSOR_LISTENER_MAX_ID, /*listener*/this, /*sendPartials*/true); return OK;
}

2.3.2 Camera2ClientBase

frameworks\av\services\camera\libcameraservice\common\Camera2ClientBase.cpp**

template <typename TClientBase> // 模板 TClientBase,在 CameraDeviceClient 继承 Camera2ClientBase 时被指定为 CameraDeviceClientBase。Camera2ClientBase<TClientBase>::Camera2ClientBase( // 结构的相干参数,以及初始化列表,这外面须要留神 TCamCallbacks 在 CameraDeviceClientBase 中被指定为了 ICameraDeviceCallbacks。const sp<CameraService>& cameraService, const sp<TCamCallbacks>& remoteCallback, const String16& clientPackageName, const String8& cameraId, int cameraFacing, int clientPid,
        uid_t clientUid, int servicePid):
        TClientBase(cameraService, remoteCallback, clientPackageName,
                cameraId, cameraFacing, clientPid, clientUid, servicePid),
        mSharedCameraCallbacks(remoteCallback),
        mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
        mDeviceActive(false)
{ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
            String8(clientPackageName).string(), clientPid, clientUid);

    mInitialClientPid = clientPid;
    mDevice = new Camera3Device(cameraId); // 创立了一个 Camera3Device。LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}

回去再看看初始化函数:

template <typename TClientBase> // 初始化函数接口,真正的实现局部在 initializeImpl 中。status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager) {return initializeImpl(manager);
} //TClientBase 对应 CameraDeviceClientBase,而 TProviderPtr 对应的是 CameraProviderManager。template <typename TClientBase> template <typename TProviderPtr> status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr) {ATRACE_CALL();
    ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
          TClientBase::mCameraIdStr.string());
    status_t res; // Verify ops permissions
    res = TClientBase::startCameraOps(); // 调用 CameraDeviceClientBase 的 startCameraOps 办法,查看 ops 的权限。if (res != OK) {return res;} if (mDevice == NULL) {
        ALOGE("%s: Camera %s: No device connected",
                __FUNCTION__, TClientBase::mCameraIdStr.string()); return NO_INIT;
    }

    res = mDevice->initialize(providerPtr); // 初始化 Camera3Device 的实例,留神此处传入了 CameraProviderManager。if (res != OK) {ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
                __FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res); return res;
    } // 在 Camera3Device 实例中设置 Notify 回调。wp<CameraDeviceBase::NotificationListener> weakThis(this);
    res = mDevice->setNotifyCallback(weakThis); return OK;
}

2.3.3 Camera3Device

frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp**

Camera3Device::Camera3Device(const String8 &id):
        mId(id),
        mOperatingMode(NO_MODE),
        mIsConstrainedHighSpeedConfiguration(false),
        mStatus(STATUS_UNINITIALIZED),
        mStatusWaiters(0),
        mUsePartialResult(false),
        mNumPartialResults(1),
        mTimestampOffset(0),
        mNextResultFrameNumber(0),
        mNextReprocessResultFrameNumber(0),
        mNextShutterFrameNumber(0),
        mNextReprocessShutterFrameNumber(0),
        mListener(NULL),
        mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID)
{ATRACE_CALL();
  // 在这个察看构造函数中设定了两个回调接口:camera3_callback_ops::notify = &sNotify;
    camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
    ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
}

其初始化函数篇幅较长,这里省略掉了对于 RequestMetadataQueue 的相干操作。

status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {ATRACE_CALL();
    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);

    ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string()); if (mStatus != STATUS_UNINITIALIZED) {CLOGE("Already initialized!"); return INVALID_OPERATION;
    } if (manager == nullptr) return INVALID_OPERATION;

    sp<ICameraDeviceSession> session;
    ATRACE_BEGIN("CameraHal::openSession");
    status_t res = manager->openSession(mId.string(), this, // 调用 CameraProviderManager 的 openSession 办法,开启了远端的 **Session**
            /*out*/ &session);
    ATRACE_END(); if (res != OK) {SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res); return res;
    } /* Do something in */ ...... /* Do something out */

    return initializeCommonLocked();}

2.3.4 CameraProviderManager

frameworks\av\services\camera\libcameraservice\common\CameraProviderManager.cpp

status_t CameraProviderManager::openSession(const std::string &id, const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback, /*out*/ sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session) {std::lock_guard<std::mutex> lock(mInterfaceMutex);

    auto deviceInfo = findDeviceInfoLocked(id, // 首先调用 findDeviceInfoLocked,获取 HAL3 相干的 DeviceInfo3
            /*minVersion*/ {3,0}, /*maxVersion*/ {4,0}); if (deviceInfo == nullptr) return NAME_NOT_FOUND;

    auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);

    Status status;
    hardware::Return<void> ret; // 通过远端调用 CameraDevice 的 open 办法,创立 CameraDeviceSession 实例并将其本地调用接口通过入参 session 返回。ret = deviceInfo3->mInterface->open(callback, [&status, &session]
            (Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {status = s; if (status == Status::OK) {*session = cameraSession;}
            }); if (!ret.isOk()) {
        ALOGE("%s: Transaction error opening a session for camera device %s: %s",
                __FUNCTION__, id.c_str(), ret.description().c_str()); return DEAD_OBJECT;
    } return mapToStatusT(status);
}

### 2.3.5 CameraDevice

hardware\interfaces\camera\device\3.2\default\CameraDevice.cpp

CameraDevice 的实例实际上在初始化 HAL Service 之后就存在了。后面说到,通过 CameraProviderManager 中的 deviceInfo 接口,调用 远端 CameraDevice 实例 的 open 办法,上面就来看看它的代码实现:

Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb)  {Status status = initStatus();
    sp<CameraDeviceSession> session = nullptr; if (callback == nullptr) {
        ALOGE("%s: cannot open camera %s. callback is null!",
                __FUNCTION__, mCameraId.c_str());
        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); return Void();} if (status != Status::OK) {/* Do something in */ ...... /* Do something out */} else {mLock.lock(); /* Do something in */ ...... /* Do something out */

        /** Open HAL device */ status_t res;
        camera3_device_t *device;

        ATRACE_BEGIN("camera3->open");
        res = mModule->open(mCameraId.c_str(), // 留神 mModule 是在 HAL Service 初始化时就曾经配置好的,它对从 libhardware 库中加载的 Camera HAL 接口进行了一层封装,从这里往下就会一路走到 QCamera3HWI 的结构流程去。reinterpret_cast<hw_device_t**>(&device));
        ATRACE_END(); /* Do something in */ ...... /* Do something out */

     // 创立 session 并让外部成员 mSession 持有,具体实现的函数为 creatSession。session = createSession(device, info.static_camera_characteristics, callback); /* Do something in */ ...... /* Do something out */ mSession = session;

        IF_ALOGV() {session->getInterface()->interfaceChain([](::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {ALOGV("Session interface chain:"); for (auto iface : interfaceChain) {ALOGV("%s", iface.c_str());
                    }
                });
        }
        mLock.unlock();}
    _hidl_cb(status, session->getInterface()); return Void();}

而 createSession 中间接创立了一个 CameraDeviceSession。当然在其构造函数中会调用外部的初始化函数,而后会进入 HAL 接口层 QCamera3HWI 的初始化流程,至此,从 CameraService 到 HAL Service 这一部分的关上相机流程就根本走通了。
简图总结:

2.4 从  HAL Service 到 Camera  HAL

在 HAL3 中,Camera HAL 的接口转化层(以及流解析层)由 QCamera3HardwareInterface 担当,而接口层与实现层与 HAL1 中根本没什么差异,都是在 mm_camera_interface.c 与 mm_camera.c 中。
那么接口转化层的实例是何时创立的,又是怎么初始化的,创立它的时候,与接口层、实现层又有什么交互?通过下图展现的次要调用流程:

2.4.1 CameraModule(HAL Service)

 hardware\interfaces\camera\common\1.0\default\CameraModule.cpp

上回说到,CameraDevice::open 的实现中,调用了 mModule->open,即 CameraModule::open,通过代码来看,它做的事并不多,次要是调用 mModule->common.methods->open,来进入下一层级的流程。
而这里则须要留神了,open 是一个函数指针,它指向的是 QCamera2Factory 的 camera_device_open 办法,至于为什么和 QCamera2Factory 无关,这就要回头看 HAL Service 的启动初始化流程了。

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;}

2.4.2 QCamera2Factory(Camera HAL)

/*===========================================================================
 * FUNCTION   : camera_device_open
 *
 * DESCRIPTION: static function to open a camera device by its ID
 *
 * PARAMETERS :
 *   @camera_id : camera ID
 *   @hw_device : ptr to struct storing camera hardware device info
 *
 * RETURN     : int32_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
int QCamera2Factory::camera_device_open( const struct hw_module_t *module, const char *id,
    struct hw_device_t **hw_device)
{ /* Do something in */ ...... /* Do something out */ #ifdef QCAMERA_HAL1_SUPPORT // 留神到这里通过宏定义增加了对 HAL1 的兼容操作。实际上是要调用 cameraDeviceOpen 来进行下一步操作。if(gQCameraMuxer)
        rc =  gQCameraMuxer->camera_device_open(module, id, hw_device); else #endif
        rc = gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device); return rc;
}

struct hw_module_methods_t QCamera2Factory::mModuleMethods = {.open = QCamera2Factory::camera_device_open, // 这里就将后面所说的 open 函数指针指定为了 camera_device_open 这个办法。};

cameraDeviceOpen 的工作:

/*===========================================================================
 * FUNCTION   : cameraDeviceOpen
 *
 * DESCRIPTION: open a camera device with its ID
 *
 * PARAMETERS :
 *   @camera_id : camera ID
 *   @hw_device : ptr to struct storing camera hardware device info
 *
 * RETURN     : int32_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
int QCamera2Factory::cameraDeviceOpen(int camera_id,
                    struct hw_device_t **hw_device)
{ /* Do something in */ ...... /* Do something out */

    if (mHalDescriptors[camera_id].device_version == CAMERA_DEVICE_API_VERSION_3_0 ) {QCamera3HardwareInterface *hw = new QCamera3HardwareInterface(mHalDescriptors[camera_id].cameraId, // 首先创立了 QCamera3HardwareInterface 的实例。mCallbacks); if (!hw) {LOGE("Allocation of hardware interface failed"); return NO_MEMORY;
        }
        rc = hw->openCamera(hw_device); // 调用实例的 openCamera 办法。if (rc != 0) {delete hw;}
    } /* Do something in */ ...... /* Do something out */

    return rc;
}

2.4.3 QCamera3HardwareInterface

 hardware\qcom\camera\qcamera2\hal3\QCamera3HWI.cpp

首先须要留神的是外部成员 mCameraOps 的定义。在结构实例时,有 mCameraDevice.ops = &mCameraOps;(关键点)

camera3_device_ops_t QCamera3HardwareInterface::mCameraOps = {
    .initialize = QCamera3HardwareInterface::initialize,
    .configure_streams = QCamera3HardwareInterface::configure_streams,
    .register_stream_buffers = NULL,
    .construct_default_request_settings = QCamera3HardwareInterface::construct_default_request_settings,
    .process_capture_request = QCamera3HardwareInterface::process_capture_request,
    .get_metadata_vendor_tag_ops = NULL,
    .dump = QCamera3HardwareInterface::dump,
    .flush = QCamera3HardwareInterface::flush,
    .reserved = {0},
};

再来持续看看 openCamera 实现:

int QCamera3HardwareInterface::openCamera(struct hw_device_t **hw_device)
{/* Do something in */ ...... /* Do something out */ rc = openCamera(); // 调用另一个 openCamera 办法,这是具体实现的局部。if (rc == 0) {*hw_device = &mCameraDevice.common; // 关上相机胜利后,将设施构造中的 common 局部通过双重指针 hw_device 返回。} else
        *hw_device = NULL; /* Do something in */ ...... /* Do something out */
    return rc;
} int QCamera3HardwareInterface::openCamera()
{/* Do something in */ ...... /* Do something out */ rc = camera_open((uint8_t)mCameraId, &mCameraHandle);  // 这里就开始进入接口层了,调用的是接口层中的 camera_open 接口。留神此处获取到了 mCameraHandle.

    /* Do something in */ ...... /* Do something out */ rc = mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle, // 留神这里传入了一个 camEvtHandle
            camEvtHandle, (void *)this); /* Do something in */ ...... /* Do something out */ rc = mCameraHandle->ops->get_session_id(mCameraHandle->camera_handle, 
        &sessionId[mCameraId]); /* Do something in */ ...... /* Do something out */

    return NO_ERROR;
}

下面是接口转化层中,对于 openCamera 的局部,上面持续看看它的初始化函数。在后面曾经剖析过,创立 CameraDeviceSession 实例时,会调用它外部的初始化办法,而这其中蕴含了调用 QCamera3HWI 的初始化办法 initialize

int QCamera3HardwareInterface::initialize(const struct camera3_device *device, const camera3_callback_ops_t *callback_ops)
{LOGD("E");
    QCamera3HardwareInterface *hw = reinterpret_cast<QCamera3HardwareInterface *>(device->priv); if (!hw) {LOGE("NULL camera device"); return -ENODEV;
    } int rc = hw->initialize(callback_ops); // 调用了真正实现的初始化逻辑的函数
    LOGD("X"); return rc;
} int QCamera3HardwareInterface::initialize(const struct camera3_callback_ops *callback_ops)
{ATRACE_CALL(); int rc;

    LOGI("E :mCameraId = %d mState = %d", mCameraId, mState);
    pthread_mutex_lock(&mMutex); // Validate current state
    switch (mState) { case OPENED: /* valid state */
            break; default:
            LOGE("Invalid state %d", mState);
            rc = -ENODEV; goto err1;
    }

    rc = initParameters(); // 参数(mParameters)初始化,留神这里的参数和 CameraParameter 是不同的,它是 metadata_buffer 相干参数的构造。if (rc < 0) {LOGE("initParamters failed %d", rc); goto err1;
    }
    mCallbackOps = callback_ops; // 这里将 camera3_call_back_ops 与 mCallbackOps 关联了起来。mChannelHandle = mCameraHandle->ops->add_channel( // 获取 mChannelHandle 这一句柄,调用的办法理论是 mm_camera_interface.c 中的 mm_camera_intf_add_channel。mCameraHandle->camera_handle, NULL, NULL, this); if (mChannelHandle == 0) {LOGE("add_channel failed");
        rc = -ENOMEM;
        pthread_mutex_unlock(&mMutex); return rc;
    }

    pthread_mutex_unlock(&mMutex);
    mCameraInitialized = true;
    mState = INITIALIZED;
    LOGI("X"); return 0;

err1:
    pthread_mutex_unlock(&mMutex); return rc;
}

2.4.4 mm_camera_interface.c(接口层)

hardware\qcom\camera\qcamera2\stack\mm-camera-interface\src\mm_camera_interface.c

camera_open 中干的事也不多,省略掉了对于为 cam_obj 分配内存以及初始化的局部 。实际上是调用实现层中的 mm_camera_open 来真正实现关上相机设施的操作,设施的各种信息都填充到 cam_obj 构造中。

int32_t camera_open(uint8_t camera_idx, mm_camera_vtbl_t **camera_vtbl)
{
    int32_t rc = 0;
    mm_camera_obj_t *cam_obj = NULL; /* Do something in */ ...... /* Do something out */ 
    rc = mm_camera_open(cam_obj); /* Do something in */ ...... /* Do something out */ 
}

而对于初始化时调用的 mm_camera_intf_add_channel 代码如下:

static uint32_t mm_camera_intf_add_channel(uint32_t camera_handle,
                                           mm_camera_channel_attr_t *attr,
                                           mm_camera_buf_notify_t channel_cb, void *userdata)
{
    uint32_t ch_id = 0;
    mm_camera_obj_t * my_obj = NULL;

    LOGD("E camera_handler = %d", camera_handle);
    pthread_mutex_lock(&g_intf_lock);
    my_obj = mm_camera_util_get_camera_by_handler(camera_handle); if(my_obj) {pthread_mutex_lock(&my_obj->cam_lock);
        pthread_mutex_unlock(&g_intf_lock);
        ch_id = mm_camera_add_channel(my_obj, attr, channel_cb, userdata); // 通过调用实现层的 mm_camera_add_channel 来获取一个 channel id,也就是其句柄。} else {pthread_mutex_unlock(&g_intf_lock);
    }
    LOGD("X ch_id = %d", ch_id); return ch_id;
}

2.4.5 mm_camera.c(实现层)

hardware\qcom\camera\qcamera2\stack\mm-camera-interface\src\mm_camera.c

终于来到最底层的实现了,mm_camera_open 次要工作是填充 my_obj,并且启动、初始化一些线程相干的货色,对于线程的局部我这里就省略掉了。

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; int cam_idx = 0; const char *dev_name_value = NULL; int l_errno = 0;
    pthread_condattr_t cond_attr;

    LOGD("begin\n"); if (NULL == my_obj) {goto on_error;}
    dev_name_value = mm_camera_util_get_dev_name(my_obj->my_hdl); // 此处调用的函数是为了获取 my_obj 的句柄,这里不深入分析。if (NULL == dev_name_value) {goto on_error;}
    snprintf(dev_name, sizeof(dev_name), "/dev/%s",
             dev_name_value);
    sscanf(dev_name, "/dev/video%d", &cam_idx);
    LOGD("dev name = %s, cam_idx = %d", dev_name, cam_idx); do{
        n_try--;
        errno = 0;
        my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK); // 读取设施文件的文件描述符,存到 my_obj->ctrl_fd 中。l_errno = errno;
        LOGD("ctrl_fd = %d, errno == %d", my_obj->ctrl_fd, l_errno); if((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0)) {break;}
        LOGE("Failed with %s error, retrying after %d milli-seconds",
              strerror(errno), sleep_msec);
        usleep(sleep_msec * 1000U);
    }while (n_try > 0); if (my_obj->ctrl_fd < 0) {LOGE("cannot open control fd of'%s'(%s)\n",
                  dev_name, strerror(l_errno)); if (l_errno == EBUSY)
            rc = -EUSERS; else rc = -1; goto on_error;
    } else {mm_camera_get_session_id(my_obj, &my_obj->sessionid); // 胜利获取到文件描述符后,就要获取 session 的 id 了。LOGH("Camera Opened id = %d sessionid = %d", cam_idx, my_obj->sessionid);
    } /* Do something in */ ...... /* Do something out */

    /* unlock cam_lock, we need release global intf_lock in camera_open(),
     * in order not block operation of other Camera in dual camera use case.*/ pthread_mutex_unlock(&my_obj->cam_lock); return rc;
}

初始化的相干局部,mm_camera_add_channel 代码如下:

uint32_t mm_camera_add_channel(mm_camera_obj_t *my_obj,
                               mm_camera_channel_attr_t *attr,
                               mm_camera_buf_notify_t channel_cb, void *userdata)
{
    mm_channel_t *ch_obj = NULL;
    uint8_t ch_idx = 0;
    uint32_t ch_hdl = 0; // 从现有的 Channel 中找到第一个状态为 NOTUSED 的,获取到 ch_obj 中
    for(ch_idx = 0; ch_idx < MM_CAMERA_CHANNEL_MAX; ch_idx++) {if (MM_CHANNEL_STATE_NOTUSED == my_obj->ch[ch_idx].state) {ch_obj = &my_obj->ch[ch_idx]; break;
        }
    }

  /* 初始化 ch_obj 构造。首先调用 mm_camera_util_generate_handler 为其生成一个句柄(也是该函数的返回值),* 而后将状态设置为 STOPPED,留神这里还保留了 my_obj 的指针及其 session id,最初调用 mm_channel_init 实现了 Channel 的初始化。*/
    if (NULL != ch_obj) {/* initialize channel obj */ memset(ch_obj, 0, sizeof(mm_channel_t));
        ch_hdl = mm_camera_util_generate_handler(ch_idx);
        ch_obj->my_hdl = ch_hdl;
        ch_obj->state = MM_CHANNEL_STATE_STOPPED;
        ch_obj->cam_obj = my_obj;
        pthread_mutex_init(&ch_obj->ch_lock, NULL);
        ch_obj->sessionid = my_obj->sessionid;
        mm_channel_init(ch_obj, attr, channel_cb, userdata);
    }

    pthread_mutex_unlock(&my_obj->cam_lock); return ch_hdl;
}

简图总结:

  总而言之,下面这一顿操作下来后,相机从上到下的整个连路就曾经买通,接下来应该只有 APP 依照流程下发 Preview 的 Request 就能够开始获取预览数据了。

三、外围概念:Request

request 是贯通 camera2 数据处理流程最为重要的概念,利用框架是通过向 camera 子系统发送 request 来获取其想要的 result。

request 有下述几个重要特色:

  • 一个 request 能够对应一系列的 result
  • request 该当蕴含所有必要的配置信息,寄存于 metadata 中。如:分辨率和像素格局;sensor、镜头、闪光等的管制信息;3A 操作模式;RAW 到 YUV 解决控件;以及统计信息的生成等。
  • request 须要携带对应的 surface(也就是框架外面的 stream),用于接管返回的图像。
  • 多个 request 能够同时处于 in-flight 状态,并且 submit request 是 non-blocking 形式的。也就是说,上一个 request 没有解决完,也能够 submit 新的 request。
  • 队列中 request 的解决总是依照 FIFO 的模式。
  • snapshot 的 request 比 preview 的 request 领有更高的优先级。

3.1request 的整体解决流程图

  • open 流程(彩色箭头线条)

    CameraManager 注册 AvailabilityCallback 回调,用于接管相机设施的可用性状态变更的告诉。
    CameraManager 通过调用 getCameraIdList()获取到以后可用的 camera id,通过 getCameraCharacteristcs()函数获取到指定相机设施的个性。
    CameraManager 调用 openCamera()关上指定相机设施,并返回一个 CameraDevice 对象,后续通过该 CameraDevice 对象操控具体的相机设施。
    应用 CameraDevice 对象的 createCaptureSession()创立一个 session,数据申请(预览、拍照等)都是通过 session 进行。在创立 session 时,须要提供 Surface 作为参数,用于接管返回的图像。

  • configure stream 流程(蓝色箭头线条)

    申请 Surface,如上图的 OUTPUT STREAMS DESTINATIONS 框,用于在创立 session 时作为参数,接管 session 返回的图像。
    创立 session 后,surface 会被配置成框架的 stream。在框架中,stream 定义了图像的 size 及 format。
    每个 request 都须要携带 target surface 用于指定返回的图像是归属到哪个被 configure 的 stream 的。

    • request 解决流程(橙色箭头线条)

      CameraDevice 对象通过 createCaptureRequest()来创立 request,每个 reqeust 都须要有 surface 和 settings(settings 就是 metadata,request 蕴含的所有配置信息都是放在 metadata 中的)。
      应用 session 的 capture()、captureBurst()、setStreamingRequest()、setStreamingBurst()等 api 能够将 request 发送到框架。
      预览的 request,通过 setStreamingRequest()、setStreamingBurst()发送,仅调用一次。将 request set 到 repeating request list 外面。只有 pending request queue 外面没有 request,就将 repeating list 外面的 request copy 到 pending queue 外面。
      拍照的 request,通过 capture()、captureBurst()发送,每次须要拍照都会调用。每次触发,都会间接将 request 入到 pending request queue 外面,所以拍照的 request 比预览的 request 的优先级更高。
      in-progress queue 代表以后正在解决的 request 的 queue,每解决完一个,都会从 pending queue 外面拿进去一个新的 request 放到这里。

  • 数据返回流程(紫色箭头线条)

    硬件层面返回的数据会放到 result 外面返回,会通过 session 的 capture callback 回调响应。

3.2 request 在 HAL 的解决形式

  • 1.framework 发送异步的 request 到 hal。
  • 2.hal 必须程序解决 request,对于每一个 request 都要返回 timestamp(shutter,也就是帧的生成工夫)、metadata、image buffers。
  • 3. 对于 request 援用的每一类 steam,必须按 FIFO 的形式返回 result。比方:对于预览的 stream,result id 9 必须要先于 result id 10 返回。然而拍照的 stream,以后能够只返回到 result id 7,因为拍照和预览用的 stream 不一样。
  • 4.hal 须要的信息都通过 request 携带的 metadata 接管,hal 须要返回的信息都通过 result 携带的 metadata 返回。

HAL 解决 request 的整体流程如下图。

    • request 解决流程(彩色箭头线条)

      framework 异步地 submit request 到 hal,hal 顺次解决,并返回 result。
      每个被 submit 到 hal 的 request 都必须携带 stream。stream 分为 input stream 和 output stream:input stream 对应的 buffer 是已有图像数据的 buffer,hal 对这些 buffer 进行 reprocess;output stream 对应的 buffer 是 empty buffer,hal 将生成的图像数据填充的这些 buffer 外面。

    • input stream 解决流程(图像的 INPUT STREAM 1

      request 携带 input stream 及 input buffer 到 hal。
      hal 进行 reprocess,而后新的图像数据从新填充到 buffer 外面,返回到 framework。

    • output stream 解决流程(图像的 OUTPUT STREAM 1…N)

      request 携带 output stream 及 output buffer 到 hal。
      hal 通过一系列模块的的解决,将图像数据写到 buffer 中,返回到 frameowork。

    原文链接:https://www.cnblogs.com/blogs…

    情谊举荐:
    Android 干货分享

    至此,本篇已完结,如有不对的中央,欢迎您的倡议与斧正。同时期待您的关注,感谢您的浏览,谢谢!

    正文完
     0