文章目录

  • 前言
  • 代码流程分析
  • 总结

前言

接上一篇Android R camera Hal启动(上)接着写,把谷歌的代码都分析完成,高通/MTK的代码就不贴了。


代码流程分析

上一篇说到getProviderImpl函数。实例化了CameraProvider对象,先看CameraProvider的构造函数。

template<typename IMPL>
struct CameraProvider : public ICameraProvider {CameraProvider() : impl() {}...
}

调用了impl也就是LegacyCameraProviderImpl_2_4的构造。

LegacyCameraProviderImpl_2_4::LegacyCameraProviderImpl_2_4() :camera_module_callbacks_t({sCameraDeviceStatusChange,sTorchModeStatusChange}) {mInitFailed = initialize();
}

camera_module_callbacks_t是HAL的回调函数,用于通知FW相机状态更新。直接看构造函数调用camera_module_callbacks_t比较奇怪,先看下LegacyCameraProviderImpl_2_4的类的申明和sCameraDeviceStatusChange/sTorchModeStatusChange两个函数的定义就能明白了。

struct LegacyCameraProviderImpl_2_4 : public camera_module_callbacks_t {...
static void sCameraDeviceStatusChange(const struct camera_module_callbacks* callbacks,int camera_id,int new_status);static void sTorchModeStatusChange(const struct camera_module_callbacks* callbacks,const char* camera_id,int new_status);...
}

LegacyCameraProviderImpl_2_4是继承了camera_module_callbacks_t,所以类构造的同时使用sCameraDeviceStatusChange/sTorchModeStatusChange初始化了camera_module_callbacks_t中的camera_device_status_change/torch_mode_status_change函数指针。
camera_module_callbacks_t结构定义如下:

typedef struct camera_module_callbacks {void (*camera_device_status_change)(const struct camera_module_callbacks*,int camera_id,int new_status);void (*torch_mode_status_change)(const struct camera_module_callbacks*,const char* camera_id,int new_status);
} camera_module_callbacks_t;

再继续往下看,调用mInitFailed = initialize();看下initialize的实现:

bool LegacyCameraProviderImpl_2_4::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 characteristicsVendorTagDescriptor::clearGlobalVendorTagDescriptor();if (!setUpVendorTags()) {ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__);}// Setup callback now because we are going to try openLegacy nexterr = mModule->setCallbacks(this);if (err != OK) {ALOGE("Could not set camera module callback: %d (%s)", err, strerror(-err));mModule.clear();return true;}mPreferredHal3MinorVersion =property_get_int32("ro.vendor.camera.wrapper.hal3TrebleMinorVersion", 3);ALOGV("Preferred HAL 3 minor version is %d", mPreferredHal3MinorVersion);switch(mPreferredHal3MinorVersion) {case 2:case 3:// OKbreak;default:ALOGW("Unknown minor camera device HAL version %d in property ""'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3",mPreferredHal3MinorVersion);mPreferredHal3MinorVersion = 3;}mNumberOfLegacyCameras = mModule->getNumberOfCameras();for (int i = 0; i < mNumberOfLegacyCameras; i++) {uint32_t device_version;auto rc = mModule->getCameraDeviceVersion(i, &device_version);if (rc != NO_ERROR) {ALOGE("%s: Camera device version query failed!", __func__);mModule.clear();return true;}if (checkCameraVersion(i, device_version) != 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;addDeviceNames(i);}return false; // mInitFailed
}

先看hw_get_module函数:hardware/libhardware/hardware.c

