GVKun编程网logo

android hal 诠释(android haxm)

1

如果您对androidhal诠释感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于androidhal诠释的详细内容,我们还将为您解答androidhaxm的相关问题,并且为您

如果您对android hal 诠释感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于android hal 诠释的详细内容,我们还将为您解答android haxm的相关问题,并且为您提供关于Android - 硬件抽象层(HAL)、Android 8.0 系统源码分析 --openCamera(HAL)启动过程源码分析、Android : Camera 之 camx hal 架构、Android Automotive types.hal 更改未自动生成的有价值信息。

本文目录一览:

android hal 诠释(android haxm)

android hal 诠释(android haxm)

历史原因使 Android 系统有了 HAL,它的角色相当于一个中间人,对上层,它负责给 JNI 提供调用 kernel 的方法,对下层,它所提供的方法包含能够访问 kernel 的函数,即 kernel 提供给上层的 API,如:open、read、write、ioctl 等;

下面,我们通过对比 Android 系统架构和 Linux 系统架构来增加理解:

 

 

Android 系统架构(HAL)

 

 

Android 系统架构(无 HAL)

 

 

Linux 系统架构

 

       补充一下基础概念:所谓的 API 函数,被包含在用户层的函数库中,API 对 kernel 是产生系统调用,对用户程序是提供产生系统调用的方法;所谓的接口,是对外公开声明的函数、变量,即汇编语言中所说的标号或符号,外部程序通过接口可以引用某些自己不具备的服务

 

1、Linux 系统架构

Android 是基于 Linux 的扩展,所以我们先来看一下 Linux 系统架构;

从软件架构的角度来看,Linux 分为 user 层、kernel 层,这两层是 C 实现的(应用层还可用 C++ 实现);

       从系统服务流程的角度来看,Linux 有调用服务的 user 层、执行系统调用的服务层、支持系统调用的内核函数(服务模块);

       所以,在 Linux 系统中访问设备的流程为:用户层程序直接产生系统调用(系统开发人员)或者通过 API 函数间接产生系统调用陷入 kernel 层,在 kernel 层找到用户程序所需的服务,这里说的是访问设备,则找的是 device driver,通过 device driver 最终实现对硬件设备的访问;

       以代码示意整个流程:

---------------------------------------------------------------

      

       main()

       {

              operation();

}     

 

extern system_call();
operation()

       {

              system_call();

}                                            user 层

---------------------------------------------------------------

                                                  kernel 层     

 

system_call()

{

        datatype (*system_service)();

        system_service = find_sys_service();

        system_service();

}

 

 

device_operateion()    // this is one of system service module functions(methods)

{

       

}

---------------------------------------------------------------

               device                         硬件层

---------------------------------------------------------------

 

2、Android 系统架构

从 Android 系统架构(无 HAL)框图可知,Android 系统架构比 Linux 系统架构多了 Application、Application Framework 两层,这就是 android 的应用层(JAVA);

Android 将 Linux 的应用层(用户 C 程序 + 函数库)添加一个 Android Runtime 作为其中间层,并将中间层和 kernel 层统称 Android 的系统层(C/C++);

HAL 所调用的 API 来自 Libraries,真正能和 kernel 打交道的是 API,所以,Android 系统架构(HAL)框图并不准确,HAL 并非一个独立的具有隔离作用的层,而是从某方面性质上宣称它是一个 Layer,其实它相当于 Linux 系统中的用户 C 程序组,只是它不仅要完成在 Linux 系统中用户 C 程序所要完成的工作,还要向上给 JNI 提供完成这些工作的接口,实现从 JAVA 调用 C 获取 kernel 系统服务的机制;因此,我个人认为 Android 系统架构(无 HAL)框图更为恰当,HAL 的存在只是为了在概念上更好的表述和理解 Android 系统而已;

Android 的整个系统服务调用流程我只从 HAL 开始往下较为清晰,对 JNI 方法有初步了解,尚未完全清晰理解,JAVA 层则几乎未涉及,此次学习只能暂时到此为止了!

Android - 硬件抽象层(HAL)

Android - 硬件抽象层(HAL)

 

出发点:保护厂商利益
 
         Android 的硬件抽象层,简单来说,就是 对 Linux 内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而 Linux 内核驱动程序运行在内核空间。
        为什么要这样安排呢?把硬件抽象层和内核驱动整合在一起放在内核空间不可行吗?从技术实现的角度来看,是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害厂家的利益。我们知道,Linux 内核源代码版权遵循 GNU License,而 Android 源代码版权遵循 Apache License,前者在发布产品时,必须公布源代码,而后者无须发布源代码。如果把对硬件支持的所有代码都放在 Linux 驱动层,那就意味着发布时要公开驱动程序的源代码,而公开源代码就意味着把硬件的相关参数和实现都公开了,在手机市场竞争激烈的今天,这对厂家来说,损害是非常大的。因此,Android 才会想到把对硬件的支持分成硬件抽象层和内核驱动层, 内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来了。也正是由于这个分层的原因,Android 被踢出了 Linux 内核主线代码树中。大家想想,Android 放在内核空间的驱动程序对硬件的支持是不完整的,把 Linux 内核移植到别的机器上去时,由于缺乏硬件抽象层的支持,硬件就完全不能用了,这也是为什么说 Android 是开放系统而不是开源系统的原因。
 
设备驱动分为内核空间和用户空间两部分:
  • 内核空间主要负责硬件访问逻辑(GPL)
  • 用户空间主要负责参数和访问流程控制(Apache License)
 
 
 
Android 硬件驱动程序开发:与传统的 Linux 硬件驱动程序开发是一样的
Android 硬件驱动程序验证
Android 硬件抽象层模块开发
 
Android 硬件访问服务开发
 
 
 

Android 8.0 系统源码分析 --openCamera(HAL)启动过程源码分析

