libcamera/src/android/camera_hal_manager.cpp
Laurent Pinchart 53704ac3f4 libcamera: camera_manager: Construct CameraManager instances manually
The CameraManager class is not supposed to be instantiated multiple
times, which led to a singleton implementation. This requires a global
instance of the CameraManager, which is destroyed when the global
destructors are executed.

Relying on global instances causes issues with cleanup, as the order in
which the global destructors are run can't be controlled. In particular,
the Android camera HAL implementation ends up destroying the
CameraHalManager after the CameraManager, which leads to use-after-free
problems.

To solve this, remove the CameraManager::instance() method and make the
CameraManager class instantiable directly. Multiple instances are still
not allowed, and this is enforced by storing the instance pointer
internally to be checked when an instance is created.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
2019-08-19 19:07:45 +03:00

146 lines
3.3 KiB
C++

/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* camera_hal_manager.cpp - libcamera Android Camera Manager
*/
#include "camera_hal_manager.h"
#include <libcamera/camera.h>
#include "log.h"
#include "camera_device.h"
#include "camera_proxy.h"
using namespace libcamera;
LOG_DECLARE_CATEGORY(HAL);
/*
* \class CameraHalManager
*
* The HAL camera manager is initializated at camera_module_t 'hal_init()' time
* and spawns its own thread where libcamera related events are dispatched to.
* It wraps the libcamera CameraManager operations and provides helpers for the
* camera_module_t operations, to retrieve the number of cameras in the system,
* their static information and to open camera devices.
*/
CameraHalManager::~CameraHalManager()
{
if (isRunning()) {
exit(0);
/* \todo Wait with a timeout, just in case. */
wait();
}
}
int CameraHalManager::init()
{
/*
* Start the camera HAL manager thread and wait until its
* initialisation completes to be fully operational before
* receiving calls from the camera stack.
*/
start();
MutexLocker locker(mutex_);
cv_.wait(locker);
return 0;
}
void CameraHalManager::run()
{
/*
* All the libcamera components must be initialised here, in
* order to bind them to the camera HAL manager thread that
* executes the event dispatcher.
*/
cameraManager_ = new CameraManager();
int ret = cameraManager_->start();
if (ret) {
LOG(HAL, Error) << "Failed to start camera manager: "
<< strerror(-ret);
return;
}
/*
* For each Camera registered in the system, a CameraProxy
* gets created here to wraps a camera device.
*
* \todo Support camera hotplug.
*/
unsigned int index = 0;
for (auto &camera : cameraManager_->cameras()) {
CameraProxy *proxy = new CameraProxy(index, camera);
proxies_.emplace_back(proxy);
++index;
}
/*
* libcamera has been initialized. Unlock the init() caller
* as we're now ready to handle calls from the framework.
*/
cv_.notify_one();
/* Now start processing events and messages. */
exec();
/* Clean up the resources we have allocated. */
proxies_.clear();
cameraManager_->stop();
delete cameraManager_;
cameraManager_ = nullptr;
}
CameraProxy *CameraHalManager::open(unsigned int id,
const hw_module_t *hardwareModule)
{
if (id >= numCameras()) {
LOG(HAL, Error) << "Invalid camera id '" << id << "'";
return nullptr;
}
CameraProxy *proxy = proxies_[id].get();
if (proxy->open(hardwareModule))
return nullptr;
LOG(HAL, Info) << "Open camera '" << id << "'";
return proxy;
}
unsigned int CameraHalManager::numCameras() const
{
return cameraManager_->cameras().size();
}
int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)
{
if (!info)
return -EINVAL;
if (id >= numCameras()) {
LOG(HAL, Error) << "Invalid camera id '" << id << "'";
return -EINVAL;
}
CameraProxy *proxy = proxies_[id].get();
/* \todo Get these info dynamically inspecting the camera module. */
info->facing = id ? CAMERA_FACING_FRONT : CAMERA_FACING_BACK;
info->orientation = 0;
info->device_version = 0;
info->resource_cost = 0;
info->static_camera_characteristics = proxy->getStaticMetadata();
info->conflicting_devices = nullptr;
info->conflicting_devices_length = 0;
return 0;
}