From patchwork Tue Jul 9 18:44:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1634 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 52AC061570 for ; Tue, 9 Jul 2019 20:45:01 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EB748596; Tue, 9 Jul 2019 20:44:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562697901; bh=iHO6yueEo51THISUS4htP8k32lxYxqjE7WqxHJ3r2MA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GCPumx3IWJA6+PlcRdGcem+0SiqqSVx3tbfyYYornwlf6Tk3I5dX0wX/zrMUb1lc7 pwfFRN9emOvHdf3mGLo03BbjrogfiSDE4CMOhXjuH3Py1KOqh9weEFfaVa8TNgt3Dz L7gytPvjF8ScSr7LSU6M0NiDLngPfYAsw6rLUVwg= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Jul 2019 03:44:44 +0900 Message-Id: <20190709184450.32023-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190709184450.32023-1-paul.elder@ideasonboard.com> References: <20190709184450.32023-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 1/7] libcamera: ipa_module_info: add license field X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 18:45:01 -0000 Add a field to IPAModuleInfo to contain the license of the module. This license field will be used to determine whether the IPA module should be run in an isolated process or not. If the license is open source, then the IPA module will be allowed to run without process isolation, if the user enables it. If the license is not open source, then the IPA module will be run with process isolation. Update the dummy IPA and IPA test to conform to the new struct layout. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v3: - make license field SPDX New patch in v2 - this replaces the isolate flag that was used in v1 include/libcamera/ipa/ipa_module_info.h | 1 + src/ipa/ipa_dummy.cpp | 1 + src/libcamera/ipa_module.cpp | 21 +++++++++++++++++++++ test/ipa/ipa_test.cpp | 1 + 4 files changed, 24 insertions(+) diff --git a/include/libcamera/ipa/ipa_module_info.h b/include/libcamera/ipa/ipa_module_info.h index 585f753..d9e33c1 100644 --- a/include/libcamera/ipa/ipa_module_info.h +++ b/include/libcamera/ipa/ipa_module_info.h @@ -18,6 +18,7 @@ struct IPAModuleInfo { uint32_t pipelineVersion; char pipelineName[256]; char name[256]; + char license[64]; } __attribute__((packed)); extern "C" { diff --git a/src/ipa/ipa_dummy.cpp b/src/ipa/ipa_dummy.cpp index ee7a3a8..4c8b665 100644 --- a/src/ipa/ipa_dummy.cpp +++ b/src/ipa/ipa_dummy.cpp @@ -34,6 +34,7 @@ const struct IPAModuleInfo ipaModuleInfo = { 0, "PipelineHandlerVimc", "Dummy IPA for Vimc", + "LGPL-2.1-or-later", }; IPAInterface *ipaCreate() diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp index d2e3c36..06111c0 100644 --- a/src/libcamera/ipa_module.cpp +++ b/src/libcamera/ipa_module.cpp @@ -214,6 +214,27 @@ elfLoadSymbol(void *map, size_t soSize, const char *symbol) * * \var IPAModuleInfo::name * \brief The name of the IPA module + * + * \var IPAModuleInfo::license + * \brief License of the IPA module + * + * This license is used to determine whether to isolate the IPA in a + * separate process. If the license is "Proprietary", then the IPA will + * be isolated. The license should be an SPDX license string. The following + * licenses are currently available to allow the IPA to run unisolated: + * + * - GPL-2.0-only + * - GPL-2.0-or-later + * - GPL-3.0-only + * - GPL-3.0-or-later + * - LGPL-2.1-only + * - LGPL-2.1-or-later + * - LGPL-3.0-only + * - LGPL-3.0-or-later + * + * Any other license will cause the IPA to be run isolated. + * + * \todo Allow user to choose to isolated open source IPAs */ /** diff --git a/test/ipa/ipa_test.cpp b/test/ipa/ipa_test.cpp index bbef069..b9e1bd6 100644 --- a/test/ipa/ipa_test.cpp +++ b/test/ipa/ipa_test.cpp @@ -59,6 +59,7 @@ protected: 0, "PipelineHandlerVimc", "Dummy IPA for Vimc", + "GPL-2.0-or-later", }; count += runTest("src/ipa/ipa_dummy.so", testInfo); From patchwork Tue Jul 9 18:44:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1635 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D44D26156F for ; Tue, 9 Jul 2019 20:45:03 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BD0E356A; Tue, 9 Jul 2019 20:45:01 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562697903; bh=Qg6CuD/pEE7itmlpX/1bKzIwRikZQaVBnBVBdryZFKo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LO0JaV50BUYVh2zu1vNS1QS4v/K+WH1UQ7rZaqvxymQarAgy0sHbTp3Pbndy/4JhR yi6NkoC2sbFOuZL/t2txOwaxHxisM3xaoLpyAfT9uL99399teWbOhKbsmsxr2073Km 7aFddsT2AHKc2kSScbCwzmXapAuCzh9BQgsogy4c= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Jul 2019 03:44:45 +0900 Message-Id: <20190709184450.32023-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190709184450.32023-1-paul.elder@ideasonboard.com> References: <20190709184450.32023-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 2/7] libcamera: Add Process and ProcessManager classes X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 18:45:04 -0000 Add a Process class to abstract a process, and a ProcessManager singleton to monitor and manage the processes. Signed-off-by: Paul Elder --- Changes in v3: - add Process test - move ProcessManager header to process.cpp - make Process final - add a bunch of things for monitoring and signals on process termination New in v2 src/libcamera/include/process.h | 61 +++++ src/libcamera/meson.build | 3 + src/libcamera/process.cpp | 359 ++++++++++++++++++++++++++++++ src/libcamera/process_manager.cpp | 0 test/meson.build | 1 + test/process/meson.build | 12 + test/process/process_test.cpp | 95 ++++++++ 7 files changed, 531 insertions(+) create mode 100644 src/libcamera/include/process.h create mode 100644 src/libcamera/process.cpp create mode 100644 src/libcamera/process_manager.cpp create mode 100644 test/process/meson.build create mode 100644 test/process/process_test.cpp diff --git a/src/libcamera/include/process.h b/src/libcamera/include/process.h new file mode 100644 index 0000000..3933f58 --- /dev/null +++ b/src/libcamera/include/process.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process.h - Process object + */ +#ifndef __LIBCAMERA_PROCESS_H__ +#define __LIBCAMERA_PROCESS_H__ + +#include +#include + +#include + +namespace libcamera { + +class Process final +{ +public: + enum ExitStatus { + NotExited, + Exited, + Signaled, + }; + + Process(); + ~Process(); + + int start(const std::string &path, + const std::vector &args = std::vector(), + const std::vector &fds = std::vector()); + + enum ExitStatus exitStatus() const { return exitStatus_; } + + int exitCode() const { return exitCode_; } + + void kill() const; + + Signal finished; + +private: + enum Status { + NotRunning, + Running, + }; + + void closefrom_except(int from, const std::vector &fds); + int isolate(); + void died(int wstatus); + + pid_t pid_; + enum Status status_; + enum ExitStatus exitStatus_; + int exitCode_; + + friend class ProcessManager; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PROCESS_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 97ff86e..a364f68 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -20,6 +20,8 @@ libcamera_sources = files([ 'media_object.cpp', 'object.cpp', 'pipeline_handler.cpp', + 'process.cpp', + 'process_manager.cpp', 'request.cpp', 'signal.cpp', 'stream.cpp', @@ -45,6 +47,7 @@ libcamera_headers = files([ 'include/media_device.h', 'include/media_object.h', 'include/pipeline_handler.h', + 'include/process.h', 'include/utils.h', 'include/v4l2_device.h', 'include/v4l2_subdevice.h', diff --git a/src/libcamera/process.cpp b/src/libcamera/process.cpp new file mode 100644 index 0000000..7df9138 --- /dev/null +++ b/src/libcamera/process.cpp @@ -0,0 +1,359 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process.cpp - Process object + */ + +#include "process.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "log.h" +#include "utils.h" + +/** + * \file process.h + * \brief Process object + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Process) + +/** + * \class ProcessManager + * \brief Manager of processes + * + * The ProcessManager singleton keeps track of all created Process instances, + * and manages the signal handling involved in terminating processes. + */ +class ProcessManager +{ +public: + void registerProcess(Process *proc); + + static ProcessManager *instance(); + + int writePipe() const; + + const struct sigaction &oldsa() const; + +private: + void sighandler(EventNotifier *notifier); + ProcessManager(); + ~ProcessManager(); + + std::list processes_; + + struct sigaction oldsa_; + EventNotifier *sigEvent_; + int pipe_[2]; +}; + +namespace { + +void sigact(int signal, siginfo_t *info, void *ucontext) +{ + char data = 0; + write(ProcessManager::instance()->writePipe(), &data, sizeof(data)); + + struct sigaction oldsa = ProcessManager::instance()->oldsa(); + if (oldsa.sa_flags & SA_SIGINFO) { + oldsa.sa_sigaction(signal, info, ucontext); + } else { + if (oldsa.sa_handler != SIG_IGN && oldsa.sa_handler != SIG_DFL) + oldsa.sa_handler(signal); + } +} + +} /* namespace */ + +void ProcessManager::sighandler(EventNotifier *notifier) +{ + char data; + read(pipe_[0], &data, sizeof(data)); + + for (auto it = processes_.begin(); it != processes_.end(); ) { + Process *process = *it; + + int wstatus; + pid_t pid = waitpid(process->pid_, &wstatus, WNOHANG); + if (process->pid_ != pid) { + ++it; + continue; + } + + it = processes_.erase(it); + process->died(wstatus); + } +} + +/** + * \brief Register process with process manager + * \param[in] proc Process to register + * + * Add \a proc to the process manager to manage. + * + * This method registers the \a proc with the process manager. It + * shall be called by the parent process after successfully forking, in + * order to let the parent signal process termination. + */ +void ProcessManager::registerProcess(Process *proc) +{ + processes_.push_back(proc); +} + +ProcessManager::ProcessManager() +{ + sigaction(SIGCHLD, NULL, &oldsa_); + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = &sigact; + sigset_t mask; + memcpy(&mask, &oldsa_.sa_mask, sizeof(mask)); + sigaddset(&mask, SIGCHLD); + sa.sa_flags = oldsa_.sa_flags | SA_SIGINFO; + + sigaction(SIGCHLD, &sa, NULL); + + pipe2(pipe_, O_CLOEXEC | O_DIRECT | O_NONBLOCK); + sigEvent_ = new EventNotifier(pipe_[0], EventNotifier::Read); + sigEvent_->activated.connect(this, &ProcessManager::sighandler); +} + +ProcessManager::~ProcessManager() +{ + delete sigEvent_; + close(pipe_[0]); + close(pipe_[1]); +} + +/** + * \brief Retrieve the Process manager instance + * + * The ProcessManager is a singleton and can't be constructed manually. This + * method shall instead be used to retrieve the single global instance of the + * manager. + * + * \return The Process manager instance + */ +ProcessManager *ProcessManager::instance() +{ + static ProcessManager processManager; + return &processManager; +} + +/** + * \brief Retrieve the Process manager's write pipe + * + * This method is meant only to be used by the static signal handler. + * + * \return Pipe for writing + */ +int ProcessManager::writePipe() const +{ + return pipe_[1]; +} + +/** + * \brief Retrive the old signal action data + * + * This method is meant only to be used by the static signal handler. + * + * \return The old signal action data + */ +const struct sigaction &ProcessManager::oldsa() const +{ + return oldsa_; +} + + +/** + * \class Process + * \brief Process object + * + * The Process class models a process, and simplifies spawning new processes + * and monitoring the exiting of a process. + */ + +/** + * \enum Process::ExitStatus + * \brief Exit status of process + * \var Process::NotExited + * The process hasn't exited yet. + * \var Process::Exited + * The process exited normally, either via exit() or returning from main. + * \var Process::Signaled + * The process was terminated by signal. + */ + +Process::Process() + : pid_(-1), status_(NotRunning), exitStatus_(NotExited), exitCode_(0) +{ +} + +Process::~Process() +{ + kill(); + /* \todo wait for child process to exit */ +} + +/** + * \brief Fork and exec a process, and close fds + * \param[in] path Path to executable + * \param[in] args Arguments to pass to executable (optional) + * \param[in] fds Vector of file descriptors to keep open (optional) + * + * Fork a process, and exec the executable specified by path. Prior to + * exec'ing, but after forking, all file descriptors except for those + * specified in fds will be closed. + * + * All indexes of args will be incremented by 1 before being fed to exec(), + * so args[0] should not need to be equal to path. + * + * \return zero on successful fork, exec, and closing the file descriptors, + * or a negative error code otherwise + */ +int Process::start(const std::string &path, + const std::vector &args, + const std::vector &fds) +{ + int ret; + + if (status_ == Running) + return 0; + + int childPid = fork(); + if (childPid == -1) { + ret = errno; + LOG(Process, Error) << "Failed to fork: " << strerror(ret); + return ret; + } else if (childPid) { + pid_ = childPid; + ProcessManager::instance()->registerProcess(this); + + status_ = Running; + + return 0; + } else { + if (isolate()) + _exit(EXIT_FAILURE); + + closefrom_except(0, fds); + + const char **argv = new const char *[args.size() + 2]; + unsigned int len = args.size(); + argv[0] = path.c_str(); + for (unsigned int i = 0; i < len; i++) + argv[i+1] = args[i].c_str(); + argv[len+1] = nullptr; + + execv(path.c_str(), (char **)argv); + + exit(EXIT_FAILURE); + } +} + +void Process::closefrom_except(int from, const std::vector &fds) +{ + std::vector v(fds); + sort(v.begin(), v.end()); + + DIR *dir = opendir("/proc/self/fd"); + if (!dir) + return; + + int dfd = dirfd(dir); + + struct dirent *ent; + while ((ent = readdir(dir)) != nullptr) { + char *endp; + int fd = strtoul(ent->d_name, &endp, 10); + if (*endp) + continue; + + if (fd >= from && fd != dfd && + !std::binary_search(v.begin(), v.end(), fd)) + close(fd); + } + + closedir(dir); +} + +int Process::isolate() +{ + return unshare(CLONE_NEWUSER | CLONE_NEWNET); +} + +/* + * \brief SIGCHLD handler + * \param[in] wstatus The status as output by waitpid() + * + * This method is called when the process associated with Process terminates. + * Emits the Process::finished signal. + */ +void Process::died(int wstatus) +{ + status_ = NotRunning; + exitStatus_ = WIFEXITED(wstatus) ? Exited : Signaled; + exitCode_ = exitStatus_ == Exited ? WEXITSTATUS(wstatus) : -1; + + finished.emit(this, exitStatus_, exitCode_); +} + +/** + * \fn Process::exitStatus() + * \brief Return the exit status of the process + * + * Return the exit status of the process, that is, whether the process + * has exited via exit() or returning from main, or if the process was + * exited by signaling. + * + * \sa ExitStatus + * + * \return Exit status + */ + +/** + * \fn Process::exitCode() + * \brief Return the exit code of the process + * + * Return the exit code of the process. + * + * This method is only valid if exitStatus() returned Exited. + * + * \return Exit code + */ + +/** + * \var Process::finished + * + * Signal that is emitted when the process is confirmed to have terminated. + */ + +/** + * \brief Kill the process + * + * Sends SIGKILL to the process. + */ +void Process::kill() const +{ + ::kill(pid_, SIGKILL); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/process_manager.cpp b/src/libcamera/process_manager.cpp new file mode 100644 index 0000000..e69de29 diff --git a/test/meson.build b/test/meson.build index 41b54ff..045e95a 100644 --- a/test/meson.build +++ b/test/meson.build @@ -6,6 +6,7 @@ subdir('ipa') subdir('ipc') subdir('media_device') subdir('pipeline') +subdir('process') subdir('stream') subdir('v4l2_subdevice') subdir('v4l2_videodevice') diff --git a/test/process/meson.build b/test/process/meson.build new file mode 100644 index 0000000..c4d83d6 --- /dev/null +++ b/test/process/meson.build @@ -0,0 +1,12 @@ +process_tests = [ + [ 'process_test', 'process_test.cpp' ], +] + +foreach t : process_tests + exe = executable(t[0], t[1], + dependencies : libcamera_dep, + link_with : test_libraries, + include_directories : test_includes_internal) + + test(t[0], exe, suite : 'process', is_parallel : false) +endforeach diff --git a/test/process/process_test.cpp b/test/process/process_test.cpp new file mode 100644 index 0000000..39f77c1 --- /dev/null +++ b/test/process/process_test.cpp @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process_test.cpp - Process test + */ + +#include +#include +#include + +#include +#include +#include + +#include "process.h" +#include "test.h" +#include "utils.h" + +using namespace std; +using namespace libcamera; + +class ProcessTestChild +{ +public: + int run(int status) + { + usleep(2000); + + return status; + } +}; + +class ProcessTest : public Test +{ +public: + ProcessTest() + : actualExitCode_(-1) + { + } + +protected: + int init() + { + return 0; + } + + int run() + { + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + Timer timeout; + + exitCode_ = 42; + vector args; + args.push_back(to_string(exitCode_)); + int ret = proc_.start("/proc/self/exe", args); + if (ret) + return TestFail; + proc_.finished.connect(this, &ProcessTest::procFinished); + + timeout.start(6); + while (timeout.isRunning()) + dispatcher->processEvents(); + + if (exitCode_ != actualExitCode_) + cout << "exit code should be " << exitCode_ << ", actual is " << actualExitCode_ << endl; + return exitCode_ == actualExitCode_ ? TestPass : TestFail; + } + +private: + void procFinished(Process *proc, enum Process::ExitStatus exitStatus, int exitCode) + { + if (exitStatus == Process::Exited) + actualExitCode_ = exitCode; + } + + Process proc_; + int exitCode_; + int actualExitCode_; +}; + +/* + * Can't use TEST_REGISTER() as single binary needs to act as both + * parent and child processes. + */ +int main(int argc, char **argv) +{ + if (argc == 2) { + int status = std::stoi(argv[1]); + ProcessTestChild child; + return child.run(status); + } + + return ProcessTest().execute(); +} From patchwork Tue Jul 9 18:44:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1636 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 98A6861579 for ; Tue, 9 Jul 2019 20:45:05 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2A7AB56A; Tue, 9 Jul 2019 20:45:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562697905; bh=HCqlVuA8zghTuSjYYnrXwlNrnxDwUOjY6G1PyrTJlK8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bkljesfqTBWcmHxSXM1zhVqaDmE37kOI9Zsj6LzKj8i/Gt2xWSSIXweU6xVS9fGIn Duisob+kgufeSJ0p6COG6F6YM1qo1EhU3W+FSI2d2HQ+dD+nAKa3F6exxtNiQ6rcpm aijuMGXMii4WMe67yXdt0RjPwl1A9xZhudsfmPK4= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Jul 2019 03:44:46 +0900 Message-Id: <20190709184450.32023-4-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190709184450.32023-1-paul.elder@ideasonboard.com> References: <20190709184450.32023-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 3/7] libcamera: add IPA proxy X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 18:45:05 -0000 Add an IPAProxy class whose implementations will act as a proxy between a pipeline handler and an isolated IPA interface. Also add an IPAProxyFactory that will construct the Proxy implementations as necessary. Update Doxygen to ignore the directory where Proxy implementations will reside. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v3: - renamed Proxy and ProxyFactory to IPAProxy and IPAProxyFactory - moved proxy workers to proxy/worker/ (from proxy_worker/) New in v2 - replaces shims from v1 - build into libcamera, hence the register macro (similar to what PipelineHandler uses) - no longer builds separate .so Documentation/Doxyfile.in | 3 +- src/libcamera/include/ipa_proxy.h | 66 ++++++++++ src/libcamera/ipa_proxy.cpp | 204 ++++++++++++++++++++++++++++++ src/libcamera/meson.build | 6 + test/libtest/test.cpp | 4 + 5 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 src/libcamera/include/ipa_proxy.h create mode 100644 src/libcamera/ipa_proxy.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index cad85ff..3d94623 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -837,7 +837,8 @@ EXCLUDE = @TOP_SRCDIR@/src/libcamera/device_enumerator_sysfs.cpp @TOP_SRCDIR@/src/libcamera/device_enumerator_udev.cpp \ @TOP_SRCDIR@/src/libcamera/include/device_enumerator_sysfs.h \ @TOP_SRCDIR@/src/libcamera/include/device_enumerator_udev.h \ - @TOP_SRCDIR@/src/libcamera/pipeline/ + @TOP_SRCDIR@/src/libcamera/pipeline/ \ + @TOP_SRCDIR@/src/libcamera/proxy/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/src/libcamera/include/ipa_proxy.h b/src/libcamera/include/ipa_proxy.h new file mode 100644 index 0000000..c76d917 --- /dev/null +++ b/src/libcamera/include/ipa_proxy.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy.h - Image Processing Algorithm proxy + */ +#ifndef __LIBCAMERA_IPA_PROXY_H__ +#define __LIBCAMERA_IPA_PROXY_H__ + +#include +#include +#include + +#include + +#include "ipa_module.h" +#include "utils.h" + +namespace libcamera { + +class IPAProxy : public IPAInterface +{ +public: + IPAProxy(); + ~IPAProxy(); + + bool isValid() const { return valid_; } + +protected: + std::string resolvePath(const std::string &file) const; + + bool valid_; +}; + +class IPAProxyFactory +{ +public: + IPAProxyFactory(const char *name); + virtual ~IPAProxyFactory() { }; + + virtual std::unique_ptr create(IPAModule *ipam) = 0; + + const std::string &name() const { return name_; } + + static void registerType(IPAProxyFactory *factory); + static std::vector &factories(); + +private: + std::string name_; +}; + +#define REGISTER_IPA_PROXY(proxy) \ +class proxy##Factory final : public IPAProxyFactory \ +{ \ +public: \ + proxy##Factory() : IPAProxyFactory(#proxy) {} \ + std::unique_ptr create(IPAModule *ipam) \ + { \ + return utils::make_unique(ipam); \ + } \ +}; \ +static proxy##Factory global_##proxy##Factory; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_PROXY_H__ */ diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp new file mode 100644 index 0000000..1f6a8a0 --- /dev/null +++ b/src/libcamera/ipa_proxy.cpp @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy.cpp - Image Processing Algorithm proxy + */ + +#include "ipa_proxy.h" + +#include +#include + +#include "log.h" +#include "utils.h" + +#include + +/** + * \file ipa_proxy.h + * \brief IPA Proxy + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(IPAProxy) + +/** + * \class IPAProxy + * \brief IPA Proxy + * + * Isolate IPA into separate process. + * + * Every subclass of proxy shall be registered with libcamera using + * the REGISTER_IPA_PROXY() macro. + */ + +/** + * \brief Construct an IPAProxy instance + * + * IPAProxy instances shall be constructed through the IPAProxyFactory::create() + * method implemented by the respective factories. + */ +IPAProxy::IPAProxy() + : valid_(false) +{ +} + +IPAProxy::~IPAProxy() +{ +} + +/** + * \fn IPAProxy::isValid() + * \brief Check if the IPAProxy instance is valid + * + * An IPAProxy instance is valid if the IPA interface is successfully created in + * isolation, and IPC is successfully set up. + * + * \return True if the IPAProxy is valid, false otherwise + */ + +/** + * \brief Find a valid full path for a proxy worker for a given executable name + * \param[in] file File name of proxy worker executable + * + * A proxy worker's executable could be found in either the global installation + * directory, or in the paths specified by the environment variable + * LIBCAMERA_IPA_PROXY_PATH. This method checks the global install directory + * first, then LIBCAMERA_IPA_PROXY_PATH in order, and returns the full path to + * the proxy worker executable that is specified by file. The proxy worker + * executable shall have exec permission. + * + * \return The full path to the proxy worker executable, or empty string if + * no valid executable path + */ +std::string IPAProxy::resolvePath(const std::string &file) const +{ + /* Try finding the exec target from the install directory first */ + std::string proxyFile = "/" + file; + std::string proxyPath = std::string(IPA_PROXY_DIR) + proxyFile; + if (!access(proxyPath.c_str(), X_OK)) + return proxyPath; + + /* No exec target in install directory; check env variable. */ + const char *execPaths = utils::secure_getenv("LIBCAMERA_IPA_PROXY_PATH"); + while (execPaths) { + const char *delim = strchrnul(execPaths, ':'); + size_t count = delim - execPaths; + + if (count) { + std::string proxyPath(execPaths, count); + proxyPath += proxyFile; + if (!access(proxyPath.c_str(), X_OK)) + return proxyPath; + } + + if (*delim == '\0') + break; + + execPaths += count + 1; + } + + return std::string(); +} + +/** + * \var IPAProxy::valid_ + * \brief Flag to indicate if the IPAProxy instance is valid + * + * A IPAProxy instance is valid if the IPA interface is successfully created in + * isolation, and IPC is successfully set up. + * + * This flag can be read via IPAProxy::isValid() + * + * Implementations of the IPAProxy class should set this flag upon successful + * construction. + */ + +/** + * \class IPAProxyFactory + * \brief Registration of IPAProxy classes and creation of instances + * + * To facilitate discovery and instantiation of IPAProxy classes, the + * IPAProxyFactory class maintains a registry of IPAProxy classes. Each + * IPAProxy subclass shall register itself using the REGISTER_IPA_PROXY() + * macro, which will create a corresponding instance of a IPAProxyFactory + * subclass and register it with the static list of factories. + */ + +/** + * \brief Construct a IPAProxy factory + * \param[in] name Name of the IPAProxy class + * + * Creating an instance of the factory registers is with the global list of + * factories, accessible through the factories() function. + * + * The factory \a name is used for debugging and IPAProxy matching purposes + * and shall be unique. + */ +IPAProxyFactory::IPAProxyFactory(const char *name) + : name_(name) +{ + registerType(this); +} + +/** + * \fn IPAProxyFactory::create() + * \brief Create an instance of the IPAProxy corresponding to the factory + * \param[in] ipam The IPA module + * + * This virtual function is implemented by the REGISTER_IPA_PROXY() macro. + * It creates a IPAProxy instance that isolates an IPA interface designated + * by the IPA module \a ipam. + * + * \return a pointer to a newly constructed instance of the IPAProxy subclass + * corresponding to the factory + */ + +/** + * \fn IPAProxyFactory::name() + * \brief Retrieve the factory name + * \return The factory name + */ + +/** + * \brief Add a IPAProxy class to the registry + * \param[in] factory Factory to use to construct the IPAProxy + * + * The caller is responsible to guarantee the uniqueness of the IPAProxy name. + */ +void IPAProxyFactory::registerType(IPAProxyFactory *factory) +{ + std::vector &factories = IPAProxyFactory::factories(); + + factories.push_back(factory); + + LOG(IPAProxy, Debug) + << "Registered proxy \"" << factory->name() << "\""; +} + +/** + * \brief Retrieve the list of all IPAProxy factories + * + * The static factories map is defined inside the function to ensure it gets + * initialized on first use, without any dependency on link order. + * + * \return the list of pipeline handler factories + */ +std::vector &IPAProxyFactory::factories() +{ + static std::vector factories; + return factories; +} + +/** + * \def REGISTER_IPA_PROXY + * \brief Register a IPAProxy with the IPAProxy factory + * \param[in] proxy Class name of IPAProxy derived class to register + * + * Register a proxy subclass with the factory and make it available to + * isolate IPA modules. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index a364f68..73a6fc7 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -14,6 +14,7 @@ libcamera_sources = files([ 'ipa_interface.cpp', 'ipa_manager.cpp', 'ipa_module.cpp', + 'ipa_proxy.cpp', 'ipc_unixsocket.cpp', 'log.cpp', 'media_device.cpp', @@ -42,6 +43,7 @@ libcamera_headers = files([ 'include/formats.h', 'include/ipa_manager.h', 'include/ipa_module.h', + 'include/ipa_proxy.h', 'include/ipc_unixsocket.h', 'include/log.h', 'include/media_device.h', @@ -63,6 +65,10 @@ includes = [ subdir('pipeline') +proxy_install_dir = join_paths(get_option('libdir'), 'libcamera', 'proxy') +config_h.set('IPA_PROXY_DIR', + '"' + join_paths(get_option('prefix'), proxy_install_dir) + '"') + libudev = dependency('libudev', required : false) if libudev.found() diff --git a/test/libtest/test.cpp b/test/libtest/test.cpp index b119cf1..333d216 100644 --- a/test/libtest/test.cpp +++ b/test/libtest/test.cpp @@ -25,6 +25,10 @@ int Test::execute() if (ret) return errno; + ret = setenv("LIBCAMERA_IPA_PROXY_PATH", "src/libcamera/proxy/worker", 1); + if (ret) + return errno; + ret = init(); if (ret) return ret; From patchwork Tue Jul 9 18:44:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1637 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7F97761577 for ; Tue, 9 Jul 2019 20:45:07 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0382D56A; Tue, 9 Jul 2019 20:45:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562697907; bh=t54uBJ1gYUlyKdE0Dt1Ip77xedGW72MuUmx/KSnpPpI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ig8icIOt10YQVEK/P81oGdcs9zQCgVnicnM1JUT/zdU+u0fQ/zYHh/1YhMHkyvIgB IWSgAVWMxEDpebUe00qqyf/DMoQYdggThjS2z267Ttu2An+7xbucnApieif5IuHybK 3fVbUo6Wk+3KtOK9FOU5jEdHBynF3VTKWJlN9t40= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Jul 2019 03:44:47 +0900 Message-Id: <20190709184450.32023-5-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190709184450.32023-1-paul.elder@ideasonboard.com> References: <20190709184450.32023-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 4/7] libcamera: proxy: add default linux IPA proxy X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 18:45:07 -0000 Add a skeletal default linux IPA proxy. It currently lacks the IPA proxy protocol itself. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v3: - better logging (both main proxy and proxy worker) - renamed ProxyLinuxDefault to IPAProxyLinux - initialize listeners for IPC New in v2 - replaces the dummy/linux default shim src/libcamera/meson.build | 7 +- src/libcamera/proxy/ipa_proxy_linux.cpp | 96 +++++++++++++++++++ src/libcamera/proxy/meson.build | 3 + .../proxy/worker/ipa_proxy_linux_worker.cpp | 89 +++++++++++++++++ src/libcamera/proxy/worker/meson.build | 16 ++++ 5 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 src/libcamera/proxy/ipa_proxy_linux.cpp create mode 100644 src/libcamera/proxy/meson.build create mode 100644 src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp create mode 100644 src/libcamera/proxy/worker/meson.build diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 73a6fc7..57238fe 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -64,10 +64,7 @@ includes = [ ] subdir('pipeline') - -proxy_install_dir = join_paths(get_option('libdir'), 'libcamera', 'proxy') -config_h.set('IPA_PROXY_DIR', - '"' + join_paths(get_option('prefix'), proxy_install_dir) + '"') +subdir('proxy') libudev = dependency('libudev', required : false) @@ -111,3 +108,5 @@ libcamera = shared_library('camera', libcamera_dep = declare_dependency(sources : [libcamera_api, libcamera_h], include_directories : libcamera_includes, link_with : libcamera) + +subdir('proxy/worker') diff --git a/src/libcamera/proxy/ipa_proxy_linux.cpp b/src/libcamera/proxy/ipa_proxy_linux.cpp new file mode 100644 index 0000000..1f982f7 --- /dev/null +++ b/src/libcamera/proxy/ipa_proxy_linux.cpp @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy_linux.cpp - Default Image Processing Algorithm proxy for Linux + */ + +#include + +#include +#include + +#include "ipa_module.h" +#include "ipa_proxy.h" +#include "ipc_unixsocket.h" +#include "log.h" +#include "process.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(IPAProxy) + +class IPAProxyLinux : public IPAProxy +{ +public: + IPAProxyLinux(IPAModule *ipam); + ~IPAProxyLinux(); + + int init(); + +private: + void readyRead(IPCUnixSocket *ipc); + + Process *proc_; + + IPCUnixSocket *socket_; +}; + +int IPAProxyLinux::init() +{ + LOG(IPAProxy, Debug) << "initializing IPA via dummy proxy!"; + + return 0; +} + +IPAProxyLinux::IPAProxyLinux(IPAModule *ipam) +{ + LOG(IPAProxy, Debug) + << "initializing dummy proxy: loading IPA from " + << ipam->path(); + + std::vector fds; + std::vector args; + args.push_back(ipam->path()); + const std::string path = resolvePath("ipa_proxy_linux"); + if (path.empty()) { + LOG(IPAProxy, Error) + << "Failed to get IPAProxyLinux worker path"; + return; + } + + socket_ = new IPCUnixSocket(); + int fd = socket_->create(); + if (fd < 0) { + LOG(IPAProxy, Error) + << "Failed to create socket for IPAProxyLinux"; + return; + } + args.push_back(std::to_string(fd)); + fds.push_back(fd); + + proc_ = new Process(); + int ret = proc_->start(path, args, fds); + if (ret) { + LOG(IPAProxy, Error) + << "Failed to start IPAProxyLinux worker process"; + return; + } + socket_->readyRead.connect(this, &IPAProxyLinux::readyRead); + + valid_ = true; +} + +IPAProxyLinux::~IPAProxyLinux() +{ + delete proc_; + delete socket_; +} + +void IPAProxyLinux::readyRead(IPCUnixSocket *ipc) +{ +} + +REGISTER_IPA_PROXY(IPAProxyLinux) + +}; /* namespace libcamera */ diff --git a/src/libcamera/proxy/meson.build b/src/libcamera/proxy/meson.build new file mode 100644 index 0000000..efc1132 --- /dev/null +++ b/src/libcamera/proxy/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'ipa_proxy_linux.cpp', +]) diff --git a/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp b/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp new file mode 100644 index 0000000..adf4511 --- /dev/null +++ b/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy_linux_worker.cpp - Default Image Processing Algorithm proxy worker for Linux + */ + +#include +#include +#include + +#include +#include +#include + +#include "ipa_module.h" +#include "ipc_unixsocket.h" +#include "log.h" +#include "utils.h" + +using namespace libcamera; + +LOG_DEFINE_CATEGORY(IPAProxyLinuxWorker) + +void readyRead(IPCUnixSocket *ipc) +{ + IPCUnixSocket::Payload message; + int ret; + + ret = ipc->receive(&message); + if (ret) { + LOG(IPAProxyLinuxWorker, Error) + << "Receive message failed: " << ret; + return; + } + + LOG(IPAProxyLinuxWorker, Debug) << "Received a message!"; +} + +int main(int argc, char **argv) +{ + std::string logPath = "/tmp/libcamera.worker." + std::to_string(getpid()) + ".log"; + int ret = setenv("LIBCAMERA_LOG_FILE", logPath.c_str(), 1); + if (ret < 0) { + ret = errno; + std::cerr << "Failed to read log file env variable" << std::endl; + return ret; + } + + if (argc < 3) { + LOG(IPAProxyLinuxWorker, Debug) + << "Tried to start worker with no args"; + return EXIT_FAILURE; + } + + int fd = std::stoi(argv[2]); + LOG(IPAProxyLinuxWorker, Debug) + << "Starting worker for IPA module " << argv[1] + << " with IPC fd = " << fd; + + std::unique_ptr ipam = utils::make_unique(argv[1]); + if (!ipam->isValid() || !ipam->load()) { + LOG(IPAProxyLinuxWorker, Error) + << "IPAModule " << argv[1] << " should be valid but isn't"; + return EXIT_FAILURE; + } + + IPCUnixSocket socket; + if (socket.bind(fd) < 0) { + LOG(IPAProxyLinuxWorker, Error) << "IPC socket binding failed"; + return EXIT_FAILURE; + } + socket.readyRead.connect(&readyRead); + + std::unique_ptr ipa = ipam->createInstance(); + if (!ipa) { + LOG(IPAProxyLinuxWorker, Error) << "Failed to create IPA interface"; + return EXIT_FAILURE; + } + + LOG(IPAProxyLinuxWorker, Debug) << "Proxy worker successfully started!"; + + /* TODO upgrade listening loop */ + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + while (1) + dispatcher->processEvents(); + + return 0; +} diff --git a/src/libcamera/proxy/worker/meson.build b/src/libcamera/proxy/worker/meson.build new file mode 100644 index 0000000..839156f --- /dev/null +++ b/src/libcamera/proxy/worker/meson.build @@ -0,0 +1,16 @@ +ipa_proxy_sources = [ + ['ipa_proxy_linux', 'ipa_proxy_linux_worker.cpp'] +] + +proxy_install_dir = join_paths(get_option('libexecdir'), 'libcamera') + +foreach t : ipa_proxy_sources + proxy = executable(t[0], t[1], + include_directories : libcamera_internal_includes, + install : true, + install_dir : proxy_install_dir, + dependencies : libcamera_dep) +endforeach + +config_h.set('IPA_PROXY_DIR', + '"' + join_paths(get_option('prefix'), proxy_install_dir) + '"') From patchwork Tue Jul 9 18:44:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1638 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5044061577 for ; Tue, 9 Jul 2019 20:45:09 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E403156A; Tue, 9 Jul 2019 20:45:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562697909; bh=clAf1sOjKATueylO+rV1uTb7i57z0xw/jFrkspTu7v0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VyfEmqiRqyLZ2v/TdqWARHKUjwX6I0urbGAklMdIz3yRmW6jcd+Ahm2zVuzLhL9/D uszwwi3/jTx10apcbVZq3xiTaKya99ULuPpUus+NtCUFnRPdnG+0aPkrxgP3IVL3HQ JTootucByEvfWLjtaimqv+/tf5+A684KAE37R75I= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Jul 2019 03:44:48 +0900 Message-Id: <20190709184450.32023-6-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190709184450.32023-1-paul.elder@ideasonboard.com> References: <20190709184450.32023-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 5/7] libcamera: ipa_manager: use proxy X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 18:45:09 -0000 Make IPAManager isolate an IPA in a Proxy if the IPA's license is not open source, before returning the IPA to the caller. For now, only use the default Linux IPA proxy, and only LGPL 2.1+ is considered open source. Signed-off-by: Paul Elder --- Changes in v3: - license checking is done with SPDX license strings, and only LGPL 2.1+ is accepted for now New in v2 - replaces adding shims - since Proxies are not external shared objects like the shims in v1 were, there is no longer a list of shims that is treated like IPAModules - instead the matching is done by searching the list of proxy factories src/libcamera/ipa_manager.cpp | 46 +++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 532b77d..49a12ca 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -14,6 +14,7 @@ #include "ipa_module.h" #include "log.h" #include "pipeline_handler.h" +#include "ipa_proxy.h" #include "utils.h" /** @@ -25,6 +26,18 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPAManager) +namespace { + +bool isOpenSource(const char *license) +{ + if (!strcmp(license, "LGPL-2.1-or-later")) + return true; + + return false; +} + +} /* namespace */ + /** * \class IPAManager * \brief Manager for IPA modules @@ -129,7 +142,7 @@ int IPAManager::addDir(const char *libDir) * \param[in] maxVersion Maximum acceptable version of IPA module * * \return A newly created IPA interface, or nullptr if no matching - * IPA module is found + * IPA module is found or if the IPA interface fails to initialize */ std::unique_ptr IPAManager::createIPA(PipelineHandler *pipe, uint32_t maxVersion, @@ -144,7 +157,36 @@ std::unique_ptr IPAManager::createIPA(PipelineHandler *pipe, } } - if (!m || !m->load()) + if (!m) + return nullptr; + + if (!isOpenSource(m->info().license)) { + IPAProxyFactory *pf = nullptr; + std::vector &factories = IPAProxyFactory::factories(); + + for (IPAProxyFactory *factory : factories) { + /* TODO: Better matching */ + if (!strcmp(factory->name().c_str(), "IPAProxyLinux")) { + pf = factory; + break; + } + } + + if (!pf) { + LOG(IPAManager, Error) << "Failed to get proxy factory"; + return nullptr; + } + + std::unique_ptr proxy = pf->create(m); + if (!proxy->isValid()) { + LOG(IPAManager, Error) << "Failed to load proxy"; + return nullptr; + } + + return proxy; + } + + if (!m->load()) return nullptr; return m->createInstance(); From patchwork Tue Jul 9 18:44:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1639 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 51F4A61570 for ; Tue, 9 Jul 2019 20:45:11 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A83F456A; Tue, 9 Jul 2019 20:45:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562697911; bh=WT+ET4ird3OTr339A69MsFyzULpD7rj5xQQ55ZHwbdQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fsBlOuyKXkDnVt85DgtzsHgcnwlXFxZ/WkMHE2WpOyamtLlim7+FRRiAL8GyfJrJn dkF6fl3s7HtNehpEfxTw4HpdhmcO+IUqsO+rLv8cK7OSeRo8ZAYMdOxgqBqNgwRQeY rC0DHVz7f2pPjs9SeGDyGFEKuUyfH0+f29hkQIGk= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Jul 2019 03:44:49 +0900 Message-Id: <20190709184450.32023-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190709184450.32023-1-paul.elder@ideasonboard.com> References: <20190709184450.32023-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 6/7] libcamera: ipa: add dummy IPA that needs to be isolated X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 18:45:11 -0000 Add a dummy IPA that needs to be isolated. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v3: - fix header Changes in v2: - ipaModuleInfo contains license rather than "please isolate me" src/ipa/ipa_dummy_isolate.cpp | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/ipa/ipa_dummy_isolate.cpp diff --git a/src/ipa/ipa_dummy_isolate.cpp b/src/ipa/ipa_dummy_isolate.cpp new file mode 100644 index 0000000..8520546 --- /dev/null +++ b/src/ipa/ipa_dummy_isolate.cpp @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_dummy_isolate.cpp - Dummy Image Processing Algorithm module that needs to be isolated + */ + +#include + +#include +#include + +namespace libcamera { + +class IPADummyIsolate : public IPAInterface +{ +public: + int init(); +}; + +int IPADummyIsolate::init() +{ + std::cout << "initializing isolated dummy IPA!" << std::endl; + return 0; +} + +/* + * External IPA module interface + */ + +extern "C" { +const struct IPAModuleInfo ipaModuleInfo = { + IPA_MODULE_API_VERSION, + 0, + "PipelineHandlerVimc", + "Dummy IPA for Vimc that needs to be isolated", + "Proprietary", +}; + +IPAInterface *ipaCreate() +{ + return new IPADummyIsolate(); +} +}; + +}; /* namespace libcamera */ From patchwork Tue Jul 9 18:44:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 1640 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2408D61575 for ; Tue, 9 Jul 2019 20:45:13 +0200 (CEST) Received: from neptunite.amanokami.net (softbank126163157105.bbtec.net [126.163.157.105]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C337856A; Tue, 9 Jul 2019 20:45:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562697912; bh=Tp9LxcbtuvL8OVcIXf9StgsDsqKGLqUUe3RXekKk7EI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eQNzzZ1ZPMirsu6ElHwMsJGjiOXbW9iT9beqMCxHwQ14bt5k7qY0CLaEV3jpLQS6D UiVAwrCzU1cON6/F7sBf8WemDBuy9gB7ii5++/zeg5PSqQAwWeGL459v6PpPkAauzf 6ksZDjK95A0T0pqRz6y8JBVq2X9pC9dBHUzU+0YU= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Jul 2019 03:44:50 +0900 Message-Id: <20190709184450.32023-8-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190709184450.32023-1-paul.elder@ideasonboard.com> References: <20190709184450.32023-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 7/7] libcamera: ipa: meson: build dummy IPA that needs isolation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 18:45:13 -0000 Add the dummy IPA that needs isolation to meson. At the same time, clean up the IPA meson to facilitate adding more IPAs. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v3: - remove sub install directory for IPAs Changes in v2: - make a sub install directory for IPAs, to keep them separate from the proxies - remove shim compilation src/ipa/meson.build | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ipa/meson.build b/src/ipa/meson.build index 3c33a37..2b9863b 100644 --- a/src/ipa/meson.build +++ b/src/ipa/meson.build @@ -1,15 +1,18 @@ -ipa_dummy_sources = files([ - 'ipa_dummy.cpp', -]) +ipa_dummy_sources = [ + ['ipa_dummy', 'ipa_dummy.cpp'], + ['ipa_dummy_isolate', 'ipa_dummy_isolate.cpp'], +] ipa_install_dir = join_paths(get_option('libdir'), 'libcamera') -ipa_dummy = shared_library('ipa_dummy', - ipa_dummy_sources, - name_prefix : '', - include_directories : libcamera_includes, - install : true, - install_dir : ipa_install_dir) +foreach t : ipa_dummy_sources + ipa = shared_module(t[0], + t[1], + name_prefix : '', + include_directories : libcamera_includes, + install : true, + install_dir : ipa_install_dir) +endforeach config_h.set('IPA_MODULE_DIR', '"' + join_paths(get_option('prefix'), ipa_install_dir) + '"')