Android 8.0 系统源码分析 --openCamera(HAL)启动过程源码分析

 前面我们详细分析了从应用层调用 CameraManager 的 openCamera 的方法来打开相机的逻辑,上次的分析我们来到了 CameraServer 进程当中,但是还没有真正看到 open 操作设备节点来实现真正打开的逻辑,遗留的问题也就是从 frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp 文件中的 status_t Camera3Device::initialize (sp<CameraProviderManager> manager) 方法的 status_t res = manager->openSession (mId.string (), this, /*out*/ &session); 这句代码进去后进行的处理。

     我们知道,Android 的内核是 Linux 内核,Linux 上所有的设备都被抽象成文件节点,对设备的操作都变成了对文件节点的操作,非常方便,我们 openCamera 的逻辑最终肯定也是通过 open 系统函数来打开 camera 的文件节点,而 open 系统调用的处理就是对应的 camera 驱动了。

     好,我们回到正文,status_t res = manager->openSession (mId.string (), this, /*out*/ &session); 这句逻辑中的 manager 是一个 sp<CameraProviderManager > 对象,那我们就来看一下 frameworks\av\services\camera\libcameraservice\common\CameraProviderManager.cpp 文件中的 openSession 方法的实现,源码如下:

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,
            /*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;
    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);
}
     该方法中根据传入的最小和最大版本号调用 findDeviceInfoLocked 方法获取到一个 DeviceInfo 对象,其中的逻辑比较简单,源码如下:

CameraProviderManager::ProviderInfo::DeviceInfo* CameraProviderManager::findDeviceInfoLocked(
        const std::string& id,
        hardware::hidl_version minVersion, hardware::hidl_version maxVersion) const {
    for (auto& provider : mProviders) {
        for (auto& deviceInfo : provider->mDevices) {
            if (deviceInfo->mId == id &&
                    minVersion <= deviceInfo->mVersion && maxVersion >= deviceInfo->mVersion) {
                return deviceInfo.get();
            }
        }
    }
    return nullptr;
}
     可以看到,该方法的逻辑就是对成员变量 mProviders 进行遍历,判断每个 DeviceInfo 的 id 值、最小版本、最大版本号是否符合传入的最小和最大版本,符合的话,就返回该对象,那我们就要问一下了,mProviders 中的值是什么时候添加的呢?我们大概追究一下,它是在 CameraService 进行启动时,初始化 CameraProviderManager 对象的逻辑中,通过 addProviderLocked 方法生成具体的 DeviceInfo 对象,添加到 mProviders 成员变量中的。addProviderLocked 方法的源码如下:

status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {
    for (const auto& providerInfo : mProviders) {
        if (providerInfo->mProviderName == newProvider) {
            ALOGW("%s: Camera provider HAL with name ''%s'' already registered", __FUNCTION__,
                    newProvider.c_str());
            return ALREADY_EXISTS;
        }
    }
 
    sp<provider::V2_4::ICameraProvider> interface;
    interface = mServiceProxy->getService(newProvider);
 
    if (interface == nullptr) {
        if (expected) {
            ALOGE("%s: Camera provider HAL ''%s'' is not actually available", __FUNCTION__,
                    newProvider.c_str());
            return BAD_VALUE;
        } else {
            return OK;
        }
    }
 
    sp<ProviderInfo> providerInfo =
            new ProviderInfo(newProvider, interface, this);
    status_t res = providerInfo->initialize();
    if (res != OK) {
        return res;
    }
 
    mProviders.push_back(providerInfo);
 
    return OK;
}
     这个方法中有一个非常重要的对象,就是 interface = mServiceProxy->getService (newProvider) 逻辑返回的 interface,它又是一个 binder 对象,获取 camera 属性、数量等实质性的方法都是通过它来完成的,获取成功后,以它为参数构造一个 ProviderInfo 对象,最后添加到 mProviders 成员变量当中。

     好了,我们回到 openSession 方法当中,找到 deviceInfo 对象之后,然后调用 deviceInfo3->mInterface->open,而它的成员变量 mInterface 就是在前面我们说构造 ProviderInfo 时获取到的 binder 对象了,它实际上是 hardware\interfaces\camera\device\3.2\default\CameraDevice.cpp 对象了,来到这里,我们就进入了 CameraDaemon 进程当中,两个进程的通信是通过 HIDL,其实还是 binder 进程间通信机制,只是它是用来提供给 HAL 层服务的,所以和 AIDL 类似,取了个 HIDL 的名字。这里需要说一下,为是什么是 3.2 下面的这个类呢?因为我们在调用 openSession 方法时,传入的第二个参数 const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback 和第三个参数 sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session 就可以非常明显的看出来,当前调用的版本是 V3_2。接下来,我们就来看一下 CameraDevice.cpp 类的 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, session);
        return Void();
    }
 
    if (status != Status::OK) {
        // Provider will never pass initFailed device to client, so
        // this must be a disconnected camera
        ALOGE("%s: cannot open camera %s. camera is disconnected!",
                __FUNCTION__, mCameraId.c_str());
        _hidl_cb(Status::CAMERA_DISCONNECTED, session);
        return Void();
    } else {
        mLock.lock();
 
        ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mCameraIdInt);
        session = mSession.promote();
        if (session != nullptr && !session->isClosed()) {
            ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
            mLock.unlock();
            _hidl_cb(Status::CAMERA_IN_USE, nullptr);
            return Void();
        }
 
        /** Open HAL device */
        status_t res;
        camera3_device_t *device;
 
        ATRACE_BEGIN("camera3->open");
        res = mModule->open(mCameraId.c_str(),
                reinterpret_cast<hw_device_t**>(&device));
        ATRACE_END();
 
        if (res != OK) {
            ALOGE("%s: cannot open camera %s!", __FUNCTION__, mCameraId.c_str());
            mLock.unlock();
            _hidl_cb(getHidlStatus(res), nullptr);
            return Void();
        }
 
        /** Cross-check device version */
        if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) {
            ALOGE("%s: Could not open camera: "
                    "Camera device should be at least %x, reports %x instead",
                    __FUNCTION__,
                    CAMERA_DEVICE_API_VERSION_3_2,
                    device->common.version);
            device->common.close(&device->common);
            mLock.unlock();
            _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
            return Void();
        }
 
        struct camera_info info;
        res = mModule->getCameraInfo(mCameraIdInt, &info);
        if (res != OK) {
            ALOGE("%s: Could not open camera: getCameraInfo failed", __FUNCTION__);
            device->common.close(&device->common);
            mLock.unlock();
            _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
            return Void();
        }
 
        session = new CameraDeviceSession(
                device, info.static_camera_characteristics, callback);
        if (session == nullptr) {
            ALOGE("%s: camera device session allocation failed", __FUNCTION__);
            mLock.unlock();
            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
            return Void();
        }
        if (session->isInitFailed()) {
            ALOGE("%s: camera device session init failed", __FUNCTION__);
            session = nullptr;
            mLock.unlock();
            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
            return Void();
        }
        mSession = session;
        mLock.unlock();
    }
    _hidl_cb(status, session);
    return Void();
}
     我们先来看一下该方法的参数,第一个是 callback 对象,它的使用方法和我们之前讲的应用层调用 openCamera 时在 CameraManager 中传入的 binder 类型的 callback 是一样的,Server 端拿到这个 callback 之后,就可以针对需要的节点事件回调应用层,而这里是在 CameraDaemon 回调 CameraServer,道理是一样的。这个 callback 参数最终赋值给 HAL 层中的 CameraDeviceSession 类的 mResultBatcher 成员变量了;第二个参数是 open_cb 类型,从它的命名中可以看出来,它也是一个回调函数,非常方便,就像一个函数指针一样,它在 CameraProviderManager 一侧中像一个结构体一样传了过来,当 CameraDevice 类中的 open 执行完成后,就会将 session 对象作为参数回传到 CameraProviderManager 这一侧,我们就拿到了 session,后续对 camera 的操作都是通过这个 sesson 对象来进行中转完成的。CameraProviderManager 这一侧传入的结构体如下:

     我们继续阅读代码,open 方法中先判断 status,正常的话,接着调用 res = mModule->open (mCameraId.c_str (), reinterpret_cast<hw_device_t**>(&device)) 来执行相机的打开操作,mModule 对象是 CameraDevice 类的成员变量,它是在 CameraDevice 的构造函数中传入的,而 CameraDevice 类的对象是在 hardware\interfaces\camera\provider\2.4\default\CameraProvider.cpp 文件中的 getCameraDeviceInterface_V3_x 方法中构造的,该方法也是 CameraDaemon 进程为 CameraServer 进程提供的,当添加相机设备时,CameraServer 就需要查询和获取 camera 设备,也就会使用到这个接口,getCameraDeviceInterface_V3_x 方法源码如下:

Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
        const hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb)  {
    std::string cameraId, deviceVersion;
    bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
    if (!match) {
        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
        return Void();
    }
 
    std::string deviceName(cameraDeviceName.c_str());
    ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName));
    if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch
        Status status = Status::OK;
        ssize_t idx = mCameraIds.indexOf(cameraId);
        if (idx == NAME_NOT_FOUND) {
            ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str());
            status = Status::ILLEGAL_ARGUMENT;
        } else { // invalid version
            ALOGE("%s: camera device %s does not support version %s!",
                    __FUNCTION__, cameraId.c_str(), deviceVersion.c_str());
            status = Status::OPERATION_NOT_SUPPORTED;
        }
        _hidl_cb(status, nullptr);
        return Void();
    }
 
    if (mCameraStatusMap.count(cameraId) == 0 ||
            mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) {
        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
        return Void();
    }
 
    sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> device =
            new android::hardware::camera::device::V3_2::implementation::CameraDevice(
                    mModule, cameraId, mCameraDeviceNames);
 
    if (device == nullptr) {
        ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str());
        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
        return Void();
    }
 
    if (device->isInitFailed()) {
        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
        device = nullptr;
        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
        return Void();
    }
 
    _hidl_cb (Status::OK, device);
    return Void();
}
     可以看到,在构造 CameraDevice 对象时,传入的第一个参数 mModule,它也是 CameraProvider 类的成员变量,它的定义在 hardware\interfaces\camera\provider\2.4\default\CameraProvider.h 头文件中,源码如下:

     它是一个 CameraModule 对象,那么我们接下来就看看 hardware\interfaces\camera\common\1.0\default\CameraModule.cpp 类的 open 方法,来看看它是如何处理的。它的 open 方法源码如下:

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;
}
     该方法非常简洁,就是调用 mModule 类的 common.methods 的 open 方法处理,它的 mModule 也是在 CameraModule 类的构造函数中传入的,而 CameraModule 的构造方法是在 CameraProvider 类的 initialize () 方法中调用的,源码如下:

