-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdaemon.cc
147 lines (128 loc) · 5.37 KB
/
daemon.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// 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/daemon.h"
#include <memory>
#include <string>
#include <sysexits.h>
#include <utility>
#include <base/bind.h>
#include <base/callback.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/threading/thread_task_runner_handle.h>
#include <base/unguessable_token.h>
#include <dbus/object_path.h>
#include <chromeos/dbus/service_constants.h>
#include <mojo/public/cpp/platform/platform_channel_endpoint.h>
#include <mojo/public/cpp/system/invitation.h>
#include <mojo/core/embedder/embedder.h>
#include "ocr/ocr_service_impl.h"
namespace ocr {
OcrDaemon::OcrDaemon() : brillo::DBusServiceDaemon(kOcrServiceName) {
ocr_service_impl_ = std::make_unique<OcrServiceImpl>();
ocr_service_impl_->SetOnDisconnectCallback(base::BindRepeating(
&OcrDaemon::OnDisconnect, weak_ptr_factory_.GetWeakPtr()));
}
OcrDaemon::~OcrDaemon() = default;
int OcrDaemon::OnInit() {
int return_code = brillo::DBusServiceDaemon::OnInit();
if (return_code != EX_OK)
return return_code;
// Initialize Mojo IPC.
mojo::core::Init();
ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>(
base::ThreadTaskRunnerHandle::Get() /* io_thread_task_runner */,
mojo::core::ScopedIPCSupport::ShutdownPolicy::
CLEAN /* blocking shutdown */);
return EX_OK;
}
void OcrDaemon::RegisterDBusObjectsAsync(
brillo::dbus_utils::AsyncEventSequencer* sequencer) {
DCHECK(!dbus_object_);
dbus_object_ = std::make_unique<brillo::dbus_utils::DBusObject>(
nullptr /* object_manager */, bus_, dbus::ObjectPath(kOcrServicePath));
brillo::dbus_utils::DBusInterface* dbus_interface =
dbus_object_->AddOrGetInterface(kOcrServiceInterface);
DCHECK(dbus_interface);
dbus_interface->AddSimpleMethodHandler(kBootstrapMojoConnectionMethod,
base::Unretained(this),
&OcrDaemon::BootstrapMojoConnection);
dbus_object_->RegisterAsync(sequencer->GetHandler(
"Failed to register D-Bus object" /* descriptive_message */,
true /* failure_is_fatal */));
}
std::string OcrDaemon::BootstrapMojoConnection(const base::ScopedFD& mojo_fd,
bool should_accept_invitation) {
VLOG(1) << "Received BootstrapMojoConnection D-Bus request";
if (!mojo_fd.is_valid()) {
constexpr char kInvalidFileDescriptorError[] =
"ScopedFD extracted from D-Bus call was invalid (i.e. empty)";
LOG(ERROR) << kInvalidFileDescriptorError;
return kInvalidFileDescriptorError;
}
// We need a file descriptor that stays alive after the current method
// finishes, but libbrillo's D-Bus wrappers currently don't support passing
// base::ScopedFD by value.
base::ScopedFD mojo_fd_copy(HANDLE_EINTR(dup(mojo_fd.get())));
if (!mojo_fd_copy.is_valid()) {
constexpr char kFailedDuplicationError[] =
"Failed to duplicate the Mojo file descriptor";
PLOG(ERROR) << kFailedDuplicationError;
return kFailedDuplicationError;
}
if (!base::SetCloseOnExec(mojo_fd_copy.get())) {
constexpr char kFailedSettingFdCloexec[] =
"Failed to set FD_CLOEXEC on Mojo file descriptor";
PLOG(ERROR) << kFailedSettingFdCloexec;
return kFailedSettingFdCloexec;
}
std::string token;
mojo::ScopedMessagePipeHandle mojo_message_pipe;
if (should_accept_invitation) {
if (mojo_service_bind_attempted_) {
// This should not normally be triggered, since the other endpoint - the
// browser process - should bootstrap the Mojo connection only once, and
// when that process is killed the Mojo shutdown notification should have
// been received earlier. But handle this case to be on the safe side.
// After we restart, the browser process is expected to invoke the
// bootstrapping again.
LOG(ERROR) << "Shutting down due to repeated Mojo bootstrap requests";
ocr_service_impl_.reset();
Quit();
return "";
}
// Connect to Mojo in the requesting process.
mojo::IncomingInvitation invitation =
mojo::IncomingInvitation::Accept(mojo::PlatformChannelEndpoint(
mojo::PlatformHandle(std::move(mojo_fd_copy))));
mojo_message_pipe =
invitation.ExtractMessagePipe(kBootstrapMojoConnectionChannelToken);
mojo_service_bind_attempted_ = true;
} else {
// Create a unique token which will allow the requesting process to connect
// to us via Mojo.
mojo::OutgoingInvitation invitation;
token = base::UnguessableToken::Create().ToString();
mojo_message_pipe = invitation.AttachMessagePipe(token);
mojo::OutgoingInvitation::Send(
std::move(invitation), base::kNullProcessHandle,
mojo::PlatformChannelEndpoint(
mojo::PlatformHandle(std::move(mojo_fd_copy))));
}
ocr_service_impl_->AddReceiver(
mojo::PendingReceiver<
chromeos::ocr::mojom::OpticalCharacterRecognitionService>(
std::move(mojo_message_pipe)),
should_accept_invitation);
VLOG(1) << "Successfully bootstrapped Mojo connection";
return token;
}
void OcrDaemon::OnDisconnect(bool should_quit) {
if (should_quit) {
LOG(ERROR) << "OcrDaemon lost Mojo connection to the browser; quitting.";
ocr_service_impl_.reset();
Quit();
}
}
} // namespace ocr