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

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: Removed the dependency on KeyedService and content/ 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 observer_list_(new base::ObserverListThreadSafe<Observer>()),
36 available_(false),
37 enabled_(false),
38 state_(ArcBridgeService::STOPPED),
39 weak_factory_(this) {
40 ipc_thread_.StartWithOptions(
41 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
42 }
43
44 ArcBridgeService::~ArcBridgeService() {}
45
46 void ArcBridgeService::HandleStartup() {
47 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
48 if (!enabled_)
49 return;
50 SocketConnect(base::FilePath(kArcBridgeSocketPath));
51 }
52
53 void ArcBridgeService::Shutdown() {
54 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
55 if (state_ == ArcBridgeService::STOPPED ||
56 state_ == ArcBridgeService::STOPPING) {
57 VLOG(1) << "Shutdown() called when ARC is not running";
58 return;
59 }
60 if (state_ == ArcBridgeService::CONNECTED ||
61 state_ == ArcBridgeService::CONNECTING) {
62 // This was stopped before the D-Bus command to start the instance. Just
63 // close the socket (if it was opened).
64 if (state_ == ArcBridgeService::CONNECTED) {
65 base::AutoLock scoped_lock(ipc_channel_lock_);
66 ipc_channel_->Close();
67 ipc_channel_.reset();
68 }
69 SetState(ArcBridgeService::STOPPED);
70 return;
71 }
72
73 SetState(ArcBridgeService::STOPPING);
74 chromeos::SessionManagerClient* session_manager_client =
75 chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
76 session_manager_client->StopArcInstance(
77 base::Bind(&ArcBridgeService::OnInstanceStopped,
78 weak_factory_.GetWeakPtr()));
79 }
80
81 void ArcBridgeService::AddObserver(Observer* observer) {
82 observer_list_->AddObserver(observer);
83 }
84
85 void ArcBridgeService::RemoveObserver(Observer* observer) {
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_ != ArcBridgeService::STOPPED &&
96 state_ != ArcBridgeService::STOPPING)
97 Shutdown();
98 observer_list_->Notify(FROM_HERE,
99 &Observer::OnEnabledChanged,
100 enabled_);
101 }
102
103 bool ArcBridgeService::RegisterInputDevice(
104 const std::string& name, const std::string& device_type,
105 base::ScopedFD fd) {
106 base::AutoLock scoped_lock(ipc_channel_lock_);
dcheng 2015/11/06 01:35:28 Consider using clang-format to fix formatting issu
lhc(google) 2015/11/06 04:14:16 Done.
107 if (!ipc_channel_) {
108 LOG(ERROR) << "Called RegisterInputDevice when the service is not ready";
109 return false;
110 }
111 return ipc_channel_->Send(new ArcInstanceMsg_RegisterInputDevice(
112 name, device_type, base::FileDescriptor(fd.Pass())));
113 }
114
115 void ArcBridgeService::SocketConnect(const base::FilePath& socket_path) {
116 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
117 if (state_ != ArcBridgeService::STOPPED) {
118 VLOG(1) << "SocketConnect() called when instance is not stopped";
119 return;
120 }
121 SetState(ArcBridgeService::CONNECTING);
122 base::PostTaskAndReplyWithResult(
123 file_task_runner_.get(),
124 FROM_HERE,
125 base::Bind(&base::CreateDirectory, socket_path.DirName()),
126 base::Bind(&ArcBridgeService::SocketConnectAfterEnsureParentDirectory,
127 weak_factory_.GetWeakPtr(),
128 socket_path));
129 }
130
131 void ArcBridgeService::SocketConnectAfterEnsureParentDirectory(
132 const base::FilePath& socket_path, bool directory_present) {
133 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
134 if (state_ != ArcBridgeService::CONNECTING) {
135 VLOG(1) << "Shutdown() called while connecting";
136 return;
137 }
138 if (!directory_present) {
139 LOG(ERROR) << "Error creating directory for " << socket_path.value();
140 Shutdown();
141 return;
142 }
143
144 if (!Connect(IPC::ChannelHandle(socket_path.value()),
145 IPC::Channel::MODE_OPEN_NAMED_SERVER)) {
146 LOG(ERROR) << "Error connecting to " << socket_path.value();
147 Shutdown();
148 return;
149 }
150
151 base::PostTaskAndReplyWithResult(
152 file_task_runner_.get(),
153 FROM_HERE,
154 // TODO(lhchavez): Tighten the security around the socket by tying it to
155 // the user the instance will run as.
156 base::Bind(&base::SetPosixFilePermissions, socket_path, 0777),
157 base::Bind(&ArcBridgeService::SocketConnectAfterSetSocketPermissions,
158 weak_factory_.GetWeakPtr(), socket_path));
159 }
160
161 void ArcBridgeService::SocketConnectAfterSetSocketPermissions(
162 const base::FilePath& socket_path, bool socket_permissions_success) {
163 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
164 if (state_ != ArcBridgeService::CONNECTED) {
165 VLOG(1) << "Shutdown() called while connecting";
166 return;
167 }
168
169 if (!socket_permissions_success) {
170 LOG(ERROR) << "Error setting socket permissions for "
171 << socket_path.value();
172 Shutdown();
173 return;
174 }
175
176 SetState(ArcBridgeService::STARTING);
177 chromeos::SessionManagerClient* session_manager_client =
178 chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
179 session_manager_client->StartArcInstance(
180 socket_path.value(),
181 base::Bind(&ArcBridgeService::OnInstanceStarted,
182 weak_factory_.GetWeakPtr()));
183 }
184
185 bool ArcBridgeService::Connect(const IPC::ChannelHandle& handle,
186 IPC::Channel::Mode mode) {
187 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
188 if (state_ != ArcBridgeService::CONNECTING) {
189 VLOG(1) << "Shutdown() called while connecting";
190 return false;
191 }
192
193 base::AutoLock scoped_lock(ipc_channel_lock_);
194 ipc_channel_ = IPC::ChannelProxy::Create(handle, mode, this,
dcheng 2015/11/06 01:35:28 I don't think this can actually return null.
lhc(google) 2015/11/06 04:14:16 Done.
195 ipc_thread_.task_runner().get());
196 if (!ipc_channel_)
197 return false;
198 SetState(ArcBridgeService::CONNECTED);
199 return true;
200 }
201
202 void ArcBridgeService::OnInstanceReady() {
203 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
204 if (state_ != ArcBridgeService::STARTING) {
205 VLOG(1) << "Shutdown() called while connecting";
206 return;
207 }
208 SetState(ArcBridgeService::READY);
209 }
210
211 void ArcBridgeService::SetState(State state) {
212 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
213 DCHECK(state_ != state);
214 state_ = state;
215 observer_list_->Notify(FROM_HERE,
216 &Observer::OnStateChanged,
217 state_);
218 }
219
220 bool ArcBridgeService::OnMessageReceived(const IPC::Message& message) {
221 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
222 bool handled = true;
223
224 IPC_BEGIN_MESSAGE_MAP(ArcBridgeService, message)
225 IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_InstanceReady, OnInstanceReady)
226 IPC_MESSAGE_UNHANDLED(handled = false)
227 IPC_END_MESSAGE_MAP()
228
229 if (!handled)
230 LOG(ERROR) << "Invalid message with type = " << message.type();
231 return handled;
232 }
233
234 void ArcBridgeService::OnInstanceStarted(bool success) {
235 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
236 if (state_ != ArcBridgeService::STARTING) {
237 VLOG(1) << "Shutdown() called while connecting";
238 return;
239 }
240 if (!success) {
241 LOG(ERROR) << "ARC instance unable to start. Shutting down the bridge";
242 Shutdown();
243 return;
244 }
245 }
246
247 void ArcBridgeService::OnInstanceStopped(bool success) {
248 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
249 // STOPPING is the only valid state for this function.
250 DCHECK(state_ == ArcBridgeService::STOPPING);
251 {
252 base::AutoLock scoped_lock(ipc_channel_lock_);
253 ipc_channel_->Close();
254 ipc_channel_.reset();
255 }
256 SetState(ArcBridgeService::STOPPED);
257 }
258
259 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698