| /* |
| * 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 |