ipa: Look up IPA configurables in configuration file

This patch adds configuration options for environment variables used in
the IPA proxy.

The configuration snippet:

  configuration:
    ipa:
      config_paths:
        - config path 1
        - config path 2
        - ...
      module_paths:
        - module path 1
        - module path 2
        - ...
      proxy_paths:
        - proxy path 1
        - proxy path 2
        - ...
      force_isolation: BOOL

LIBCAMERA_<IPA_NAME>_TUNING_FILE remains configurable only via the
environment variable; this is supposed to be used only for testing and
debugging and it's not clear what to do about IPA names like "rpi/vc4"
and "rpi/pisp" exactly.

There are two ways to pass the configuration to the places where it is
needed: Either to pass it as an argument to the method calls that need
it, or to pass it to the class constructors and extract the needed
configuration from there.  This patch uses the second method as it is
less polluting the code.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Milan Zamazal
2025-09-12 16:29:06 +02:00
committed by Laurent Pinchart
parent 17febd7bb3
commit dcbde32f5e
7 changed files with 67 additions and 53 deletions

View File

@@ -17,6 +17,7 @@
#include <libcamera/ipa/ipa_module_info.h>
#include "libcamera/internal/camera_manager.h"
#include "libcamera/internal/global_configuration.h"
#include "libcamera/internal/ipa_module.h"
#include "libcamera/internal/pipeline_handler.h"
#include "libcamera/internal/pub_key.h"
@@ -28,7 +29,7 @@ LOG_DECLARE_CATEGORY(IPAManager)
class IPAManager
{
public:
IPAManager();
IPAManager(const GlobalConfiguration &configuration);
~IPAManager();
template<typename T>
@@ -42,7 +43,8 @@ public:
if (!m)
return nullptr;
std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m));
const GlobalConfiguration &configuration = cm->_d()->configuration();
std::unique_ptr<T> proxy = std::make_unique<T>(m, !self->isSignatureValid(m), configuration);
if (!proxy->isValid()) {
LOG(IPAManager, Error) << "Failed to load proxy";
return nullptr;
@@ -73,6 +75,7 @@ private:
#if HAVE_IPA_PUBKEY
static const uint8_t publicKeyData_[];
static const PubKey pubKey_;
bool forceIsolation_;
#endif
};

View File

@@ -7,10 +7,14 @@
#pragma once
#include <optional>
#include <string>
#include <vector>
#include <libcamera/ipa/ipa_interface.h>
#include "libcamera/internal/global_configuration.h"
namespace libcamera {
class IPAModule;
@@ -24,7 +28,7 @@ public:
ProxyRunning,
};
IPAProxy(IPAModule *ipam);
IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration);
~IPAProxy();
bool isValid() const { return valid_; }
@@ -40,6 +44,8 @@ protected:
private:
IPAModule *ipam_;
std::vector<std::string> configPaths_;
std::vector<std::string> execPaths_;
};
} /* namespace libcamera */

View File

@@ -41,7 +41,7 @@ LOG_DEFINE_CATEGORY(Camera)
CameraManager::Private::Private()
: initialized_(false)
{
ipaManager_ = std::make_unique<IPAManager>();
ipaManager_ = std::make_unique<IPAManager>(this->configuration());
}
int CameraManager::Private::start()

View File

