[Android]Camera2--(2) 打开camera

941 阅读5分钟

1 CameraManager.openCamera分析

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,
                     CameraDeviceImpl.checkAndWrapHandler(handler),
                     USE_CALLING_UID);
}

  其会调用:

private CameraDevice openCameraDeviceUserAsync(String cameraId, CameraDevice.StateCallback callback, Executor executor, final int uid) throws CameraAccessException {
    CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
    CameraDevice device = null;
    ................
    ICameraDeviceUser cameraUser = null;
    // step 1
    android.hardware.camera2.impl.CameraDeviceImpl deviceImpl = 
            new android.hardware.camera2.impl.CameraDeviceImpl(
                cameraId, callback, executor,
                characteristics,
                mContext.getApplicationInfo().targetSdkVersion);
                
    ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
    
    if (supportsCamera2ApiLocked(cameraId)) {
        ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
        ................
        // step 2
        cameraUser = cameraService.connectDevice(callbacks, 
                                                 cameraId, 
                                                 mContext.getOpPackageName(), 
                                                 uid);
    }
    ................
    // step 3
    deviceImpl.setRemoteDevice(cameraUser);
    device = deviceImpl;
    return device;
}

  上述调用可以总结为三步:

  1. 构建CameraDeviceImpl;
  2. 得到CameraService代理,并调用connectDevice,并获得实现了ICameraDeviceUser接口的对象(实际类型是CameraDeviceClient);
  3. CameraDeviceImpl调用setRemoteDevice,触发onOpened的回调给app;onOpened将把本阶段创建的CameraDeviceImpl对象抛送给app。

2 openCamera各个步骤分析

2.1 【step 1】构造CameraDeviceImpl

  step1中直接调用构造器创建CameraDeviceImpl:

public CameraDeviceImpl(String cameraId, StateCallback callback,
           Executor executor,
           CameraCharacteristics characteristics, 
           int appTargetSdkVersion) 
       {
           mCameraId = cameraId;
           mDeviceCallback = callback;
           mDeviceExecutor = executor;
           mCharacteristics = characteristics;
           mAppTargetSdkVersion = appTargetSdkVersion;
           ...............
       }

  app传入的callback赋值给了mDeviceCallback;
  在3.5中,camera在打开后,mDeviceCallback会给app提供回调。

2.2 【step 2】CameraService::connectDevice

  调用connectDevice,通过aidl,进行了一次跨进程通信: frameworks/av/services/camera/libcameraservice/CameraService.cpp)

Status CameraService::connectDevice(
            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
            const String16& cameraId,
            const String16& clientPackageName,
            int clientUid,
            // device作为输出参数,即java层connectDevice的返回值
            /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) 
{
    Status ret = Status::ok();
    String8 id = String8(cameraId);
    sp<CameraDeviceClient> client = nullptr;
    
    // <CALLBACK, CLIENT = CameraDeviceClient>为泛型模板类
    ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>
              (cameraCb, id, /*api1CameraId*/-1,
               CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
               clientUid, USE_CALLING_PID, API_2,
               /*legacyMode*/ false, /*shimUpdateOnly*/ false,
               /*out*/client);
    
    *device = client;
    return ret;
}

  将调用connectHelper:

Status CameraService::connectHelper(
        const sp<CALLBACK>& cameraCb, const String8& cameraId,
        /*-1*/int api1CameraId, /*UNSPECIFIED*/int halVersion,
        const String16& clientPackageName, 
        int clientUid, int clientPid, /*API_2*/apiLevel effectiveApiLevel, 
        /*false*/bool legacyMode, /*false*/bool shimUpdateOnly, 
        /*out*/sp<CLIENT>& device) 
{
    binder::Status ret = binder::Status::ok();
    String8 clientName8(clientPackageName);
    int originalClientPid = 0;
    // CLIENT = CameraDeviceClient
    sp<CLIENT> client = nullptr;
    ................
    int facing = -1;
    // step 1:获取指定id的camera设备版本
    int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing);
    
    sp<BasicClient> tmp = nullptr;
    // step 2:创建CameraDeviceClient对象(最后的输出对象)
    if(!(ret = makeClient(this, cameraCb, clientPackageName,
                          cameraId, /*-1*/api1CameraId, facing,
                          clientPid, clientUid, getpid(), 
                          /*false*/legacyMode, /*UNSPECIFIED*/halVersion, 
                          deviceVersion, /*API_2*/effectiveApiLevel,
                          /*out*/&tmp)).isOk()) 
    {
        return ret;
    }
    client = static_cast<CLIENT*>(tmp.get());
    // step 3:初始化CameraDeviceClient
    err = client->initialize(mCameraProviderManager, mMonitorTags);
    ................
    // 设置输出参数
    device = client;
    return ret;
}

  综上,CameraService::connectDevice也可大致分为三个步骤:

  1. 根据id获取设备版本;
  2. 创建CameraDeviceClient对象;
  3. CameraDeviceClient初始化。