int hw_get_module(const char *id, const struct hw_module_t **module)
{return hw_get_module_by_class(id, NULL, module);
}int hw_get_module_by_class(const char *class_id, const char *inst,const struct hw_module_t **module)
{int i = 0;char prop[PATH_MAX] = {0};char path[PATH_MAX] = {0};char name[PATH_MAX] = {0};char prop_name[PATH_MAX] = {0};if (inst)snprintf(name, PATH_MAX, "%s.%s", class_id, inst);elsestrlcpy(name, class_id, PATH_MAX);/** Here we rely on the fact that calling dlopen multiple times on* the same .so will simply increment a refcount (and not load* a new copy of the library).* We also assume that dlopen() is thread-safe.*//* First try a property specific to the class and possibly instance */snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);if (property_get(prop_name, prop, NULL) > 0) {if (hw_module_exists(path, sizeof(path), name, prop) == 0) {goto found;}}/* Loop through the configuration variants looking for a module */for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {if (property_get(variant_keys[i], prop, NULL) == 0) {continue;}if (hw_module_exists(path, sizeof(path), name, prop) == 0) {goto found;}}/* Nothing found, try the default */if (hw_module_exists(path, sizeof(path), name, "default") == 0) {goto found;}return -ENOENT;found:/* load the module, if this fails, we're doomed, and we should not try* to load a different variant. */return load(class_id, path, module);
}

hw_get_module会调用hw_get_module_by_class去找到实现HAL的so,class_id的值就是camera。先根据ro.hardware.camera的prop来找,这是没有的,然后就是根据variant_keys的数组查找对应的prop。

static const char *variant_keys[] = {"ro.hardware",  /* This goes first so that it can pick up a differentfile on the emulator. */"ro.product.board","ro.board.platform","ro.arch"
};

高通的平台ro.hardware的值是qcom,因为这个数组中的prop的值get出来之后能找到对应的so,所以就会调用hw_module_exists拼接这个so的完整路径,如果找不到的话就会调用hw_module_exists拼接camera.default.so的全路径,camera.default.so的源码在hardware/libhardware/modules/camera/3_0目录下,平台方会自己实现camera.xxx.so,所以这里可以看成谷歌写的一个demo,如果自己想写一个camera HAL的话,可以参考着写。
再继续看hw_get_module_by_class,通过hw_module_exists拿到全路径之后,继续调用load。

static int load(const char *id,const char *path,const struct hw_module_t **pHmi)
{int status = -EINVAL;void *handle = NULL;struct hw_module_t *hmi = NULL;
#ifdef __ANDROID_VNDK__const bool try_system = false;
#elseconst bool try_system = true;
#endif/** load the symbols resolving undefined symbols before* dlopen returns. Since RTLD_GLOBAL is not or'd in with* RTLD_NOW the external symbols will not be global*/if (try_system &&strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) == 0) {/* If the library is in system partition, no need to check* sphal namespace. Open it with dlopen.*/handle = dlopen(path, RTLD_NOW);} else {#if defined(__ANDROID_RECOVERY__)handle = dlopen(path, RTLD_NOW);
#elsehandle = android_load_sphal_library(path, RTLD_NOW);
#endif}if (handle == NULL) {char const *err_str = dlerror();ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");status = -EINVAL;goto done;}/* Get the address of the struct hal_module_info. */const char *sym = HAL_MODULE_INFO_SYM_AS_STR;hmi = (struct hw_module_t *)dlsym(handle, sym);if (hmi == NULL) {ALOGE("load: couldn't find symbol %s", sym);status = -EINVAL;goto done;}/* Check that the id matches */if (strcmp(id, hmi->id) != 0) {ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);status = -EINVAL;goto done;}hmi->dso = handle;/* success */status = 0;done:if (status != 0) {hmi = NULL;if (handle != NULL) {dlclose(handle);handle = NULL;}} else {ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",id, path, hmi, handle);}*pHmi = hmi;return status;
}

load函数会根据上面传过来的地址通过dlopen打开camera.xxxx.so,这里打开的就是/vendor/lib64/hw/camera.qcom.so。然后再通过HAL_MODULE_INFO_SYM_AS_STR找到对应的符号链接。

#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"

这里为什么要用HMI,自行谷歌搜索,我一开始看到这里也很懵。谷歌搜完了只知道反正就是这么定的,想要用dlsym找到对应的符号,必须要这么写:

