Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: components/arc/arc_bridge_service.cc

Issue 1412863004: arc-bridge: Add the ARC Bridge Service (Closed) Base URL: https://chromium.googlesource.com/a/chromium/src.git@master
Patch Set: Addressed feedback Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/arc/arc_bridge_service.h"
6
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/prefs/pref_registry_simple.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/task_runner_util.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "chromeos/arc/bridge/common/arc_host_messages.h"
14 #include "chromeos/arc/bridge/common/arc_instance_messages.h"
15 #include "chromeos/dbus/dbus_method_call_status.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "chromeos/dbus/session_manager_client.h"
18 #include "components/arc/arc_pref_names.h"
19 #include "ipc/ipc_channel.h"
20
21 namespace {
22
23 const base::FilePath::CharType kArcBridgeSocketPath[] =
24 FILE_PATH_LITERAL("/home/chronos/ArcBridge/bridge.sock");
25
26 } // namespace
27
28 namespace arc {
29
30 ArcBridgeService::ArcBridgeService(
31 const scoped_refptr<base::SequencedTaskRunner>& file_task_runner)
32 : ipc_thread_("ARC bridge listener"),
33 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
34 file_task_runner_(file_task_runner),
35 available_(false),
36 enabled_(false),
37 state_(State::STOPPED),
38 weak_factory_(this) {
39 ipc_thread_.StartWithOptions(
jochen (gone - plz use gerrit) 2015/11/06 06:02:17 why do you need a dedicated thread?
jochen (gone - plz use gerrit) 2015/11/06 06:02:17 why do you need a dedicated thread?
Luis Héctor Chávez 2015/11/09 16:41:04 Changed it to ask for the task runner in the const
40 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
41 }
42
43 ArcBridgeService::~ArcBridgeService() {}
44
45 void ArcBridgeService::HandleStartup() {
46 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
47 if (!enabled_)
48 return;
49 SocketConnect(base::FilePath(kArcBridgeSocketPath));
50 }
51
52 void ArcBridgeService::Shutdown() {
53 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
54 if (state_ == State::STOPPED ||
55 state_ == State::STOPPING) {
56 VLOG(1) << "Shutdown() called when ARC is not running";
57 return;
58 }
59 if (state_ == State::CONNECTED ||
60 state_ == State::CONNECTING) {
61 // This was stopped before the D-Bus command to start the instance. Just
62 // close the socket (if it was opened).
63 if (state_ == State::CONNECTED) {
64 ipc_channel_->Close();
65 ipc_channel_.reset();
66 }
67 SetState(State::STOPPED);
68 return;
69 }
70
71 SetState(State::STOPPING);
72 chromeos::SessionManagerClient* session_manager_client =
73 chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
74 session_manager_client->StopArcInstance(
75 base::Bind(&ArcBridgeService::OnInstanceStopped,
76 weak_factory_.GetWeakPtr()));
77 }
78
79 void ArcBridgeService::AddObserver(Observer* observer) {
80 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
81 observer_list_.AddObserver(observer);
82 }
83
84 void ArcBridgeService::RemoveObserver(Observer* observer) {
85 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
86 observer_list_.RemoveObserver(observer);
87 }
88
89 void ArcBridgeService::SetEnabled(bool enabled) {
90 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
91
92 if (enabled_ == enabled)
93 return;
94 enabled_ = enabled;
95 if (!enabled_ && state_ != State::STOPPED &&
96 state_ != State::STOPPING)
97 Shutdown();
98 FOR_EACH_OBSERVER(Observer, observer_list_, OnEnabledChanged(enabled_));
99 }
100
101 bool ArcBridgeService::RegisterInputDevice(
102 const std::string& name, const std::string& device_type,
103 base::ScopedFD fd) {
104 DCHECK(ipc_thread_.task_runner()->RunsTasksOnCurrentThread());
105 if (state_ != State::READY) {
106 LOG(ERROR) << "Called RegisterInputDevice when the service is not ready";
107 return false;
108 }
109 return ipc_channel_->Send(new ArcInstanceMsg_RegisterInputDevice(
110 name, device_type, base::FileDescriptor(fd.Pass())));
111 }
112
113 void ArcBridgeService::SocketConnect(const base::FilePath& socket_path) {
114 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
115 if (state_ != State::STOPPED) {
116 VLOG(1) << "SocketConnect() called when instance is not stopped";
117 return;
118 }
119 SetState(State::CONNECTING);
120 base::PostTaskAndReplyWithResult(
121 file_task_runner_.get(),
122 FROM_HERE,
123 base::Bind(&base::CreateDirectory, socket_path.DirName()),
124 base::Bind(&ArcBridgeService::SocketConnectAfterEnsureParentDirectory,
125 weak_factory_.GetWeakPtr(),
126 socket_path));
127 }
128
129 void ArcBridgeService::SocketConnectAfterEnsureParentDirectory(
130 const base::FilePath& socket_path, bool directory_present) {
131 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
132 if (state_ != State::CONNECTING) {
133 VLOG(1) << "Shutdown() called while connecting";
134 return;
135 }
136 if (!directory_present) {
137 LOG(ERROR) << "Error creating directory for " << socket_path.value();
138 Shutdown();
139 return;
140 }
141
142 if (!Connect(IPC::ChannelHandle(socket_path.value()),
143 IPC::Channel::MODE_OPEN_NAMED_SERVER)) {
144 LOG(ERROR) << "Error connecting to " << socket_path.value();
145 Shutdown();
146 return;
147 }
148
149 base::PostTaskAndReplyWithResult(
150 file_task_runner_.get(),
151 FROM_HERE,
152 // TODO(lhchavez): Tighten the security around the socket by tying it to
153 // the user the instance will run as.
154 base::Bind(&base::SetPosixFilePermissions, socket_path, 0777),
155 base::Bind(&ArcBridgeService::SocketConnectAfterSetSocketPermissions,
156 weak_factory_.GetWeakPtr(), socket_path));
157 }
158
159 void ArcBridgeService::SocketConnectAfterSetSocketPermissions(
160 const base::FilePath& socket_path, bool socket_permissions_success) {
161 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
162 if (state_ != State::CONNECTED) {
163 VLOG(1) << "Shutdown() called while connecting";
164 return;
165 }
166
167 if (!socket_permissions_success) {
168 LOG(ERROR) << "Error setting socket permissions for "
169 << socket_path.value();
170 Shutdown();
171 return;
172 }
173
174 SetState(State::STARTING);
175 chromeos::SessionManagerClient* session_manager_client =
176 chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
177 session_manager_client->StartArcInstance(
178 socket_path.value(),
179 base::Bind(&ArcBridgeService::OnInstanceStarted,
180 weak_factory_.GetWeakPtr()));
181 }
182
183 bool ArcBridgeService::Connect(const IPC::ChannelHandle& handle,
184 IPC::Channel::Mode mode) {
185 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
186 if (state_ != State::CONNECTING) {
187 VLOG(1) << "Shutdown() called while connecting";
188 return false;
189 }
190
191 ipc_channel_ = IPC::ChannelProxy::Create(handle, mode, this,
192 ipc_thread_.task_runner().get());
193 if (!ipc_channel_)
194 return false;
195 SetState(State::CONNECTED);
196 return true;
197 }
198
199 void ArcBridgeService::OnInstanceReady() {
200 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
201 if (state_ != State::STARTING) {
202 VLOG(1) << "Shutdown() called while connecting";
203 return;
204 }
205 SetState(State::READY);
206 }
207
208 void ArcBridgeService::SetState(State state) {
209 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
210 DCHECK(state_ != state);
211 state_ = state;
212 FOR_EACH_OBSERVER(Observer, observer_list_, OnStateChanged(state_));
213 }
214
215 bool ArcBridgeService::OnMessageReceived(const IPC::Message& message) {
216 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
217 bool handled = true;
218
219 IPC_BEGIN_MESSAGE_MAP(ArcBridgeService, message)
220 IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_InstanceReady, OnInstanceReady)
221 IPC_MESSAGE_UNHANDLED(handled = false)
222 IPC_END_MESSAGE_MAP()
223
224 if (!handled)
225 LOG(ERROR) << "Invalid message with type = " << message.type();
226 return handled;
227 }
228
229 void ArcBridgeService::OnInstanceStarted(bool success) {
230 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
231 if (state_ != State::STARTING) {
232 VLOG(1) << "Shutdown() called while connecting";
233 return;
234 }
235 if (!success) {
236 LOG(ERROR) << "ARC instance unable to start. Shutting down the bridge";
237 Shutdown();
238 return;
239 }
240 }
241
242 void ArcBridgeService::OnInstanceStopped(bool success) {
243 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
244 // STOPPING is the only valid state for this function.
245 DCHECK(state_ == State::STOPPING);
246 ipc_channel_->Close();
247 ipc_channel_.reset();
248 SetState(State::STOPPED);
249 }
250
251 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698