bool CameraProvider::initialize() {
    camera_module_t *rawModule;
    int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
            (const hw_module_t **)&rawModule);
    if (err < 0) {
        ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
        return true;
    }
 
    mModule = new CameraModule(rawModule);
    err = mModule->init();
    if (err != OK) {
        ALOGE("Could not initialize camera HAL module: %d (%s)", err, strerror(-err));
        mModule.clear();
        return true;
    }
    ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
 
    // Setup vendor tags here so HAL can setup vendor keys in camera characteristics
    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    if (!setUpVendorTags()) {
        ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__);
    }
 
    // Setup callback now because we are going to try openLegacy next
    err = mModule->setCallbacks(this);
    if (err != OK) {
        ALOGE("Could not set camera module callback: %d (%s)", err, strerror(-err));
        mModule.clear();
        return true;
    }
 
    mNumberOfLegacyCameras = mModule->getNumberOfCameras();
    for (int i = 0; i < mNumberOfLegacyCameras; i++) {
        struct camera_info info;
        auto rc = mModule->getCameraInfo(i, &info);
        if (rc != NO_ERROR) {
            ALOGE("%s: Camera info query failed!", __func__);
            mModule.clear();
            return true;
        }
 
        if (checkCameraVersion(i, info) != OK) {
            ALOGE("%s: Camera version check failed!", __func__);
            mModule.clear();
            return true;
        }
 
        char cameraId[kMaxCameraIdLen];
        snprintf(cameraId, sizeof(cameraId), "%d", i);
        std::string cameraIdStr(cameraId);
        mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;
        mCameraIds.add(cameraIdStr);
 
        // initialize mCameraDeviceNames and mOpenLegacySupported
        mOpenLegacySupported[cameraIdStr] = false;
        int deviceVersion = mModule->getDeviceVersion(i);
        mCameraDeviceNames.add(
                std::make_pair(cameraIdStr,
                               getHidlDeviceName(cameraIdStr, deviceVersion)));
        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
                mModule->isOpenLegacyDefined()) {
            // try open_legacy to see if it actually works
            struct hw_device_t* halDev = nullptr;
            int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
            if (ret == 0) {
                mOpenLegacySupported[cameraIdStr] = true;
                halDev->close(halDev);
                mCameraDeviceNames.add(
                        std::make_pair(cameraIdStr,
                                getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)));
            } else if (ret == -EBUSY || ret == -EUSERS) {
                // Looks like this provider instance is not initialized during
                // system startup and there are other camera users already.
                // Not a good sign but not fatal.
                ALOGW("%s: open_legacy try failed!", __FUNCTION__);
            }
        }
    }
 
    return false; // mInitFailed
}
     这里构造 CameraModule 时传入的参数 rawModule 就是在该方法一开始时,通过调用 int err = hw_get_module (CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule) 获取到的,看到这里大家是不是觉得有些熟悉,CAMERA_HARDWARE_MODULE_ID 就是 HAL 层定义的 module,从这里往下就和对应的设备厂商有密切关系了,当然具体的实现也就差别很大了,而不像我们前面到这里,不分厂商,所有设备,只要是 android 都是通用的。好了,我这里下载的 8.0 源码中提供了三个厂商的实现,分别命名为 google、huawei、lge,截图如下:

     google 目录下具体的实现使用的是高通的设备,我们就来看看这个是怎么实现的。高通相机中的 hw_module_t、camera_module_t 两个结构体定义在 device\google\marlin\camera\QCamera2\QCamera2Hal.cpp 文件中,在 CameraProvider 类的 initialize () 方法中调用 hw_get_module 获取到的就是这里定义的 camera_module_t,它也就是构造 CameraModule 时传入的参数,好了,回到 CameraModule 类的 open 方法中,继续调用它的 common(这里就是 camera_module_t 结构体的第一个成员变量 common 了,它指向 camera_common 结构体)的 methods(就是 static hw_module_t camera_common 结构体的倒数第三个属性 methods 了,它指向 & qcamera::QCamera2Factory::mModuleMethods)的 open 方法,我们还是以 goole 目录下高通的实现为例,继续看一下 QCamera2Factory 类的 mModuleMethods 的定义,device\google\marlin\camera\QCamera2\QCamera2Factory.cpp 文件中的 mModuleMethods 定义源码如下:

struct hw_module_methods_t QCamera2Factory::mModuleMethods = {
    .open = QCamera2Factory::camera_device_open,
};
     这里的 open 又指向了 QCamera2Factory 类的 camera_device_open 方法,该方法的源码如下:

int QCamera2Factory::camera_device_open(
    const struct hw_module_t *module, const char *id,
    struct hw_device_t **hw_device)
{
    int rc = NO_ERROR;
    if (module != &HAL_MODULE_INFO_SYM.common) {
        LOGE("Invalid module. Trying to open %p, expect %p",
            module, &HAL_MODULE_INFO_SYM.common);
        return INVALID_OPERATION;
    }
    if (!id) {
        LOGE("Invalid camera id");
        return BAD_VALUE;
    }
 
    if(gQCameraMuxer)
        rc =  gQCameraMuxer->camera_device_open(module, id, hw_device);
    else
        rc = gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device);
 
    return rc;
}
     这里先判断成员变量 gQCameraMuxer 是否为空,它是在 QCamera2Factory 类的构造函数中,判断如果当前为双摄(bDualCamera 为 true,它是通过配置项 persist.camera.dual.camera 获取的)的情况下获取的,这里我们假设它不为空,那么就调用 rc =  gQCameraMuxer->camera_device_open (module, id, hw_device) 来继续打开 camera,gQCameraMuxer 的类型为 QCameraMuxer,接下来看一下 device\google\marlin\camera\QCamera2\HAL\QCameraMuxer.cpp 类中的 camera_device_open 方法的实现,源码如下:

int QCameraMuxer::camera_device_open(
        __unused const struct hw_module_t *module, const char *id,
        struct hw_device_t **hw_device)
{
    int rc = NO_ERROR;
    LOGH("id= %d",atoi(id));
    if (!id) {
        LOGE("Invalid camera id");
        return BAD_VALUE;
    }
 
    rc =  gMuxer->cameraDeviceOpen(atoi(id), hw_device);
    LOGH("id= %d, rc: %d", atoi(id), rc);
    return rc;
}
     该方法的逻辑也非常简洁,参数正确,就接着调用 gMuxer 变量的 cameraDeviceOpen 方法来处理,gMuxer 就是当前类的实例,它的 cameraDeviceOpen 方法的源码如下:

int QCameraMuxer::cameraDeviceOpen(int camera_id,
        struct hw_device_t **hw_device)
{
    int rc = NO_ERROR;
    uint32_t phyId = 0;
    qcamera_logical_descriptor_t *cam = NULL;
 
    if (camera_id < 0 || camera_id >= m_nLogicalCameras) {
        LOGE("Camera id %d not found!", camera_id);
        return -ENODEV;
    }
 
    if ( NULL == m_pLogicalCamera) {
        LOGE("Hal descriptor table is not initialized!");
        return NO_INIT;
    }
 
    char prop[PROPERTY_VALUE_MAX];
    property_get("persist.camera.dc.frame.sync", prop, "1");
    m_bFrameSyncEnabled = atoi(prop);
 
    // Get logical camera
    cam = &m_pLogicalCamera[camera_id];
 
    if (m_pLogicalCamera[camera_id].device_version ==
            CAMERA_DEVICE_API_VERSION_1_0) {
        // HW Dev Holders
        hw_device_t *hw_dev[cam->numCameras];
 
        if (m_pPhyCamera[cam->pId[0]].type != CAM_TYPE_MAIN) {
            LOGE("Physical camera at index 0 is not main!");
            return UNKNOWN_ERROR;
        }
 
        // Open all physical cameras
        for (uint32_t i = 0; i < cam->numCameras; i++) {
            phyId = cam->pId[i];
            QCamera2HardwareInterface *hw =
                    new QCamera2HardwareInterface((uint32_t)phyId);
            if (!hw) {
                LOGE("Allocation of hardware interface failed");
                return NO_MEMORY;
            }
            hw_dev[i] = NULL;
 
            // Make Camera HWI aware of its mode
            cam_sync_related_sensors_event_info_t info;
            info.sync_control = CAM_SYNC_RELATED_SENSORS_ON;
            info.mode = m_pPhyCamera[phyId].mode;
            info.type = m_pPhyCamera[phyId].type;
            rc = hw->setRelatedCamSyncInfo(&info);
            hw->setFrameSyncEnabled(m_bFrameSyncEnabled);
            if (rc != NO_ERROR) {
                LOGE("setRelatedCamSyncInfo failed %d", rc);
                delete hw;
                return rc;
            }
 
            rc = hw->openCamera(&hw_dev[i]);
            if (rc != NO_ERROR) {
                delete hw;
                return rc;
            }
            hw->getCameraSessionId(&m_pPhyCamera[phyId].camera_server_id);
            m_pPhyCamera[phyId].dev = reinterpret_cast<camera_device_t*>(hw_dev[i]);
            m_pPhyCamera[phyId].hwi = hw;
            cam->sId[i] = m_pPhyCamera[phyId].camera_server_id;
            LOGH("camera id %d server id : %d hw device %x, hw %x",
                     phyId, cam->sId[i], hw_dev[i], hw);
        }
    } else {
        LOGE("Device version for camera id %d invalid %d",
                 camera_id, m_pLogicalCamera[camera_id].device_version);
        return BAD_VALUE;
    }
 
