blob: 90b4a0b234f7ab1fc82f02a2134beca9b656a77a [file] [log] [blame]
/*
* Copyright 2017 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "common/camera_algorithm_adapter.h"
#include <dlfcn.h>
#include <memory>
#include <string>
#include <utility>
#include <base/bind.h>
#include <mojo/core/embedder/embedder.h>
#include <mojo/core/embedder/scoped_ipc_support.h>
#include <mojo/public/cpp/bindings/interface_request.h>
#include <mojo/public/cpp/system/invitation.h>
#include "cros-camera/camera_algorithm.h"
#include "cros-camera/common.h"
namespace cros {
namespace {
const char* GetAlgorithmLibraryName(const std::string& pipe_name) {
// TODO(kamesan): Arrange the library names in some format like
// libcam_algo_<pipe_name>.so
if (pipe_name == "vendor_cpu") {
return "libcam_algo.so";
}
if (pipe_name == "vendor_gpu") {
return "libcam_algo_vendor_gpu.so";
}
if (pipe_name == "google_gpu") {
return "libcam_gpu_algo.so";
}
if (pipe_name == "test") {
return "libcam_algo_test.so";
}
NOTREACHED() << "Unknown message pipe name: " << pipe_name;
return "";
}
} // namespace
CameraAlgorithmAdapter::CameraAlgorithmAdapter()
: algo_impl_(CameraAlgorithmOpsImpl::GetInstance()),
algo_dll_handle_(nullptr),
ipc_thread_("IPC thread") {}
CameraAlgorithmAdapter::~CameraAlgorithmAdapter() = default;
void CameraAlgorithmAdapter::Run(std::string pipe_name,
base::ScopedFD channel) {
VLOGF_ENTER();
auto future = cros::Future<void>::Create(&relay_);
ipc_lost_cb_ = cros::GetFutureCallback(future);
ipc_thread_.StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0));
ipc_thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(&CameraAlgorithmAdapter::InitializeOnIpcThread,
base::Unretained(this), pipe_name, base::Passed(&channel)));
future->Wait(-1);
ipc_thread_.Stop();
VLOGF_EXIT();
}
void CameraAlgorithmAdapter::InitializeOnIpcThread(std::string pipe_name,
base::ScopedFD channel) {
DCHECK(ipc_thread_.task_runner()->BelongsToCurrentThread());
VLOGF(1) << "Setting up message pipe, name: " << pipe_name;
mojo::core::Init();
ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
ipc_thread_.task_runner(),
mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
mojo::IncomingInvitation invitation = mojo::IncomingInvitation::Accept(
mojo::PlatformChannelEndpoint(mojo::PlatformHandle(std::move(channel))));
mojom::CameraAlgorithmOpsRequest request(
invitation.ExtractMessagePipe(pipe_name));
VLOGF_ENTER();
const char* algo_lib_name = GetAlgorithmLibraryName(pipe_name);
algo_dll_handle_ = dlopen(algo_lib_name, RTLD_NOW);
if (!algo_dll_handle_) {
LOGF(ERROR) << "Failed to dlopen: " << dlerror();
DestroyOnIpcThread();
return;
}
camera_algorithm_ops_t* cam_algo = static_cast<camera_algorithm_ops_t*>(
dlsym(algo_dll_handle_, CAMERA_ALGORITHM_MODULE_INFO_SYM_AS_STR));
if (!cam_algo) {
LOGF(ERROR) << "Camera algorithm is invalid";
dlclose(algo_dll_handle_);
DestroyOnIpcThread();
return;
}
base::Closure ipc_lost_handler = base::Bind(
&CameraAlgorithmAdapter::DestroyOnIpcThread, base::Unretained(this));
algo_impl_->Bind(std::move(request), cam_algo, ipc_thread_.task_runner(),
ipc_lost_handler);
VLOGF_EXIT();
}
void CameraAlgorithmAdapter::DestroyOnIpcThread() {
DCHECK(ipc_thread_.task_runner()->BelongsToCurrentThread());
VLOGF_ENTER();
algo_impl_->Unbind();
ipc_support_ = nullptr;
if (algo_dll_handle_) {
dlclose(algo_dll_handle_);
}
ipc_lost_cb_.Run();
VLOGF_EXIT();
}
} // namespace cros