blob: ff804263851619d9cfce00749f5a0ca01e87bf26 [file] [log] [blame]
// Copyright 2020 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 "ocr/mojo_adapter/ocr_service_mojo_adapter_delegate_impl.h"
#include <memory>
#include <string>
#include <utility>
#include <base/bind.h>
#include <base/logging.h>
#include <base/memory/scoped_refptr.h>
#include <base/synchronization/waitable_event.h>
#include <brillo/dbus/dbus_method_invoker.h>
#include <brillo/dbus/file_descriptor.h>
#include <brillo/errors/error.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/bus.h>
#include <dbus/message.h>
#include <dbus/object_path.h>
#include <dbus/object_proxy.h>
#include <mojo/core/embedder/embedder.h>
#include <mojo/public/cpp/bindings/remote.h>
#include <mojo/public/cpp/platform/platform_channel.h>
#include <mojo/public/cpp/system/invitation.h>
#include <mojo/public/cpp/system/message_pipe.h>
namespace ocr {
namespace {
namespace mojo_ipc = chromeos::ocr::mojom;
// Sends |raw_fd| to OCR Daemon via D-Bus. Sets |token_out| to a unique token
// which can be used to create a message pipe to the OCR service.
void DoDBusBootstrap(int raw_fd,
base::WaitableEvent* event,
std::string* token_out) {
dbus::Bus::Options bus_options;
bus_options.bus_type = dbus::Bus::SYSTEM;
scoped_refptr<dbus::Bus> bus = new dbus::Bus(bus_options);
CHECK(bus->Connect());
dbus::ObjectProxy* ocr_service_proxy =
bus->GetObjectProxy(kOcrServiceName, dbus::ObjectPath(kOcrServicePath));
brillo::dbus_utils::FileDescriptor fd(raw_fd);
brillo::ErrorPtr error;
auto response = brillo::dbus_utils::CallMethodAndBlock(
ocr_service_proxy, kOcrServiceInterface, kBootstrapMojoConnectionMethod,
&error, fd, false /* should_accept_invitation */);
if (!response) {
LOG(ERROR) << "No response received.";
return;
}
dbus::MessageReader reader(response.get());
if (!reader.PopString(token_out)) {
LOG(ERROR) << "Failed to extract token.";
return;
}
event->Signal();
}
} // namespace
OcrServiceMojoAdapterDelegateImpl::OcrServiceMojoAdapterDelegateImpl() {
CHECK(mojo_thread_.StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0)))
<< "Failed starting the Mojo thread.";
CHECK(dbus_thread_.StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0)))
<< "Failed starting the D-Bus thread.";
mojo::core::Init();
ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
mojo_thread_.task_runner(),
mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
}
OcrServiceMojoAdapterDelegateImpl::~OcrServiceMojoAdapterDelegateImpl() =
default;
mojo::Remote<mojo_ipc::OpticalCharacterRecognitionService>
OcrServiceMojoAdapterDelegateImpl::GetOcrService() {
mojo::PlatformChannel channel;
std::string token;
// Pass the other end of the pipe to the OCR daemon. Wait for this task to
// run, since we need the resulting token to continue. The OCR daemon will
// send an invitation to connect to the OCR service.
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
dbus_thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(
&DoDBusBootstrap,
channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD().release(),
&event, &token));
event.Wait();
mojo::IncomingInvitation invitation =
mojo::IncomingInvitation::Accept(channel.TakeLocalEndpoint());
mojo::ScopedMessagePipeHandle pipe = invitation.ExtractMessagePipe(token);
return mojo::Remote<mojo_ipc::OpticalCharacterRecognitionService>(
mojo::PendingRemote<mojo_ipc::OpticalCharacterRecognitionService>(
std::move(pipe), 0));
}
} // namespace ocr