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

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/arc_instance_client.h"
16 #include "chromeos/dbus/dbus_method_call_status.h"
17 #include "chromeos/dbus/dbus_thread_manager.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");
hidehiko 2015/10/29 16:29:47 nit: 4 indent.
Luis Héctor Chávez 2015/10/29 23:43:53 Done.
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/10/29 16:29:47 nit: 4 indent. http://google-styleguide.googlecode
Luis Héctor Chávez 2015/10/29 23:43:52 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 LOG(ERROR) << "Shutdown() called when ARC is not running";
69 return;
70 }
71 SetState(ArcBridgeService::STOPPING);
72 ipc_channel_->Close();
Shuhei Takahashi 2015/10/29 00:13:08 ipc_channel_ can be null when state_ == CONNECTING
Luis Héctor Chávez 2015/10/29 23:43:52 Done.
73 ipc_channel_.reset();
74 base::PostTaskAndReplyWithResult(
hidehiko 2015/10/29 16:29:47 In general, shutdown step is the reverse order of
Luis Héctor Chávez 2015/10/29 23:43:53 SGTM, done.
75 file_task_runner_.get(),
76 FROM_HERE,
77 base::Bind(&base::DeleteFile, base::FilePath(kArcBridgeSocketPath),
78 false),
79 base::Bind(&ArcBridgeService::FinishShutdownAfterSocketDeleted,
80 weak_factory_.GetWeakPtr()));
81 }
82
83 void ArcBridgeService::AddObserver(Observer* observer) {
84 observer_list_->AddObserver(observer);
85 }
86
87 void ArcBridgeService::RemoveObserver(Observer* observer) {
88 observer_list_->RemoveObserver(observer);
89 }
90
91 void ArcBridgeService::SetEnabled(bool enabled) {
92 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
93
94 if (enabled_ == enabled)
95 return;
96 enabled_ = enabled;
97 if (!enabled_ && state_ != ArcBridgeService::STOPPED &&
98 state_ != ArcBridgeService::STOPPING)
99 Shutdown();
Shuhei Takahashi 2015/10/29 00:13:08 I'm puzzled by asymmetry here that SetEnabled(fals
Luis Héctor Chávez 2015/10/29 23:43:53 HandleStartup() is called upon profile startup, wh
100 observer_list_->Notify(FROM_HERE,
101 &Observer::OnEnabledChanged,
102 enabled_);
103 }
104
105 bool ArcBridgeService::RegisterInputDevice(
106 const std::string& name, const std::string& device_type,
107 base::ScopedFD fd) {
108 // ipc_channel_->Send() is thread-safe, so there is no thread check.
109 if (state_ != ArcBridgeService::READY) {
Shuhei Takahashi 2015/10/29 00:13:08 If this function is called from arbitrary threads,
Luis Héctor Chávez 2015/10/29 23:43:53 Ugh, yes. I was trying to avoid locks, but it's no
110 LOG(ERROR) << "Called RegisterInputDevice when the service is not ready";
111 return false;
112 }
113 return ipc_channel_->Send(new ArcInstanceMsg_RegisterInputDevice(
114 name, device_type, base::FileDescriptor(fd.Pass())));
115 }
116
117 void ArcBridgeService::SocketConnect(const base::FilePath& socket_path) {
118 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
119 if (state_ != ArcBridgeService::STOPPED) {
120 LOG(ERROR) << "SocketConnect() called when instance is not stopped";
121 return;
122 }
123 SetState(ArcBridgeService::CONNECTING);
124 base::PostTaskAndReplyWithResult(
125 file_task_runner_.get(),
126 FROM_HERE,
127 base::Bind(&base::CreateDirectory, socket_path.DirName()),
128 base::Bind(&ArcBridgeService::SocketConnectAfterEnsureParentDirectory,
129 weak_factory_.GetWeakPtr(),
130 socket_path));
131 }
132
133 void ArcBridgeService::SocketConnectAfterEnsureParentDirectory(
134 const base::FilePath& socket_path, bool directory_present) {
135 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
136 if (state_ != ArcBridgeService::CONNECTING) {
137 LOG(ERROR) << "Shutdown requested while connecting";
138 return;
139 }
140 if (!directory_present) {
141 LOG(ERROR) << "Error creating directory for " << socket_path.value();
142 Shutdown();
143 return;
144 }
145
146 if (!Connect(IPC::ChannelHandle(socket_path.value()),
147 IPC::Channel::MODE_OPEN_NAMED_SERVER)) {
148 LOG(ERROR) << "Error connecting to " << socket_path.value();
149 Shutdown();
150 return;
151 }
152
153 base::PostTaskAndReplyWithResult(
154 file_task_runner_.get(),
155 FROM_HERE,
156 // TODO(lhchavez): Tighten the security around the socket by tying it to
157 // the user the instance will run as.
158 base::Bind(&base::SetPosixFilePermissions, socket_path, 0777),
159 base::Bind(&ArcBridgeService::FinishConnectAfterSetSocketPermissions,
160 weak_factory_.GetWeakPtr(), socket_path));
161 }
162
163 void ArcBridgeService::FinishConnectAfterSetSocketPermissions(
164 const base::FilePath& socket_path, bool socket_permissions_success) {
165 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
166 if (state_ != ArcBridgeService::CONNECTED) {
167 LOG(ERROR) << "Shutdown requested while connecting";
168 return;
169 }
170
171 if (!socket_permissions_success) {
172 LOG(ERROR) << "Error setting socket permissions for "
173 << socket_path.value();
174 Shutdown();
175 return;
176 }
177
178 // This will fail if the ArcInstanceService is not running on Chrome OS.
179 chromeos::DBusThreadManager::Get()->GetArcInstanceClient()->StartInstance(
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 // Testing code can have the state in STOPPED since it does not go through
hidehiko 2015/10/29 16:29:47 How about DCHECK(state_ == CONNECTING);? For testi
Luis Héctor Chávez 2015/10/29 23:43:53 Keeping the current code as discussed offline.
189 // the whole connection flow.
190 if (state_ != ArcBridgeService::CONNECTING &&
191 state_ != ArcBridgeService::STOPPED) {
192 LOG(ERROR) << "Shutdown requested while connecting";
193 return false;
194 }
195
196 ipc_channel_ = IPC::ChannelProxy::Create(handle, mode, this,
197 ipc_thread_.task_runner().get());
198 if (!ipc_channel_)
199 return false;
200 SetState(ArcBridgeService::CONNECTED);
hidehiko 2015/10/29 16:29:47 Let's move this to SocketConnectAfterEnsureParentD
Luis Héctor Chávez 2015/10/29 23:43:53 Keeping the current code as discussed offline.
201 return true;
202 }
203
204 void ArcBridgeService::OnInstanceReady() {
205 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
206 if (state_ != ArcBridgeService::CONNECTED) {
207 LOG(ERROR) << "Shutdown requested while connecting";
208 return;
209 }
210 SetState(ArcBridgeService::READY);
211 }
212
213 void ArcBridgeService::SetState(State state) {
214 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
215 if (state_ == state)
216 return;
217 state_ = state;
218 observer_list_->Notify(FROM_HERE,
219 &Observer::OnStateChanged,
220 state_);
221 }
222
223 void ArcBridgeService::FinishShutdownAfterSocketDeleted(bool socket_deleted) {
224 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
225 // STOPPING is the only valid state for this function.
226 CHECK(state_ == ArcBridgeService::STOPPING);
227 chromeos::DBusThreadManager::Get()->GetArcInstanceClient()->StopInstance(
228 base::Bind(&ArcBridgeService::OnInstanceStopped,
229 weak_factory_.GetWeakPtr()));
230 }
231
232 bool ArcBridgeService::OnMessageReceived(const IPC::Message& message) {
233 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
234 bool handled = true;
235
236 IPC_BEGIN_MESSAGE_MAP(ArcBridgeService, message)
237 IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_InstanceReady, OnInstanceReady)
238 IPC_MESSAGE_UNHANDLED(handled = false)
239 IPC_END_MESSAGE_MAP()
240
241 if (!handled)
242 LOG(ERROR) << "Invalid message with type = " << message.type();
243 return handled;
244 }
245
246 void ArcBridgeService::OnInstanceStarted(
247 chromeos::DBusMethodCallStatus status) {
248 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
249 if (state_ != ArcBridgeService::CONNECTED) {
250 LOG(ERROR) << "Shutdown requested while connecting";
251 return;
252 }
253 if (status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
254 LOG(ERROR) << "ARC instance unable to start. Shutting down the bridge";
255 Shutdown();
256 return;
257 }
258 SetState(ArcBridgeService::STARTING);
259 }
260
261 void ArcBridgeService::OnInstanceStopped(
262 chromeos::DBusMethodCallStatus status) {
263 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
264 // STOPPING is the only valid state for this function.
265 CHECK(state_ == ArcBridgeService::STOPPING);
266 SetState(ArcBridgeService::STOPPED);
267 }
268
269 } // namespace arc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698