camera_module_t HAL_MODULE_INFO_SYM __attribute__ ((visibility("default")))

再用readelf -s camera.xxxx.so可以看到符号表里面有HMI。下面是我拿手机看的符号表:

0000000000802718   344 OBJECT  GLOBAL DEFAULT   23 HMI

既然一定要有camera_module_t HAL_MODULE_INFO_SYM,那就到平台的代码里面找一下。
果然,在平台的代码里面找到了camera_module_t HAL_MODULE_INFO_SYM对应的实现。
到这里就明白了,谷歌只是注册了一个hidl服务,怎么就能调用到平台的代码完成初始化了。
再往下就是平台的具体实现,代码就不贴了,继续回头看bool LegacyCameraProviderImpl_2_4::initialize()函数。
接下来就是初始化module:

mModule = new CameraModule(rawModule);

hardware/interfaces/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.h中定义了:

using ::android::hardware::camera::common::V1_0::helper::CameraModule;

还是和前面一样,先看一下如何使用这个CameraModule的,先看一下hardware/interfaces/camera/common/1.0/default/Android.bp

cc_library_static {name: "android.hardware.camera.common@1.0-helper",vendor_available: true,defaults: ["hidl_defaults"],srcs: ["CameraModule.cpp","CameraMetadata.cpp","CameraParameters.cpp","VendorTagDescriptor.cpp","HandleImporter.cpp","Exif.cpp",],cflags: ["-Werror","-Wextra","-Wall",],shared_libs: ["liblog","libgralloctypes","libhardware","libcamera_metadata","android.hardware.graphics.mapper@2.0","android.hardware.graphics.mapper@3.0","android.hardware.graphics.mapper@4.0","libexif",],include_dirs: ["system/media/private/camera/include"],export_include_dirs: ["include"],
}

cc_library_static说明这是一个静态库,应该直接就link到android.hardware.camera.provider@2.4-impl.so里面了。找了个手机看来一下,果然搜不到这个库,再看一下android.hardware.camera.provider@2.4-impl的编译文件。

cc_library_shared {name: "android.hardware.camera.provider@2.4-impl",...static_libs: ["android.hardware.camera.common@1.0-helper",],...
}

再看CameraModule的构造:

CameraModule::CameraModule(camera_module_t *module) : mNumberOfCameras(0) {if (module == NULL) {ALOGE("%s: camera hardware module must not be null", __FUNCTION__);assert(0);}mModule = module;
}

因为CameraModule就是相机HAL的一个封装,所以初始化就是要保存camera_module_t到mModule。再继续看initialize函数。调用了err = mModule->init();这个实际上就是camera_module_t的init,平台的代码中实现了init,谷歌原生代码并没有实现这部分。再往下就没有什么特殊的代码就是一些初始化,获取属性,最终将camera状态设置成CAMERA_DEVICE_STATUS_PRESENT。initialize函数初始化完成,返回值是false。。。最终这个值给到mInitFailed。
这里的代码看完,再回到hardware/interfaces/camera/provider/2.4/default/CameraProvider_2_4.cpp中,provider初始化完成,调用provider->isInitFailed()检查是不是init成功。

总结

到这里就全部结束了,上面的流程是按照看代码的过程写的,有点乱,好多细节也没有说,不过也算是梳理了整个代码流程。最主要是说明HAL进程如何加载平台so并且关联到平台代码的。

