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

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"),
hidehiko 2015/11/05 18:08:50 nit: 4 space indent, followed by 6 space indent. h
lhc(google) 2015/11/06 04:14:16 Done.
Luis Héctor Chávez 2015/11/09 16:41:04 Hmm I had it this way before. Done.
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 // static
47 void ArcBridgeService::RegisterPrefs(PrefRegistrySimple* registry) {
48 registry->RegisterBooleanPref(prefs::kArcEnabled, false);
49 }
50
51 // static
52 bool ArcBridgeService::GetEnabledPref(PrefService* pref_service) {
53 // TODO(lhchavez): Once this is user-configurable, use the real pref.
54 return true;
55 }
56
57 void ArcBridgeService::HandleStartup() {
58 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
59 if (!enabled_)
60 return;
61 SocketConnect(base::FilePath(kArcBridgeSocketPath));
62 }
63
64 void ArcBridgeService::Shutdown() {
65 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
66 if (state_ == ArcBridgeService::STOPPED ||
67 state_ == ArcBridgeService::STOPPING) {
68 VLOG(1) << "Shutdown() called when ARC is not running";
69 return;
70 }
71 if (state_ == ArcBridgeService::CONNECTED ||
72 state_ == ArcBridgeService::CONNECTING) {
73 // This was stopped before the D-Bus command to start the instance. Just
74 // close the socket (if it was opened).
75 if (state_ == ArcBridgeService::CONNECTED) {
76 base::AutoLock scoped_lock(ipc_channel_lock_);
77 ipc_channel_->Close();
78 ipc_channel_.reset();
79 }
80 SetState(ArcBridgeService::STOPPED);
81 return;
82 }
83
84 SetState(ArcBridgeService::STOPPING);
85 chromeos::SessionManagerClient* session_manager_client =
86 chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
87 session_manager_client->StopArcInstance(
88 base::Bind(&ArcBridgeService::OnInstanceStopped,
89 weak_factory_.GetWeakPtr()));
90 }
91
92 void ArcBridgeService::AddObserver(Observer* observer) {
93 observer_list_->AddObserver(observer);
94 }
95
96 void ArcBridgeService::RemoveObserver(Observer* observer) {
97 observer_list_->RemoveObserver(observer);
98 }
99
100 void ArcBridgeService::SetEnabled(bool enabled) {
101 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
102
103 if (enabled_ == enabled)
104 return;
105 enabled_ = enabled;
106 if (!enabled_ && state_ != ArcBridgeService::STOPPED &&
107 state_ != ArcBridgeService::STOPPING)
108 Shutdown();
109 observer_list_->Notify(FROM_HERE,
110 &Observer::OnEnabledChanged,
111 enabled_);
112 }
113
114 bool ArcBridgeService::RegisterInputDevice(
115 const std::string& name, const std::string& device_type,
116 base::ScopedFD fd) {
117 base::AutoLock scoped_lock(ipc_channel_lock_);
118 if (!ipc_channel_) {
hidehiko 2015/11/05 18:08:50 IIUC, state_ should be checked here? (If it is not
lhc(google) 2015/11/06 04:14:16 Done, although no matter what we do there will alw
119 LOG(ERROR) << "Called RegisterInputDevice when the service is not ready";
120 return false;
121 }
122 return ipc_channel_->Send(new ArcInstanceMsg_RegisterInputDevice(
123 name, device_type, base::FileDescriptor(fd.Pass())));
124 }
125
126 void ArcBridgeService::SocketConnect(const base::FilePath& socket_path) {
127 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
128 if (state_ != ArcBridgeService::STOPPED) {
129 VLOG(1) << "SocketConnect() called when instance is not stopped";
130 return;
131 }
132 SetState(ArcBridgeService::CONNECTING);
133 base::PostTaskAndReplyWithResult(
134 file_task_runner_.get(),
135 FROM_HERE,
136 base::Bind(&base::CreateDirectory, socket_path.DirName()),
137 base::Bind(&ArcBridgeService::SocketConnectAfterEnsureParentDirectory,
138 weak_factory_.GetWeakPtr(),
139 socket_path));
140 }
141
142 void ArcBridgeService::SocketConnectAfterEnsureParentDirectory(
143 const base::FilePath& socket_path, bool directory_present) {
144 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
145 if (state_ != ArcBridgeService::CONNECTING) {
146 VLOG(1) << "Shutdown() called while connecting";
147 return;
148 }
149 if (!directory_present) {
150 LOG(ERROR) << "Error creating directory for " << socket_path.value();
151 Shutdown();
152 return;
153 }
154
155 if (!Connect(IPC::ChannelHandle(socket_path.value()),
156 IPC::Channel::MODE_OPEN_NAMED_SERVER)) {
157 LOG(ERROR) << "Error connecting to " << socket_path.value();
158 Shutdown();
159 return;
160 }
161
162 base::PostTaskAndReplyWithResult(
163 file_task_runner_.get(),
164 FROM_HERE,
165 // TODO(lhchavez): Tighten the security around the socket by tying it to
166 // the user the instance will run as.
167 base::Bind(&base::SetPosixFilePermissions, socket_path, 0777),
168 base::Bind(&ArcBridgeService::SocketConnectAfterSetSocketPermissions,
169 weak_factory_.GetWeakPtr(), socket_path));
170 }
171
172 void ArcBridgeService::SocketConnectAfterSetSocketPermissions(
173 const base::FilePath& socket_path, bool socket_permissions_success) {
174 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
175 if (state_ != ArcBridgeService::CONNECTED) {
176 VLOG(1) << "Shutdown() called while connecting";
177 return;
178 }
179
180 if (!socket_permissions_success) {
181 LOG(ERROR) << "Error setting socket permissions for "
182 << socket_path.value();
183 Shutdown();
184 return;
185 }
186
187 SetState(ArcBridgeService::STARTING);
188 chromeos::SessionManagerClient* session_manager_client =
189 chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
190 session_manager_client->StartArcInstance(
191 socket_path.value(),
192 base::Bind(&ArcBridgeService::OnInstanceStarted,
193 weak_factory_.GetWeakPtr()));
194 }
195
196 bool ArcBridgeService::Connect(const IPC::ChannelHandle& handle,
197 IPC::Channel::Mode mode) {
198 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
199 if (state_ != ArcBridgeService::CONNECTING) {
200 VLOG(1) << "Shutdown() called while connecting";
201 return false;
202 }
203
204 base::AutoLock scoped_lock(ipc_channel_lock_);
205 ipc_channel_ = IPC::ChannelProxy::Create(handle, mode, this,
206 ipc_thread_.task_runner().get());
207 if (!ipc_channel_)
208 return false;
209 SetState(ArcBridgeService::CONNECTED);
210 return true;
211 }
212
213 void ArcBridgeService::OnInstanceReady() {
214 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
215 if (state_ != ArcBridgeService::STARTING) {
216 VLOG(1) << "Shutdown() called while connecting";
217 return;
218 }
219 SetState(ArcBridgeService::READY);
220 }
221
222 void ArcBridgeService::SetState(State state) {
223 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
224 DCHECK(state_ != state);
225 state_ = state;
226 observer_list_->Notify(FROM_HERE,
227 &Observer::OnStateChanged,
228 state_);
229 }
230
231 bool ArcBridgeService::OnMessageReceived(const IPC::Message& message) {
232 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
233 bool handled = true;
234
235 IPC_BEGIN_MESSAGE_MAP(ArcBridgeService, message)
236 IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_InstanceReady, OnInstanceReady)
237 IPC_MESSAGE_UNHANDLED(handled = false)
238 IPC_END_MESSAGE_MAP()
239
240 if (!handled)
241 LOG(ERROR) << "Invalid message with type = " << message.type();
242 return handled;
243 }
244
245 void ArcBridgeService::OnInstanceStarted(bool success) {
246 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
247 if (state_ != ArcBridgeService::STARTING) {
248 VLOG(1) << "Shutdown() called while connecting";
249 return;
250 }
251 if (!success) {
252 LOG(ERROR) << "ARC instance unable to start. Shutting down the bridge";
253 Shutdown();
254 return;
255 }
256 }
257
258 void ArcBridgeService::OnInstanceStopped(bool success) {
259 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
260 // STOPPING is the only valid state for this function.
261 DCHECK(state_ == ArcBridgeService::STOPPING);
262 {
263 base::AutoLock scoped_lock(ipc_channel_lock_);
264 ipc_channel_->Close();
265 ipc_channel_.reset();
266 }
267 SetState(ArcBridgeService::STOPPED);
268 }
269
270 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698