    cam->dev.common.tag = HARDWARE_DEVICE_TAG;
    cam->dev.common.version = HARDWARE_DEVICE_API_VERSION(1, 0);
    cam->dev.common.close = close_camera_device;
    cam->dev.ops = &mCameraMuxerOps;
    cam->dev.priv = (void*)cam;
    *hw_device = &cam->dev.common;
    return rc;
}
     该方法中最重要的就是中间的 for 循环了,先构造 QCamera2HardwareInterface 对象,然后调用它的 openCamera 方法打开 camera,接下来就看一下 device\google\marlin\camera\QCamera2\HAL3\QCamera3HWI.cpp 类的 openCamera 方法的实现,源码如下:

int QCamera3HardwareInterface::openCamera(struct hw_device_t **hw_device)
{
    int rc = 0;
    if (mState != CLOSED) {
        *hw_device = NULL;
        return PERMISSION_DENIED;
    }
 
    m_perfLock.lock_acq();
    LOGI("[KPI Perf]: E PROFILE_OPEN_CAMERA camera id %d",
             mCameraId);
 
    rc = openCamera();
    if (rc == 0) {
        *hw_device = &mCameraDevice.common;
    } else
        *hw_device = NULL;
 
    m_perfLock.lock_rel();
    LOGI("[KPI Perf]: X PROFILE_OPEN_CAMERA camera id %d, rc: %d",
             mCameraId, rc);
 
    if (rc == NO_ERROR) {
        mState = OPENED;
    }
    return rc;
}
     它又是转调另一个 openCamera 方法来处理的,源码如下:

int QCamera3HardwareInterface::openCamera()
{
    int rc = 0;
    char value[PROPERTY_VALUE_MAX];
 
    KPI_ATRACE_CALL();
    if (mCameraHandle) {
        LOGE("Failure: Camera already opened");
        return ALREADY_EXISTS;
    }
 
    rc = QCameraFlash::getInstance().reserveFlashForCamera(mCameraId);
    if (rc < 0) {
        LOGE("Failed to reserve flash for camera id: %d",
                mCameraId);
        return UNKNOWN_ERROR;
    }
 
    rc = camera_open((uint8_t)mCameraId, &mCameraHandle);
    if (rc) {
        LOGE("camera_open failed. rc = %d, mCameraHandle = %p", rc, mCameraHandle);
        return rc;
    }
 
    if (!mCameraHandle) {
        LOGE("camera_open failed. mCameraHandle = %p", mCameraHandle);
        return -ENODEV;
    }
 
    rc = mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle,
            camEvtHandle, (void *)this);
 
    if (rc < 0) {
        LOGE("Error, failed to register event callback");
        /* Not closing camera here since it is already handled in destructor */
        return FAILED_TRANSACTION;
    }
 
    mExifParams.debug_params =
            (mm_jpeg_debug_exif_params_t *) malloc (sizeof(mm_jpeg_debug_exif_params_t));
    if (mExifParams.debug_params) {
        memset(mExifParams.debug_params, 0, sizeof(mm_jpeg_debug_exif_params_t));
    } else {
        LOGE("Out of Memory. Allocation failed for 3A debug exif params");
        return NO_MEMORY;
    }
    mFirstConfiguration = true;
 
    //Notify display HAL that a camera session is active.
    //But avoid calling the same during bootup because camera service might open/close
    //cameras at boot time during its initialization and display service will also internally
    //wait for camera service to initialize first while calling this display API, resulting in a
    //deadlock situation. Since boot time camera open/close calls are made only to fetch
    //capabilities, no need of this display bw optimization.
    //Use "service.bootanim.exit" property to know boot status.
    property_get("service.bootanim.exit", value, "0");
    if (atoi(value) == 1) {
        pthread_mutex_lock(&gCamLock);
        if (gNumCameraSessions++ == 0) {
            setCameraLaunchStatus(true);
        }
        pthread_mutex_unlock(&gCamLock);
    }
 
    //fill the session id needed while linking dual cam
    pthread_mutex_lock(&gCamLock);
    rc = mCameraHandle->ops->get_session_id(mCameraHandle->camera_handle,
        &sessionId[mCameraId]);
    pthread_mutex_unlock(&gCamLock);
 
    if (rc < 0) {
        LOGE("Error, failed to get sessiion id");
        return UNKNOWN_ERROR;
    } else {
        //Allocate related cam sync buffer
        //this is needed for the payload that goes along with bundling cmd for related
        //camera use cases
        m_pRelCamSyncHeap = new QCamera3HeapMemory(1);
        rc = m_pRelCamSyncHeap->allocate(sizeof(cam_sync_related_sensors_event_info_t));
        if(rc != OK) {
            rc = NO_MEMORY;
            LOGE("Dualcam: Failed to allocate Related cam sync Heap memory");
            return NO_MEMORY;
        }
 
        //Map memory for related cam sync buffer
        rc = mCameraHandle->ops->map_buf(mCameraHandle->camera_handle,
                CAM_MAPPING_BUF_TYPE_SYNC_RELATED_SENSORS_BUF,
                m_pRelCamSyncHeap->getFd(0),
                sizeof(cam_sync_related_sensors_event_info_t),
                m_pRelCamSyncHeap->getPtr(0));
        if(rc < 0) {
            LOGE("Dualcam: failed to map Related cam sync buffer");
            rc = FAILED_TRANSACTION;
            return NO_MEMORY;
        }
        m_pRelCamSyncBuf =
                (cam_sync_related_sensors_event_info_t*) DATA_PTR(m_pRelCamSyncHeap,0);
    }
 
    LOGH("mCameraId=%d",mCameraId);
 
    return NO_ERROR;
}
     这里又转调 camera_open 方法来处理,camera_open 方法的实现是在 device\google\marlin\camera\QCamera2\stack\mm-camera-interface\src\mm_camera_interface.c 文件中,源码如下:

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;
 
#ifdef QCAMERA_REDEFINE_LOG
    mm_camera_set_dbg_log_properties();
#endif
 
    LOGD("E camera_idx = %d\n", camera_idx);
    if (camera_idx >= g_cam_ctrl.num_cam) {
        LOGE("Invalid camera_idx (%d)", camera_idx);
        return -EINVAL;
    }
 
    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);
        LOGD("opened alreadyn");
        *camera_vtbl = &g_cam_ctrl.cam_obj[camera_idx]->vtbl;
        return rc;
    }
 
    cam_obj = (mm_camera_obj_t *)malloc(sizeof(mm_camera_obj_t));
    if(NULL == cam_obj) {
        pthread_mutex_unlock(&g_intf_lock);
        LOGE("no mem");
        return -EINVAL;
    }
 
    /* 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);
    /* unlock global interface lock, if not, in dual camera use case,
      * current open will block operation of another opened camera obj*/
    pthread_mutex_lock(&cam_obj->cam_lock);
    pthread_mutex_unlock(&g_intf_lock);
 
    rc = mm_camera_open(cam_obj);
 
    pthread_mutex_lock(&g_intf_lock);
    if (rc != 0) {
        LOGE("mm_camera_open err = %d", 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);
        *camera_vtbl = NULL;
        return rc;
    } else {
        LOGD("Open succeded\n");
        g_cam_ctrl.cam_obj[camera_idx] = cam_obj;
        pthread_mutex_unlock(&g_intf_lock);
        *camera_vtbl = &cam_obj->vtbl;
        return 0;
    }
}
     这里调用 malloc 给方法变量分配内存,memset 初始化,然后接着调用 mm_camera_open 继续处理,mm_camera_open 方法的实现在 device\google\marlin\camera\QCamera2\stack\mm-camera-interface\src\mm_camera_interface.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;
    int cam_idx = 0;
    const char *dev_name_value = NULL;
    int l_errno = 0;
 
    LOGD("begin\n");
 
    if (NULL == my_obj) {
        goto on_error;
    }
    dev_name_value = mm_camera_util_get_dev_name(my_obj->my_hdl);
    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);
        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);
        LOGH("Camera Opened id = %d sessionid = %d", cam_idx, my_obj->sessionid);
    }
 