Android R camera Hal启动(下)相关推荐

  1. android R vendor.boot-hal-1-1启动失败问题分析

    记一个android R上开机启动vendor.boot-hal-1-1进程启动失败的过程分析,总结一下下,也给需要的提供个参考. 问题: 在开机启动过程中,一直报错,vendor.boot-hal- ...

  2. android l camera no panorama,Android Camera从App层到framework层到HAL层的初始化过程

    Android camera 从上到下能够分为四个部分: Application层. framework层. HAL(hardware abstract layer)层. Kernel层 通常面向开发 ...

  3. android R启动找不到super分区问题

    总结一个android R打开super动态分区后,init第一阶段启动失败的例子,也为了自己后面看看趟过的坑. 在移植适配android R项目,主要做了如下事情: 打开BOARD_AVB_ENAB ...

  4. Android 4.0.4系统下实现apk的静默安装和启动

    转自http://www.linuxidc.com/Linux/2013-02/79403.htm 未亲测 最近在Android 4.0.4系统下实现apk的静默安装和启动的功能,这里和大家分享一下, ...

  5. android mtk camera startpreview,android8.1 mtk camera hal各种操作流程

    最近一年,一直在做android上的视频编解码和录相.以及camera hal和系统框架这一块.随着做的慢慢的深入,越发觉得mtk的camera hal这一块,有其独到之处.偏偏网上相关的资料却是极少 ...

  6. Android Camera 五 Camera HAL v1

    Android Camera 一 源码路径 Android Camera 二 JNI JAVA和C/CPP图像数据传输流程分析 Android Camera 三 CameraService 和 Cli ...

  7. Android Camera 四 Camera HAL 分析

    Android Camera 一 源码路径 Android Camera 二 JNI JAVA和C/CPP图像数据传输流程分析 Android Camera 三 CameraService 和 Cli ...

  8. android sdk启动不了,windows server 2008下android sdk不能正常启动

    说起这个问题来我就很郁闷,因为这个问题让我白白的损失超过4个G的流量 ,作为在校大学生,这么多的流量可是很让人肉疼的啊(每月总共就10个G的流量,还要看电影.上网啥的,疼啊....),得,闲话少说,入 ...

  9. camera android 黑屏,Android Camera.startPreview()启动未报错,但SurfaceView无画面输出

    问题如标题所示,不知道问题出在那里,能正常出数据,但是画面就是没有,请各位大神指点迷津 代码如下 package com.jiechu.wnd.sl; import android.content.C ...

最新文章

  1. linux stop函数,perfmonctl()函数 Unix/Linux
  2. 为什么要用 redis/为什么要用缓存
  3. 4pics1word android,4 Pics 1 Word
  4. 测试工具之RobotFramework界面基本功能使用
  5. RAID0、1、5、6、10介绍
  6. centeros安装mysql_CenterOS上安装MySQL具体步骤
  7. Jenkins安装后设置,访问http://localhost:8080进入jenkins解锁,完成安装后的配置
  8. 重庆邮电大学801信号与系统考研最核心知识点
  9. 机器码解除教程,逃离塔科夫机器码解除,彩虹6号机器码解除,dayz机器码解除,腐蚀rust机器码解除
  10. win10安装完ubuntu后win10时间改变了 最简单调整方式
  11. 一台电脑控制多部手机怎么实现
  12. 数据结构与算法综合实验——队列实现停车场管理系统
  13. SAP ABAP DUMP GETWA_NOT_ASSIGNED 指针未分配错误
  14. 记录一次并发情况下的redis导致服务假死的问题
  15. libjpeg与turbo libjpeg的使用
  16. 基于Google Earth Engine Explorer谷歌地球引擎GEE浏览界面实现遥感影像地物监督分类
  17. 《量子力学教程》曾谨言著,第二章课后习题作业2.4画图题
  18. UltraEdit 脚本命令
  19. macOS效率操作入门,浅Option键妙用
  20. mysql sleep详解_MySQL中的sleep函数介绍

热门文章

  1. Markdown语法学习笔记(Typora)
  2. html5 li表格纵向合并,vue elementui 表格合并/纵向表头
  3. 控制GPIO接口就可以控制电机了吧?不需要额外硬件吧
  4. C# TCP如何限制单个客户端的访问流量
  5. glibc 知:内容
  6. 《极速蜗牛》渲染时间
  7. ruby sinatra 内部机制(一)
  8. java大学生综合素质测评系统ssm
  9. 读《数据挖掘技术(第三版)》-应用于市场营销,销售与客户关系管理 有感
  10. Android闹钟,Android AlarmManager使用心得