@@ -10,12 +10,15 @@
#include <algorithm>
#include <dirent.h>
#include <string.h>
#include <string>
#include <sys/types.h>
#include <vector>
#include <libcamera/base/file.h>
#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>
#include "libcamera/internal/global_configuration.h"
#include "libcamera/internal/ipa_module.h"
#include "libcamera/internal/ipa_proxy.h"
#include "libcamera/internal/pipeline_handler.h"
@@ -101,30 +104,37 @@ LOG_DEFINE_CATEGORY(IPAManager)
* The IPAManager class is meant to only be instantiated once, by the
* CameraManager.
*/
IPAManager::IPAManager()
IPAManager::IPAManager(const GlobalConfiguration &configuration)
{
#if HAVE_IPA_PUBKEY
if (!pubKey_.isValid())
LOG(IPAManager, Warning) << "Public key not valid";
char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION");
forceIsolation_ = (force && force[0] != '\0') ||
(!force && configuration.option<bool>({ "ipa", "force_isolation" })
.value_or(false));
#endif
unsigned int ipaCount = 0;
/* User-specified paths take precedence. */
const char *modulePaths = utils::secure_getenv("LIBCAMERA_IPA_MODULE_PATH");
if (modulePaths) {
for (const auto &dir : utils::split(modulePaths, ":")) {
if (dir.empty())
continue;
const auto modulePaths =
configuration.envListOption(
"LIBCAMERA_IPA_MODULE_PATH", { "ipa", "module_paths" })
.value_or(std::vector<std::string>());
for (const auto &dir : modulePaths) {
if (dir.empty())
continue;
ipaCount += addDir(dir.c_str());
}
if (!ipaCount)
LOG(IPAManager, Warning)
<< "No IPA found in '" << modulePaths << "'";
ipaCount += addDir(dir.c_str());
}
if (!modulePaths.empty() && !ipaCount)
LOG(IPAManager, Warning) << "No IPA found in '"
<< utils::join(modulePaths, ":")
<< "'";
/*
* When libcamera is used before it is installed, load IPAs from the
* same build directory as the libcamera library itself.
@@ -279,11 +289,10 @@ IPAModule *IPAManager::module(PipelineHandler *pipe, uint32_t minVersion,
bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const
{
#if HAVE_IPA_PUBKEY
char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION");
if (force && force[0] != '\0') {
if (forceIsolation_) {
LOG(IPAManager, Debug)
<< "Isolation of IPA module " << ipa->path()
<< " forced through environment variable";
<< " forced through configuration";
return false;
}

View File

@@ -7,13 +7,16 @@
#include "libcamera/internal/ipa_proxy.h"
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>
#include "libcamera/internal/global_configuration.h"
#include "libcamera/internal/ipa_module.h"
/**
@@ -27,7 +30,8 @@ LOG_DEFINE_CATEGORY(IPAProxy)
namespace {
std::string ipaConfigurationFile(const std::string &ipaName, const std::string &name)
std::string ipaConfigurationFile(const std::string &ipaName, const std::string &name,
const std::vector<std::string> &configPaths)
{
/*
* Start with any user override through the module-specific environment
@@ -46,21 +50,14 @@ std::string ipaConfigurationFile(const std::string &ipaName, const std::string &
struct stat statbuf;
int ret;
/*
* Check the directory pointed to by the IPA config path environment
* variable next.
*/
const char *confPaths = utils::secure_getenv("LIBCAMERA_IPA_CONFIG_PATH");
if (confPaths) {
for (const auto &dir : utils::split(confPaths, ":")) {
if (dir.empty())
continue;
std::string confPath = dir + "/" + ipaName + "/" + name;
ret = stat(confPath.c_str(), &statbuf);
if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG)
return confPath;
}
/* Check the directory pointed to by the IPA config path next. */
for (const auto &dir : configPaths) {
if (dir.empty())
continue;
std::string confPath = dir + "/" + ipaName + "/" + name;
ret = stat(confPath.c_str(), &statbuf);
if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG)
return confPath;
}
std::string root = utils::libcameraSourcePath();
@@ -120,9 +117,12 @@ std::string ipaConfigurationFile(const std::string &ipaName, const std::string &
/**
* \brief Construct an IPAProxy instance
* \param[in] ipam The IPA module
* \param[in] configuration The global configuration
*/
IPAProxy::IPAProxy(IPAModule *ipam)
: valid_(false), state_(ProxyStopped), ipam_(ipam)
IPAProxy::IPAProxy(IPAModule *ipam, const GlobalConfiguration &configuration)
: valid_(false), state_(ProxyStopped), ipam_(ipam),
configPaths_(configuration.envListOption("LIBCAMERA_IPA_CONFIG_PATH", { "ipa", "config_paths" }).value_or(std::vector<std::string>())),
execPaths_(configuration.envListOption("LIBCAMERA_IPA_PROXY_PATH", { "ipa", "proxy_paths" }).value_or(std::vector<std::string>()))
{
}
@@ -175,7 +175,7 @@ std::string IPAProxy::configurationFile(const std::string &name,
* has been validated when loading the module.
*/
const std::string ipaName = ipam_->info().name;
std::string confPath = ipaConfigurationFile(ipaName, name);
std::string confPath = ipaConfigurationFile(ipaName, name, configPaths_);
if (!confPath.empty()) {
LOG(IPAProxy, Info) << "Using tuning file " << confPath;
return confPath;
@@ -188,7 +188,7 @@ std::string IPAProxy::configurationFile(const std::string &name,
return std::string();
}
confPath = ipaConfigurationFile(ipaName, fallbackName);
confPath = ipaConfigurationFile(ipaName, fallbackName, configPaths_);
LOG(IPAProxy, Warning)
<< "Configuration file '" << name
<< "' not found for IPA module '" << ipaName
@@ -214,18 +214,14 @@ std::string IPAProxy::resolvePath(const std::string &file) const
{
std::string proxyFile = "/" + file;
/* Check env variable first. */
const char *execPaths = utils::secure_getenv("LIBCAMERA_IPA_PROXY_PATH");
if (execPaths) {
for (const auto &dir : utils::split(execPaths, ":")) {
if (dir.empty())
continue;
/* Try paths from the configuration first. */
for (const auto &dir : execPaths_) {
if (dir.empty())
continue;
std::string proxyPath = dir;
proxyPath += proxyFile;
if (!access(proxyPath.c_str(), X_OK))
return proxyPath;
}
std::string proxyPath = dir + proxyFile;
if (!access(proxyPath.c_str(), X_OK))
return proxyPath;
}
/*

View File

@@ -45,8 +45,8 @@ namespace {{ns}} {
{% endfor %}
{%- endif %}
{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate)
: IPAProxy(ipam), isolate_(isolate),
{{proxy_name}}::{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration)
: IPAProxy(ipam, configuration), isolate_(isolate),
controlSerializer_(ControlSerializer::Role::Proxy), seq_(0)
{
LOG(IPAProxy, Debug)

View File

@@ -37,7 +37,7 @@ namespace {{ns}} {
class {{proxy_name}} : public IPAProxy, public {{interface_name}}, public Object
{
public:
{{proxy_name}}(IPAModule *ipam, bool isolate);
{{proxy_name}}(IPAModule *ipam, bool isolate, const GlobalConfiguration &configuration);
~{{proxy_name}}();
{% for method in interface_main.methods %}