#ifdef DAEMON_PRESENT
    /* open 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);
        l_errno = errno;
        LOGD("ds_fd = %d, errno = %d", my_obj->ds_fd, l_errno);
        if((my_obj->ds_fd >= 0) || (n_try <= 0 )) {
            LOGD("opened, break out while loop");
            break;
        }
        LOGD("failed with I/O error retrying after %d milli-seconds",
              sleep_msec);
        usleep(sleep_msec * 1000U);
    } while (n_try > 0);
 
    if (my_obj->ds_fd < 0) {
        LOGE("cannot open domain socket fd of ''%s''(%s)\n",
                  dev_name, strerror(l_errno));
        rc = -1;
        goto on_error;
    }
#else /* DAEMON_PRESENT */
    cam_status_t cam_status;
    cam_status = mm_camera_module_open_session(my_obj->sessionid,
            mm_camera_module_event_handler);
    if (cam_status < 0) {
        LOGE("Failed to open session");
        if (cam_status == CAM_STATUS_BUSY) {
            rc = -EUSERS;
        } else {
            rc = -1;
        }
        goto on_error;
    }
#endif /* DAEMON_PRESENT */
 
    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);
 
    LOGD("Launch evt Thread in Cam Open");
    snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, "CAM_Dispatch");
    mm_camera_cmd_thread_launch(&my_obj->evt_thread,
                                mm_camera_dispatch_app_event,
                                (void *)my_obj);
 
    /* launch event poll thread
     * we will add evt fd into event poll thread upon user first register for evt */
    LOGD("Launch evt Poll Thread in Cam Open");
    snprintf(my_obj->evt_poll_thread.threadName, THREAD_NAME_SIZE, "CAM_evntPoll");
    mm_camera_poll_thread_launch(&my_obj->evt_poll_thread,
                                 MM_CAMERA_POLL_TYPE_EVT);
    mm_camera_evt_sub(my_obj, TRUE);
 
    /* 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);
    LOGD("end (rc = %d)\n", rc);
    return rc;
 
on_error:
 
    if (NULL == dev_name_value) {
        LOGE("Invalid device name\n");
        rc = -1;
    }
 
    if (NULL == my_obj) {
        LOGE("Invalid camera object\n");
        rc = -1;
    } else {
        if (my_obj->ctrl_fd >= 0) {
            close(my_obj->ctrl_fd);
            my_obj->ctrl_fd = -1;
        }
#ifdef DAEMON_PRESENT
        if (my_obj->ds_fd >= 0) {
            mm_camera_socket_close(my_obj->ds_fd);
            my_obj->ds_fd = -1;
        }
#endif
    }
 
    /* 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;
}
     到这里,终于看到了 open 的系统调用,HAL 端也就是从这里进入内核,调用驱动来处理的,这里大家可以看到,是通过 do/while 循环来处理的,有一个重试机制,重试次数 n_try 不断的减小,当它等于 0 时,相机设备还未正常打开,就退出 do/while 循环了,它的初值为 MM_CAMERA_DEV_OPEN_TRIES,该宏定义的值为 20,在 do 判断中,只要 if ((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0 )) 条件中有一个成立,就跳出循环,(my_obj->ctrl_fd >= 0) 的意思是就 camera 打开成功,返回的 FD 有效;(errno != EIO && errno != ETIMEDOUT) 的意思是未出现 IO 或者超时错误;(n_try <= 0 ) 意思是重试次数已用完,打开成功后,还要进行一些其他初始化的操作。

     到这里,openCamera 才算完成了,大家可以看到,中间的过程真是复杂,当然我们所分析的部分还没有包含驱动部分,想要搞清楚整个逻辑,还是要花费很大的气力的,也希望我们搞技术的同事,能够认认真真的静下心来专心搞技术,以此来提升我们的能力。

     好了,今天就到这里,休息一下!
 

Android : Camera 之 camx hal 架构

Android : Camera 之 camx hal 架构

一、camx 的代码结构

  目前主流的机型都使用 camx 架构,这个架构和之前架构的主要区别就是 芯片接口层的代码从 hardware/qcom 迁移到 vendor/qcom/proprietary/ 下面,
  我们主要关注的 camera hal 层的源码也是放在 vendor/qcom/proprietary/camx/ 下面。
  

 

二、camx 编译:

  camx 的核心目录是 vendor/qcom/proprietary/camx/src/ 目录下面:

total 40
drwxrwxr-x 10 lxl lxl 4096  4  4 10:52 ./
drwxrwxr-x  4 lxl lxl 4096  4  4 10:52 ../
drwxrwxr-x  3 lxl lxl 4096  4  4 10:52 chiiqutils/
drwxrwxr-x  7 lxl lxl 4096  4  4 10:56 core/
drwxrwxr-x  7 lxl lxl 4096  4  4 10:52 csl/
drwxrwxr-x 14 lxl lxl 4096  4  4 10:52 hwl/
drwxrwxr-x  3 lxl lx 4096  4  4 10:52 lib/
drwxrwxr-x  3 lxl lxl 4096  4  4 10:52 osutils/
drwxrwxr-x 11 lxl lxl 4096  4  4 10:52 swl/
drwxrwxr-x  3 lxl lxl 4096  4  4 10:52 utils/

  核心的 Android.mk 在 ./lib/build/android/Android.mk 中。
  其中包括的静态库如下:

# Libraries to link
LOCAL_STATIC_LIBRARIES :=   \
    libcamxcore             \
    libcamxchi              \
    libcamxcsl              \
    libcamxofflinestats     \
    libnc                   \
    libcamxncs              \
    libifestriping          \
    libstriping

LOCAL_WHOLE_STATIC_LIBRARIES := \
    libcamxdspstreamer          \
    libcamxhwlbps               \
    libcamxgenerated            \
    libcamxhal                  \
    libcamxhalutils             \
    libcamxhwlfd                \
    libcamxhwlife               \
    libcamxhwlipe               \
    libcamxhwliqmodule          \
    libcamxswlfdmanager         \
    libcamxswljpeg              \
    libcamxhwljpeg              \
    libcamxhwllrme              \
    libcamxswlransac            \
    libcamxhwltitan17x          \
    libcamxiqsetting            \
    libcamxosutils              \
    libcamxstats                \
    libcamxsensor               \
    libcamxutils

  这些静态库都是 camx 或者其他的目录下编译的,编译工程的时候,我们要先编译这些静态库,然后编译 camx 的动态库(/vendor/lib/hw/camera.qcom.so)。

 

三、camx 代码流程分析:

  camera.provider 中如何实现到 camera hal 层的跳跃,camera service 调用到 camera provider 中的接口方法,现在调用到 camera provider 中的 hardware/interfaces/camera/device/3.2/default/CameraDeviceSession.cpp 中的 processCaptureRequest (...) 方法,最终会调用到:
  status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
  这个 mDevice->ops 就是 hardware/libhardware/include/hardware/camera3.h 中的 camera3_device_ops 结构体: (参考:https://www.jianshu.com/p/099cc3b0ab25)

typedef struct camera3_device_ops {
    int (*initialize)(const struct camera3_device *,
            const camera3_callback_ops_t *callback_ops);
    int (*configure_streams)(const struct camera3_device *,
            camera3_stream_configuration_t *stream_list);
    int (*register_stream_buffers)(const struct camera3_device *,
            const camera3_stream_buffer_set_t *buffer_set);
    const camera_metadata_t* (*construct_default_request_settings)(
            const struct camera3_device *,
            int type);
    int (*process_capture_request)(const struct camera3_device *,
            camera3_capture_request_t *request);
    void (*get_metadata_vendor_tag_ops)(const struct camera3_device*,
            vendor_tag_query_ops_t* ops);
    void (*dump)(const struct camera3_device *, int fd);
    int (*flush)(const struct camera3_device *);
 
    /* reserved for future use */
    void *reserved[8];
} camera3_device_ops_t;

  camera3_device_ops_t 映射函数指针操作: hardware/libhardware/modules/camera/3_0/Camera.cpp

const camera3_device_ops_t Camera::sOps = {
    .initialize = default_camera_hal::initialize,
    .configure_streams = default_camera_hal::configure_streams,
    .register_stream_buffers = default_camera_hal::register_stream_buffers,
    .construct_default_request_settings
        = default_camera_hal::construct_default_request_settings,
    .process_capture_request = default_camera_hal::process_capture_request,
    .get_metadata_vendor_tag_ops = NULL,
    .dump = default_camera_hal::dump,
    .flush = default_camera_hal::flush,
    .reserved = {0},
};

  这样找到在 camera hal 层的函数指针的映射关系。
  映射到:vendor/qcom/proprietary/camx/src/core/hal/camxhal3entry.cpp 中的:

  // Global dispatch
  static Dispatch g_dispatchHAL3(&g_jumpTableHAL3);
