Android 13 Camera HAL startup process (2)

Article directory


Welcome to follow the WeChat public account Wuxian

The previous section Android 13 Camera HAL startup process (1) mainly introduces the loading of the [email protected] library and execution of the initialization function of LegacyCameraProviderImpl_2_4 after the CameraProvider process is started. This section continues from the initialization process of LegacyCameraProviderImpl_2_4 Explain below.

// hardware/interfaces/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
LegacyCameraProviderImpl_2_4::LegacyCameraProviderImpl_2_4() :
        camera_module_callbacks_t({
    
    sCameraDeviceStatusChange,
                                   sTorchModeStatusChange}) {
    
    
    mInitFailed = initialize();
}

// initialize()函数的实现
bool LegacyCameraProviderImpl_2_4::initialize() {
    
    
    camera_module_t *rawModule;
    // 1. 通过hw_get_module加载对应的so库,这个库是由厂商提供的,一般只以so库的方式提供,
    // 不过也有情况会提供so库的源码,不过核心的地方还是会封装在别的so库中。
    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;
    }
	// 这里先省略后面的代码,将hw_get_module介绍完后我们再返回来继续
	...
}

Let's start with the hw_get_module function.
The first parameter is CAMERA_HARDWARE_MODULE_ID, where it is defined.
The second parameter is the output parameter.

// hardware/libhardware/include/hardware/camera_common.h
#define CAMERA_HARDWARE_MODULE_ID "camera"
// 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)d_name
{
    
    
    int i = 0;
    char prop[PATH_MAX] = {
    
    0};
    char path[PATH_MAX] = {
    
    0};
    char name[PATH_MAX] = {
    
    0};
    char prop_name[PATH_MAX] = {
    
    0};

	// inst为NULL, 即为false
    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
    	// name 为 “camera”
        strlcpy(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 */
    // 查看ro.hardware.camera属性值是否为空,这个实际上定义了camera hal so库的名称
    // 这个so库是厂商专门封装的so库,这样可以将自己的核心代码保持闭源
    // 最后的标准名称应为path/camera.xxx.so, 这里的xxx就是prop属性值.
    // 对于这个so库,google提供了一个默认实现,
    // 位于hardware/libhardware/modules/camera/3_4, so库名称为camera.v4l2_test
    // 如果这个属性值为空的话,会去判断其他几个属性值,下面的代码会看到
    // 查找路径的话会依次从"/odm/lib64/hw"  "/vendor/lib64/hw"  "/system/lib64/hw"
    // 寻找,一般在"/vendor/lib64/hw"路径,下面的代码就不详细分析了,比较简单。
    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 */
    // 如果ro.hardware.camera属性没有定义,则从如下几个prop中依次查找
	// static const char *variant_keys[] = {
    
    
	//     "ro.hardware",  /* This goes first so that it can pick up a different
	//                        file on the emulator. */
	//     "ro.product.board",
	//     "ro.board.platform",
	//     "ro.arch"
	// };
    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 */
    // 如果以上几个属性均为定义或者对应so库未找到,则判断是否存在camera.default.so是否存在
    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. */
    // 找到对应的so库后,
    return load(class_id, path, module);
}

// 我们接着分析上面找到so库后的load函数,这个函数很重要
/**
 * Load the file defined by the variant and if successful
 * return the dlopen handle and the hmi.
 * @return 0 = success, !0 = failure.
 */
 // 别忘了参数值:
 // id: camera
 // path: 上面找到的路径,假设为 /vendor/lib64/hw/
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;
#else
    const 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.
         */
        //如果位于"/system/lib64/hw",则使用dlopen函数
        handle = dlopen(path, RTLD_NOW);
    } else {
    
    
#if defined(__ANDROID_RECOVERY__)
		// recovery模式的话走这里
        handle = dlopen(path, RTLD_NOW);
#else
		// 非Recovery的话最终走的是这里
        handle = 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;
    }

	// 上面的无非就是load so,拿到handle,接下来就是关键之处了
    /* Get the address of the struct hal_module_info. */
    // HAL_MODULE_INFO_SYM_AS_STR的定义如下
    // #define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
    // 所以sym也为 "HMI”
    // 注意这个值是固定的,是实现hw_get_module实现的一个标准
    // 厂商定义hal的时候,在so库里面必须定义一个结构体名称为“HMI”
    // 这里是调用so库的入口
    // 我们以Google的默认 camera hal so为例看下
	// 这里定义了一个类型为camera_module_t,名称为HAL_MODULE_INFO_SYM的结构体
	// 而HAL_MODULE_INFO_SYM的名称就是 “HMI”
	// 找到这里后会调用该结构体变量的.common.methods.open函数
	// 对应到这里的话就是v4l2_module_methods.open
	// 最终会调用v4l2_camera_hal::open_dev,如下
	// static hw_module_methods_t v4l2_module_methods = {
    
    
	//     .open = v4l2_camera_hal::open_dev};
	// camera_module_t HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
    
    
	//     .common =
	//         {
    
    
	//             .tag = HARDWARE_MODULE_TAG,
	//             .module_api_version = CAMERA_MODULE_API_VERSION_2_4,
	//             .hal_api_version = HARDWARE_HAL_API_VERSION,
	//             .id = CAMERA_HARDWARE_MODULE_ID,
	//             .name = "V4L2 Camera HAL v3",
	//             .author = "The Android Open Source Project",
	//             .methods = &v4l2_module_methods,
	//             .dso = nullptr,
	//             .reserved = {0},
	//         },
	//     .get_number_of_cameras = v4l2_camera_hal::get_number_of_cameras,
	//     .get_camera_info = v4l2_camera_hal::get_camera_info,
	//     .set_callbacks = v4l2_camera_hal::set_callbacks,
	//     .get_vendor_tag_ops = v4l2_camera_hal::get_vendor_tag_ops,
	//     .open_legacy = v4l2_camera_hal::open_legacy,
	//     .set_torch_mode = v4l2_camera_hal::set_torch_mode,
	//     .init = nullptr,
	//     .get_physical_camera_info = nullptr,
	//     .reserved = {nullptr, nullptr}};
    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);
    }

	// 返回hmi,这个是名称为“HMI”的结构体变量在so库中的地址,类型为hw_module_t
	// 但是结构体定义的地方却是camera_module_t类型的,那么这两者有啥关系呢
	// 通过查看定义就知道camera_module_t结构体的第一个成员就是hw_module_t common
	// 这样是为了方便直接调用.common.methods.open函数吧
    *pHmi = hmi;

    return status;
}