(2.2-1) connectHelper::step1--根据id获取设备版本

CameraService::getDeviceVersion(const String8& cameraId, int* facing) {
    int deviceVersion = 0;
    status_t res;
    hardware::hidl_version maxVersion{0,0};
    // CameraProviderManager封装了device的信息
    // 其会根据id找到对应的device,并赋值
    res = mCameraProviderManager->getHighestSupportedVersion(
                                          cameraId.string(), &maxVersion);
    deviceVersion = HARDWARE_DEVICE_API_VERSION(maxVersion.get_major(), maxVersion.get_minor());
    
    hardware::CameraInfo info;
    // -1
    if (facing) {
        ................
    }
    return deviceVersion;
}

  根据id从CameraProviderManager找到设备,并获得其version信息。 CameraService初始化时,同时会初始化CameraProviderManager,其会从hal层获取设备信息,并缓存。
  该过程可参考下述文章:[Android]Camera2——(1) camera模块初始化

(2.2-2) connectHelper::step2--makeClient创建CameraDeviceClient

Status CameraService::makeClient(const sp<CameraService>& cameraService,
       const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
       /*-1*/int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
       /*false*/bool legacyMode, /*UNSPECIFIED*/int halVersion, int deviceVersion, /*API_2*/apiLevel effectiveApiLevel,
       /*out*/sp<BasicClient>* client) 
    {
        // halVersion为UNSPECIFIED, 数值为-1
        if (halVersion < 0 || halVersion == deviceVersion) {
            switch(deviceVersion) {
                ................
                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
                        ................
                    } else { // Camera2 API route
                        sp<hardware::camera2::ICameraDeviceCallbacks> tmp = 
                                static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
                        // 构建CameraDeviceClient
                        *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
                                      facing, clientPid, clientUid, servicePid);
                    }
                    break;
                    ................
            } //switch ends
        } else {
            ................
        }
        return Status::ok();
    }

  makeClient实际根据版本信息,创建了CameraDeviceClient对象。
  step 3是CameraDeviceClient初始化。在3.3、3.4中,了解CameraDeviceClient的同时,了解其初始化流程。

2.3 CameraDeviceClient构造、初始化

(2.3-1) CameraDeviceClient构造

  类声明如下:

class CameraDeviceClient :
        public Camera2ClientBase<CameraDeviceClientBase>,
        public camera2::FrameProcessorBase::FilteredListener
    {
        ...............
    }

  父类Camera2ClientBase传入的泛型类实例为CameraDeviceClientBase。

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, /*API1 camera ID*/ -1,
                          cameraFacing, clientPid, clientUid, servicePid),
        mInputStream(),
        mStreamingRequestId(REQUEST_ID_NONE),
        mRequestIdCounter(0) 
    {
        ATRACE_CALL();
        ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
    }

  CameraDeviceClient构造中,主要调用了父类Camera2ClientBase的构造。

(2.3-2) Camera2ClientBase构造,创建Camera3Device内部对象

// TClientBase实际为CameraDeviceClientBase
template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(
        const sp<CameraService>& cameraService,
        const sp<TCamCallbacks>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraId,
        int api1CameraId,
        int cameraFacing,
        int clientPid,
        uid_t clientUid,
        int servicePid)
        :
        TClientBase(cameraService, remoteCallback, clientPackageName,
                    cameraId, api1CameraId, cameraFacing, clientPid, clientUid, 
                    servicePid),
        mSharedCameraCallbacks(remoteCallback),
        mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
        mDeviceActive(false),
        mApi1CameraId(api1CameraId)
    {
        mInitialClientPid = clientPid;
        mDevice = new Camera3Device(cameraId);
    }

  父类中,主要构造了Camera3Device

(2.3-3) CameraDeviceClient初始化

  在(3.2-1)中已经看到,当CameraDeviceClient被创建后,即调用initialize()初始化。