/// Array containing camera3_device_ops_t methods
static camera3_device_ops_t g_camera3DeviceOps =
{
    CamX::initialize,
    CamX::configure_streams,
    NULL,
    CamX::construct_default_request_settings,
    CamX::process_capture_request,
    NULL,
    CamX::dump,
    CamX::flush,
    {0},
};
  定义了 g_camera3DeviceOps 变量:
/// Array containing camera3_device_ops_t methods
static camera3_device_ops_t g_camera3DeviceOps =
{
    CamX::initialize,
    CamX::configure_streams,
    NULL,
    CamX::construct_default_request_settings,
    CamX::process_capture_request,
    NULL,
    CamX::dump,
    CamX::flush,
    {0},
};

  并在 \vendor\qcom\proprietary\camx\src\core\hal\camxhaldevice.cpp 的 Initialize 方法中通过 GetCamera3DeviceOps 获取,建立联系:

CamxResult HALDevice::Initialize(
    const HwModule* pHwModule,
    UINT32          cameraId)
{
    CamxResult result = CamxResultSuccess;

    m_cameraId = cameraId;

    if (CamxResultSuccess == result)
    {
        m_camera3Device.hwDevice.tag     = HARDWARE_DEVICE_TAG; /// @todo (CAMX-351) Get from local macro
        m_camera3Device.hwDevice.version = CAMERA_DEVICE_API_VERSION_3_3;
        m_camera3Device.hwDevice.close   = reinterpret_cast<CloseFunc>(GetHwDeviceCloseFunc());
        m_camera3Device.pDeviceOps       = reinterpret_cast<Camera3DeviceOps*>(GetCamera3DeviceOps());
        m_camera3Device.pPrivateData     = this;
        // NOWHINE CP036a: Need exception here
        m_camera3Device.hwDevice.pModule = const_cast<HwModule*>(pHwModule);

        m_HALCallbacks.ProcessCaptureResult = ProcessCaptureResult;
        m_HALCallbacks.NotifyResult         = Notify;
        CamX::ChiOverrideBypass(&m_HALCallbacks);
    }

    m_pHALSession = NULL;
    Utils::Memset(m_flushRequest, 0, sizeof(m_flushRequest));

    return result;
}

  看一下 g_jumpTableHAL3 变量:在 vendor/qcom/proprietary/camx/src/core/hal/camxhal3.cpp 中定义的:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Jump table for HAL3
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
JumpTableHAL3 g_jumpTableHAL3 =
{
    open,
    get_number_of_cameras,
    get_camera_info,
    set_callbacks,
    get_vendor_tag_ops,
    open_legacy,
    set_torch_mode,
    init,
    parallelQuery,
    setCallBack,
    get_tag_count,
    get_all_tags,
    get_section_name,
    get_tag_name,
    get_tag_type,
    close,
    initialize,
    configure_streams,
    construct_default_request_settings,
    process_capture_request,
    dump,
    flush,
    camera_device_status_change,
    torch_mode_status_change,
    process_capture_result,
    notify
};

  这儿直接构成了指针函数的映射关系(对应 camxhaldevice.cpp 中的函数)。

  vendor/qcom/proprietary/camx/src/core/chi/camxchitypes.h 中定义了 CHIAppCallbacks 结构体,如下:

struct CHIAppCallbacks
{
    /// @brief Called by the driver to get number of cameras
    INT(*CHIGetNumCameras)(
        UINT32* pNumFwCameras,
        UINT32* pNumLogicalCameras);
 
    /// @brief Called by the driver to get the camera info for the camera id
    CamxResult (*CHIGetCameraInfo)(
        UINT32      cameraId,
        CameraInfo* pCameraInfo);
 
    /// @brief Defines the prototype for the device status change callback method from to the framework. Please refer to
    ///        the camera_device_status_change documentation in hardware/camera_common.h.
    VOID (*CHIInitializeOverrideSession)(
        UINT32               cameraId,
        const Camera3Device* pCamera3Device,
        const HALCallbacks*  pHALCallbacks,
        Camera3StreamConfig* pStreamConfig,
        BOOL*                isOverrideEnabled,
        VOID**               ppPrivate);
 
    /// @brief Defines the prototype for the torch mode status change callback method from to the framework. Please refer to
    ///        the torch_mode_status_change documentation in hardware/camera_common.h.
    VOID (*CHIFinalizeOverrideSession)(
        const Camera3Device* pCamera3Device,
        UINT64*              pSession,
        VOID**               ppPrivate);
 
    /// @brief Called by the driver to inform about session closing
    VOID (*CHITeardownOverrideSession)(
        const Camera3Device* pCamera3Device,
        UINT64*              pSession,
        VOID*                pPrivate);
 
    /// @brief Called by the driver to pass on capture request call to CHI
    INT (*CHIOverrideProcessRequest)(
        const Camera3Device*    pCamera3Device,
        Camera3CaptureRequest*  pCaptureRequest,
        VOID*                   pPrivate);
 
    /// @brief Called by the driver to allow for additional override processing during open()
    INT(*CHIExtendOpen)(
        UINT32  cameraId,
        VOID*   pPrivateData);
 
    /// @brief Called by the driver to allow for additional override processing during close()
    INT(*CHIExtendClose)(
        UINT32  cameraId,
        VOID*   pPrivateData);
 
    /// @brief Called by the driver to allow override to remap special camera IDs into logical camera IDs
    UINT32(*CHIRemapCameraId)(
        UINT32              frameworkCameraId,
        CameraIdRemapMode   mode);
 
    /// @brief Interface to allow various override-specific settings to be toggled.
    UINT32(*CHIModifySettings)(
        VOID*   pPrivateData);
 
    /// @brief Get any vendor tag specific request settings the override wants to get added to the default settings
    VOID (*CHIGetDefaultRequestSettings)(
        UINT32           frameworkCameraId,
        INT              requestTemplate,
        const Metadata** pAdditionalMetadata);
 
    /// @brief Called by the driver to allow for flush()
    INT(*CHIOverrideFlush)(
        const Camera3Device*    pCamera3Device);
    INT(*CHIParallelQuery) (INT num, char* list[]);
    INT(*CHISetCallback) (void*);
 
};
 
typedef VOID(*CHIHALOverrideEntry)(
    CHIAppCallbacks* pCHIAppCallbacks);

  这个结构体是函数指针,映射关系:
  vendor/qcom/proprietary/camx/src/core/hal/camxhal3module.h 中定义了 CHIAppCallbacks m_ChiAppCallbacks;

CHIAppCallbacks       m_ChiAppCallbacks;                    ///< CHI HAL override entry

  vendor/qcom/proprietary/camx/src/core/hal/camxhal3module.cpp 中的 HAL3Module 构造函数中,存在下面的执行语句:

CHIHALOverrideEntry funcCHIHALOverrideEntry =
    reinterpret_cast<CHIHALOverrideEntry>(
        CamX::OsUtils::LibGetAddr(m_hChiOverrideModuleHandle, "chi_hal_override_entry"));
 
if (NULL != funcCHIHALOverrideEntry)
{
    funcCHIHALOverrideEntry(&m_ChiAppCallbacks); //对应到 chxextensioninterface.cpp 中的chi_hal_override_entry函数
 
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIGetNumCameras);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIGetCameraInfo);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIFinalizeOverrideSession);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIInitializeOverrideSession);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIOverrideProcessRequest);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIOverrideFlush);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHITeardownOverrideSession);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIExtendOpen);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIExtendClose);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIRemapCameraId);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIModifySettings);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIParallelQuery);
    CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHISetCallback);
 
    if ((NULL != m_ChiAppCallbacks.CHIGetNumCameras)             &&
        (NULL != m_ChiAppCallbacks.CHIGetCameraInfo)             &&
        (NULL != m_ChiAppCallbacks.CHIFinalizeOverrideSession)   &&
        (NULL != m_ChiAppCallbacks.CHIInitializeOverrideSession) &&
        (NULL != m_ChiAppCallbacks.CHIOverrideProcessRequest)    &&
        (NULL != m_ChiAppCallbacks.CHIOverrideFlush)             &&
        (NULL != m_ChiAppCallbacks.CHITeardownOverrideSession)   &&
        (NULL != m_ChiAppCallbacks.CHIExtendOpen)                &&
        (NULL != m_ChiAppCallbacks.CHIExtendClose)               &&
        (NULL != m_ChiAppCallbacks.CHIRemapCameraId)             &&
        (NULL != m_ChiAppCallbacks.CHIModifySettings)            &&
        (NULL != m_ChiAppCallbacks.CHIParallelQuery)             &&
        (NULL != m_ChiAppCallbacks.CHISetCallback))
    {
        CAMX_LOG_WARN(CamxLogGroupHAL, "CHI Module library function pointers exchanged");
    }
}

  m_ChiAppCallbacks 通过 funcCHIHALOverrideEntry 映射到 chi_hal_override_entry 这个 chi_hal_override_entry 就是指 vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxextensioninterface.cpp 中的 chi_hal_override_entry 函数,如下:

void chi_hal_override_entry(
    chi_hal_callback_ops_t* callbacks)
{
    ExtensionModule* pExtensionModule = ExtensionModule::GetInstance();
 
    CHX_ASSERT(NULL != callbacks);
 
    if (NULL != pExtensionModule)
    {
        callbacks->chi_get_num_cameras              = chi_get_num_cameras;
        callbacks->chi_get_camera_info              = chi_get_camera_info;
        callbacks->chi_initialize_override_session  = chi_initialize_override_session;
        callbacks->chi_finalize_override_session    = chi_finalize_override_session;
        callbacks->chi_override_process_request     = chi_override_process_request;
        callbacks->chi_teardown_override_session    = chi_teardown_override_session;
        callbacks->chi_extend_open                  = chi_extend_open;
        callbacks->chi_extend_close                 = chi_extend_close;
        callbacks->chi_remap_camera_id              = chi_remap_camera_id;
        callbacks->chi_modify_settings              = chi_modify_settings;
        callbacks->chi_get_default_request_settings = chi_get_default_request_settings;
        callbacks->chi_override_flush               = chi_override_flush;
        callbacks->chi_parallelquery                = chi_parallelquery;
        callbacks->chi_setcallback                  = chi_setcallback;
    }
}

  这样就建立了 CHIAppCallbacks 中函数指针的一一映射关系。

  

  vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxextensionmodule.cpp 中的 ExtensionModule::OverrideProcessRequest 函数中执行了 m_pUsecaseFactory->CreateUsecaseObject,如下:

m_pSelectedUsecase[logicalCameraId] =
            m_pUsecaseFactory->CreateUsecaseObject(&m_logicalCameraInfo[logicalCameraId],
                static_cast<UsecaseId>(m_SelectedUsecaseId[logicalCameraId]),
                m_pStreamConfig[logicalCameraId]);

  直接调用到: vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxusecaseutils.cpp 中的 UsecaseFactory::CreateUsecaseObject 函数:

Usecase* UsecaseFactory::CreateUsecaseObject(
    LogicalCameraInfo*              pLogicalCameraInfo,     ///< camera info
    UsecaseId                       usecaseId,              ///< Usecase Id
    camera3_stream_configuration_t* pStreamConfig)          ///< Stream config
{
    Usecase* pUsecase  = NULL;
    UINT     camera0Id = pLogicalCameraInfo->ppDeviceInfo[0]->cameraId;
    CHX_LOG_ERROR("UsecaseFactory::CreateUsecaseObject id = %d", usecaseId);
    switch (usecaseId)
    {
        case UsecaseId::PreviewZSL:
            pUsecase = AdvancedCameraUsecase::Create(pLogicalCameraInfo, pStreamConfig, usecaseId);
            break;
        case UsecaseId::MultiCamera:
            pUsecase = UsecaseMultiCamera::Create(pLogicalCameraInfo, pStreamConfig);
            break;
        case UsecaseId::MultiCameraVR:
            pUsecase = UsecaseMultiVRCamera::Create(pLogicalCameraInfo, pStreamConfig);
            break;
        case UsecaseId::MFNR:
            pUsecase = UsecaseMFNR::Create(camera0Id, pStreamConfig);
            break;
        case UsecaseId::QuadCFA:
            pUsecase = UsecaseQuadCFA::Create(pLogicalCameraInfo, pStreamConfig);
            break;
        case UsecaseId::Torch:
            pUsecase = UsecaseTorch::Create(camera0Id, pStreamConfig);
            break;
        default:
            pUsecase = AdvancedCameraUsecase::Create(pLogicalCameraInfo, pStreamConfig, usecaseId);
            break;
    }
 
    return pUsecase;
}
enum class UsecaseId
{
    NoMatch         = 0,
    Default         = 1,
    Preview         = 2,
    PreviewZSL      = 3,
    MFNR            = 4,
    MFSR            = 5,
    MultiCamera     = 6,
    QuadCFA         = 7,
    RawJPEG         = 8,
    MultiCameraVR   = 9,
    Torch           = 10,
    YUVInBlobOut    = 11,
    MaxUsecases     = 12,
};

  前置摄像头的 UsecaseId 是 PreviewZSL,是单摄,后置摄像头的 UsecaseId 是 MultiCamera,是多摄。

  

 



  camx-usecase

  

  vendor/qcom/proprietary/camx/src/core/chi/camxchi.cpp 中的 ChiEntry 函数如下:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiEntry
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CAMX_VISIBILITY_PUBLIC VOID ChiEntry(
    ChiContextOps* pChiContextOps)
{
    if (NULL != pChiContextOps)
    {
        pChiContextOps->size                       = sizeof(ChiContextOps);
 
        pChiContextOps->majorVersion               = CHI_API_MAJOR_VERSION;
        pChiContextOps->minorVersion               = CHI_API_MINOR_VERSION;
        pChiContextOps->pOpenContext               = CamX::ChiOpenContext;
        pChiContextOps->pCloseContext              = CamX::ChiCloseContext;
        pChiContextOps->pGetNumCameras             = CamX::ChiGetNumCameras;
        pChiContextOps->pGetCameraInfo             = CamX::ChiGetCameraInfo;
        pChiContextOps->pEnumerateSensorModes      = CamX::ChiEnumerateSensorModes;
        pChiContextOps->pCreatePipelineDescriptor  = CamX::ChiCreatePipelineDescriptor;
        pChiContextOps->pDestroyPipelineDescriptor = CamX::ChiDestroyPipelineDescriptor;
        pChiContextOps->pCreateSession             = CamX::ChiCreateSession;
        pChiContextOps->pDestroySession            = CamX::ChiDestroySession;
        pChiContextOps->pFlushSession              = CamX::ChiFlushSession;
        pChiContextOps->pActivatePipeline          = CamX::ChiActivatePipeline;
        pChiContextOps->pDeactivatePipeline        = CamX::ChiDeactivatePipeline;
        pChiContextOps->pSubmitPipelineRequest     = CamX::ChiSubmitPipelineRequest;
        pChiContextOps->pTagOps                    = CamX::ChiGetTagOps;
    }
 
    // This is the workaround for presil HAL3test on Windows
    // On Device, set_camera_metadata_vendor_ops will be call the set the
    // static vendor tag operation in camera_metadata.c
    //
    // On Windows side, theoretically hal3test should mimic what Android framework
    // does and call the set_camera_metadata_vendor_ops function in libcamxext library
    // However, in Windows, if both hal3test.exe and hal.dll link to libcamxext library,
    // there are two different instance of static varibles sit in different memory location.
    // Even if set_camera_metadata_vendor_ops is called in hal3test, when hal try to
    // access to vendor tag ops, it is still not set.
    //
    // This is also a workaround to call vendor tag ops in Chi at GetNumCameras which happens to get called before
    // GetVendorTagOps
    CamX::g_vendorTagOps.get_all_tags     = CamX::ChiGetAllTags;
    CamX::g_vendorTagOps.get_section_name = CamX::ChiGetSectionName;
    CamX::g_vendorTagOps.get_tag_count    = CamX::ChiGetTagCount;
    CamX::g_vendorTagOps.get_tag_name     = CamX::ChiGetTagName;
    CamX::g_vendorTagOps.get_tag_type     = CamX::ChiGetTagType;
 
    set_camera_metadata_vendor_ops(&(CamX::g_vendorTagOps));
}

  这个函数映射关系很重要,也在 camx chi 中比较常见,直接映射在此文件的 CamxChi 类中。都是从 vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxextensionmodule.cpp 中调用过来的。

  下面是预览时 capture request 处理流程图:

  

 check 这段流程的时候我们最关注应该是 5 个重要的处理类型:

    1.UseCase , vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxusecase.h 上面有介绍类图。UseCase 在 camx 中很有很多衍生类,这是 camx 针对不同的 stream 来建立不同的 usecase 对象,用来管理选择 feature,并且创建 pipeline 以及 session。
    2.ChiFeature, vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxfeature.h, usecase 选择相应的 feature,关联一组 pipeline,收到 request 请求,根据 request 选择对应的 feature。
    3.Node , vendro/qcom/propriatary/camx/src/core/camxnode.h ,下面有类图。Node 是 camx 中非常重要的一个父类,是 camx 中处理 camera 请求的一个中间节点,用于处理 pipeline 下发的请求,下面有类图介绍,比较重要 ** 的 Node 子类已经标出来了。
    4.pipeline , 一连串 node 的集合,通过 pipeline 下发给各个 node 处理。
    5.session , 若干个有关联的 pipeline 的集合,用来管理 pipeline,使用 pipeline 处理请求。

 注: Node 节点在 camx chi 架构中至关重要,数据的处理都是通过封装好的 Node 节点来进行的。

  

  camxnode 结构图:

  

  

  node 节点的创建地方在 vendor/qcom/proprietary/camx/src/hwl/titian17x/camxtitian17xfactory.cpp