// 上面的.common.methods.open函数是so库调用的入口和起点,记住这个是标准定义,如果不这么定义的话,
// hw_get_module就会执行失败,无法加载so库。那么这个open函数主要实现什么功能呢,可能不同厂家实现都不一样,
// 但是有一个是必须的就是遍历camera节点,检查video能力等,我们可以看下Google的默认实现
static int open_dev(const hw_module_t* module,
                    const char* name,
                    hw_device_t** device) {
    
    
  return gCameraHAL.openDevice(module, name, device);
}

// 先看gCameraHAL的构造函数,主要做了以下几件事情
// 1. 遍历/dev/videoX节点
// 2. 尝试open节点并查询video能力
// 3. 构建V4L2Camera对象,放入mCameras
V4L2CameraHAL::V4L2CameraHAL() : mCameras(), mCallbacks(NULL) {
    
    
  HAL_LOG_ENTER();
  // Adds all available V4L2 devices.
  // List /dev nodes.
  DIR* dir = opendir("/dev");
  if (dir == NULL) {
    
    
    HAL_LOGE("Failed to open /dev");
    return;
  }
  // Find /dev/video* nodes.
  dirent* ent;
  std::vector<std::string> nodes;
  // 遍历/dev/video*节点
  while ((ent = readdir(dir))) {
    
    
    std::string desired = "video";
    size_t len = desired.size();
    if (strncmp(desired.c_str(), ent->d_name, len) == 0) {
    
    
      if (strlen(ent->d_name) > len && isdigit(ent->d_name[len])) {
    
    
        // ent is a numbered video node.
        nodes.push_back(std::string("/dev/") + ent->d_name);
        HAL_LOGV("Found video node %s.", nodes.back().c_str());
      }
    }
  }
  // Test each for V4L2 support and uniqueness.
  std::unordered_set<std::string> buses;
  std::string bus;
  v4l2_capability cap;
  int fd;
  int id = 0;
  for (const auto& node : nodes) {
    
    
    // Open the node.
    // 打开节点,拿到fd,用于后面ioctl
    fd = TEMP_FAILURE_RETRY(open(node.c_str(), O_RDWR));
    if (fd < 0) {
    
    
      HAL_LOGE("failed to open %s (%s).", node.c_str(), strerror(errno));
      continue;
    }
    // Read V4L2 capabilities.
    // 查询是否可以作为Camera设备使用
    if (TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_QUERYCAP, &cap)) != 0) {
    
    
      HAL_LOGE(
          "VIDIOC_QUERYCAP on %s fail: %s.", node.c_str(), strerror(errno));
    } else if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
    
    
      HAL_LOGE("%s is not a V4L2 video capture device.", node.c_str());
    } else {
    
    
      // If the node is unique, add a camera for it.
      bus = reinterpret_cast<char*>(cap.bus_info);
      if (buses.insert(bus).second) {
    
    
        HAL_LOGV("Found unique bus at %s.", node.c_str());
        // 构建V4l2Camera对象用于后续作用
        std::unique_ptr<V4L2Camera> cam(V4L2Camera::NewV4L2Camera(id++, node));
        if (cam) {
    
    
          mCameras.push_back(std::move(cam));
        } else {
    
    
          HAL_LOGE("Failed to initialize camera at %s.", node.c_str());
        }
      }
    }
    close(fd);
  }
}

Okay, this section mainly talks about the function implementation of hw_get_module. We will stop here for the startup process of Camera HAL. Of course, it is not over yet. The specific So library is also briefly introduced. When we talk about the CameraServer process startup process later, the CameraProvider process will also be involved, and we will continue then. Regarding the implementation of specific manufacturers' So libraries, we will only introduce the key points (taking Google's default implementation as an example), and will not do in-depth analysis. If there is a chance in the future, we will briefly introduce the Camera HAL implementation of several major platforms (take (Explanation of public information on the Internet), or try to write a complete Camera HAL implementation yourself, which is a story for another time.

Guess you like

Origin blog.csdn.net/weixin_41678668/article/details/130997399