status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager,
             const String8& monitorTags) 
         {
             return initializeImpl(manager, monitorTags);
         }

  继续调用initializeImpl:

template<typename TProviderPtr>
status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) 
{
    status_t res;
    res = Camera2ClientBase::initialize(providerPtr, monitorTags);
    
    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;
}

  主要调用了父类的initialize方法,并初始化了FrameProcessor。

(2.3-4) Camera2ClientBase::initialize--初始化Camera3Device

  最终会调用Camera2ClientBase::initializeImpl:

template <typename TClientBase>
template <typename TProviderPtr>
status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr,
         const String8& monitorTags)
    {
    status_t res;
    
    // Verify ops permissions
    res = TClientBase::startCameraOps();
    
    // Camera3Device
    res = mDevice->initialize(providerPtr, monitorTags);
    
    wp<CameraDeviceBase::NotificationListener> weakThis(this);
    res = mDevice->setNotifyCallback(weakThis);
    return OK;
}

  实际上初始化Camera3Device,并传入了CameraProviderManager。

2.4 Camera3Device构造、初始化

(2.4-1) Camera3Device构造

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),
          mLastTemplateId(-1)
{
    camera3_callback_ops::notify = &sNotify;
    camera3_callback_ops::process_capture_result = &sProcessCaptureResult;
}

  初始化内部域,并指定了两个hal的回调函数。

(2.4-2) 初始化Camera3Device,创建当前camera会话

status_t Camera3Device::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
    Mutex::Autolock il(mInterfaceLock);
    Mutex::Autolock l(mLock);
    
    ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
    ................
    sp<ICameraDeviceSession> session;
    // openSession会通过camera id找到CameraProviderManager初始化时缓存的camera设备
    // hal层的CameraDevice会调用open方法,通过camera module获得camera3_device_t*
    // 创建CameraDeviceSession,代表当前camera会话,并返回给framework
    status_t res = manager->openSession(mId.string(), this, /*out*/ &session);
    ................
    res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
    ................
    ................
    // queue为RequestMetadataQueue
    // 通过hidl接口从CameraDeviceSession获得
    mInterface = new HalInterface(session, queue);
    ................
    return initializeCommonLocked();
}

  Camera3Device::initialize的流程可简述为如下:
  step 1:CameraProviderManager::openSession,其内部通过cameraId找到CameraProviderManager初始化时缓存的camera设备信息(hal层CameraDevice的远程接口);#[Android]Camera2——(1) camera模块初始化
  step 2:hal的CameraDevice内部持有CameraModule(camera驱动封装),CameraDevice调用open;
  step 3:CameraDevice::open通过CameraModule获得cameraId所代表的camera硬件设备索引camera3_device_t*,通过该索引创建CameraDeviceSession,代表当前camera会话,返回给framework;
  step 4:在Camera3Device内部封装HalInterface对象,其内部会持有CameraDeviceSession的远程代理;
  step 5:调用initializeCommonLocked(),其中涉及到过多细节,暂不在这里累述。
  综上,3.3和3.4详述了3.2-step3中提及到的CameraDeviceClient初始化

2.5 【step 3】CameraDeviceImpl::setRemoteDevice产生onOpened回调

  回到应用层的CameraDeviceImpl:

// 输入参数为CameraDeviceClient的代理
public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
    synchronized(mInterfaceLock) {
        ................
        mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
        ................
        mDeviceExecutor.execute(mCallOnOpened);
        mDeviceExecutor.execute(mCallOnUnconfigured);
    }
}

  mCallOnOpened是一个runnable:

private final Runnable mCallOnOpened = new Runnable() {
    @Override
    public void run() {
        StateCallbackKK sessionCallback = null;
        synchronized(mInterfaceLock) {
            if (mRemoteDevice == null) return; // Camera already closed
                sessionCallback = mSessionStateCallback;
            }
            if (sessionCallback != null) {
                sessionCallback.onOpened(CameraDeviceImpl.this);
            }
            // mDeviceCallback将onOpened的回调提供给app
            mDeviceCallback.onOpened(CameraDeviceImpl.this);
        }
    };

  mDeviceCallback将onOpened的回调提供给app。

3 打开camera简易时序图

p2_openCamera时序.png

4 camera2架构中各类层级整理

  下图来自Android官网,用于加深对openCamera过程中各个模块的理解:

fw.jpg