Node* Titan17xFactory::HwCreateNode(
    const NodeCreateInputData* pCreateInputData,
    NodeCreateOutputData*      pCreateOutputData
    ) const
{
    Node* pNode = NULL;
 
    switch (pCreateInputData->pNodeInfo->nodeId)
    {
        case AutoFocus:
            pNode = AutoFocusNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case BPS:
            pNode = BPSNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case IFE:
            pNode = IFENode::Create(pCreateInputData, pCreateOutputData);
            break;
        case IPE:
            pNode = IPENode::Create(pCreateInputData, pCreateOutputData);
            break;
        case Sensor:
            pNode = SensorNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case StatsProcessing:
            pNode = StatsProcessingNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case JPEG:
            pNode = JPEGEncNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case JPEGAggregator:
            pNode = JPEGAggrNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case StatsParse:
            pNode = StatsParseNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case ChiExternalNode:
            pNode = ChiNodeWrapper::Create(pCreateInputData, pCreateOutputData);
            break;
        case FDHw:
            pNode = FDHwNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case FDManager:
            pNode = FDManagerNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case OfflineStats:
            pNode = OfflineStatsNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case Torch:
            pNode = TorchNode::Create(pCreateInputData, pCreateOutputData);
            break;
        case LRME:
            pNode = LRMENode::Create(pCreateInputData, pCreateOutputData);
            break;
        case RANSAC:
            pNode = RANSACNode::Create(pCreateInputData, pCreateOutputData);
            break;
        default:
            CAMX_ASSERT_ALWAYS_MESSAGE("Unexpected node type");
            break;
    }
 
    return pNode;
}

  

   camx_feature:

  

  在 vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxadvancedcamerausecase.cpp 中的 SelectFeatures (...) 函数中有这些 feature 的创建代码。 

  拍照的场景分为前置和后置,前置是单摄,后置是多摄,前面也有介绍,单摄和多摄使用的 usecase 是不同:

  前置拍照创建的 pipeline 有:

MiuiZSLSnapshotJpeg at index 0 for session 0, session''s pipeline 0, camera id:1
MiuiZSLPreviewRaw at index 1 for session 1, session''s pipeline 0, camera id:1
BinningZSLYuv2Jpeg at index 2 for session 2, session''s pipeline 0, camera id:1
BinningMerge3YuvCustomTo1Yuv at index 3 for session 3, session''s pipeline 0, camera id:1
ZSLSnapshotYUV at index 4 for session 4, session''s pipeline 0, camera id:1
AdvancedAsdMeta at index 5 for session 5, session''s pipeline 0, camera id:1
SWMFClearShotYuv at index 6 for session 6, session''s pipeline 0, camera id:1
BinningZSLSnapshotYUV at index 7 for session 7, session''s pipeline 0, camera id:1

  后置拍照创建的 pipeline 有:

 
BackCameraJpegEncode at index 0 for session 0, session''s pipeline 0, camera id:0
MfnrPrefilter at index 1 for session 0, session''s pipeline 1, camera id:0
MfnrBlend at index 2 for session 0, session''s pipeline 2, camera id:0
MfnrPostFilter at index 3 for session 0, session''s pipeline 3, camera id:0
MfnrScale at index 4 for session 0, session''s pipeline 4, camera id:0
Merge3YuvCustomTo1Yuv at index 5 for session 1, session''s pipeline 0, camera id:0
ZSLSnapshotYUV at index 6 for session 2, session''s pipeline 0, camera id:0
ZSLSnapshotYUVAux at index 7 for session 3, session''s pipeline 0, camera id:3
SWMFSRYuv at index 8 for session 4, session''s pipeline 0, camera id:0
AdvancedAsdMeta at index 9 for session 5, session''s pipeline 0, camera id:0

  pipeline 在 camx 中的配置文件是:vendor/qcom/proprietary/chi-cdk/vendor/topology/default/titan17x_usecases.xml,编译时会根据此 xml 的配置生成对应 vendor\qcom\proprietary\chi-cdk\vendor\chioverride\default\g_pipelines.h,
  vendor\qcom\proprietary\chi-cdk\vendor\chioverride\default\build\android\Android.mk:

...
$(info $(shell perl $(CAMX_CDK_PATH)/topology/usecaseconverter.pl $(CAMX_VENDOR_PATH)/topology/default/titan17x_usecases.xml $(LOCAL_PATH)/g_pipelines.h))
...

   然后在 \vendor\qcom\proprietary\chi-cdk\vendor\chioverride\default\chxusecaseutils.cpp 中会根据 pStreamConfig->num_streams 选择到对应的 Usecases(g_pipelines.h 中定义):

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// UsecaseSelector::DefaultMatchingUsecase
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ChiUsecase* UsecaseSelector::DefaultMatchingUsecase(
    camera3_stream_configuration_t* pStreamConfig)
{
...
  pSelectedUsecase = &pChiTargetUsecases->pChiUsecases[i];
...

}

  DefaultMatchingUsecase 方法即在 \vendor\qcom\proprietary\chi-cdk\vendor\chioverride\default\chxadvancedcamerausecase.cpp 被调用:

CDKResult AdvancedCameraUsecase::SelectUsecaseConfig(
    LogicalCameraInfo*              pCameraInfo,   ///< Camera info
    camera3_stream_configuration_t* pStreamConfig)  ///< Stream configuration
{
...
        m_pChiUsecase = UsecaseSelector::DefaultMatchingUsecase(pStreamConfig);
...
}

 

四、调试:

修改 \vendor\qcom\proprietary\camx\src\core\camxsettings.xml 设置 log 打印级别,如:

overrideLogLevels=0x1F
logInfoMask=0x40080
logVerboseMask=0x40000

 

-end-

Android Automotive types.hal 更改未自动生成

Android Automotive types.hal 更改未自动生成

如何解决Android Automotive types.hal 更改未自动生成

我需要一些关于 types.hal 和 VehiclePropertyIds.java 的信息。 我在 types.hal 中添加了新属性,如下所示,

types.hal 文件更改,

enum ButtonStatus : int32_t {
    ON = 1,OFF = 2
};

/**
 * SunRoofButton
 * @change_mode VehiclePropertyChangeMode:ON_CHANGE
 * @access VehiclePropertyAccess:READ_WRITE
 * @data_enum ButtonStatus
*/
    SunRoof =(
        0x0602
        | VehiclePropertyGroup:vendOR
        | VehiclePropertyType:INT32
        | VehicleArea:SEAT),What should i do next to get these ids generated in **VehiclePropertyId.java**
Currently am doing following 3 steps 

**Commands :** 

. build/envsetup.sh
lunch aosp_car_x86-userdebug
make -j8

By this the build is successful but i don''t see these entries generated in vehiclePropertyIds.java

解决方法

您不应该直接编辑 HAL。

Vehicle HAL 可以通过其他方式扩展:您只需在要使用它的地方将您的 SunRoof 属性定义为一个整数(您可以参考 VehiclePropertyGroup 和其他枚举或只是硬编码 0x25400602 以进行快速和肮脏的测试)。这可能是您的 HAL 实现和面向用户的应用。

但是,请仔细检查是否:

  • 您想将您的天窗按钮与座位区域相关联(每个座位都有自己的天窗按钮吗?)或只是全局区域
  • 您不想重复使用 WINDOW_VENT_POS 或 WINDOW_VENT_MOVE

关于android hal 诠释android haxm的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Android - 硬件抽象层(HAL)、Android 8.0 系统源码分析 --openCamera(HAL)启动过程源码分析、Android : Camera 之 camx hal 架构、Android Automotive types.hal 更改未自动生成等相关知识的信息别忘了在本站进行查找喔。

本文标签: