OLD | NEW |
---|---|
(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 char kArcBridgeSocketPath[] = "/home/chronos/ArcBridge/bridge.sock"; | |
satorux1
2015/10/28 05:45:22
Please use const FilePath::CharType and FILE_PATH_
Luis Héctor Chávez
2015/10/28 17:19:14
Done.
| |
24 | |
25 bool EnsureParentDirectoryPresent(const std::string& socket_path) { | |
satorux1
2015/10/28 05:45:22
how about taking base::FilePath?
The caller shou
Luis Héctor Chávez
2015/10/28 17:19:14
Done.
hidehiko
2015/10/28 17:48:45
Or, in this case, we can inline the code in the ca
Luis Héctor Chávez
2015/10/28 21:06:32
Yep, that's cleaner. Done.
| |
26 base::FilePath path(socket_path); | |
27 return base::CreateDirectory(path.DirName()); | |
28 } | |
29 | |
30 bool SocketPermissions(const std::string& socket_path) { | |
satorux1
2015/10/28 05:45:22
Maybe SetSocketPermissions? std::string -> base::F
Luis Héctor Chávez
2015/10/28 17:19:14
Done.
hidehiko
2015/10/28 17:48:45
Or, does base::SetPosixFilePermissions work?
Luis Héctor Chávez
2015/10/28 21:06:32
Done.
| |
31 // TODO(lhchavez): Tighten the security around the socket by tying it to the | |
32 // user the instance will run as. | |
33 return HANDLE_EINTR(chmod(socket_path.c_str(), 0777)) == 0; | |
34 } | |
35 | |
36 } // namespace | |
37 | |
38 namespace arc { | |
39 | |
40 ArcBridgeService::ArcBridgeService( | |
41 const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) | |
42 : ipc_thread_("ARC bridge listener"), | |
43 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
44 file_task_runner_(file_task_runner), | |
45 state_(ArcBridgeService::DISABLED) { | |
46 ipc_thread_.StartWithOptions( | |
47 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | |
48 } | |
49 | |
50 ArcBridgeService::~ArcBridgeService() {} | |
51 | |
52 // static | |
53 void ArcBridgeService::RegisterPrefs(PrefRegistrySimple* registry) { | |
54 registry->RegisterBooleanPref(prefs::kArcEnabled, false); | |
55 } | |
56 | |
57 // static | |
58 bool ArcBridgeService::GetEnabledPref(PrefService* pref_service) { | |
59 // TODO(lhchavez): Once this is user-configurable, use the real pref. | |
60 return true; | |
61 } | |
62 | |
63 void ArcBridgeService::HandleStartup() { | |
64 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
65 if (state_ != ArcBridgeService::STOPPED) | |
hidehiko
2015/10/28 17:48:45
Is this expected case?
If yes, it's good to commen
Luis Héctor Chávez
2015/10/28 21:06:32
Done
| |
66 return; | |
67 base::PostTaskAndReplyWithResult( | |
hidehiko
2015/10/28 17:48:45
Just a suggestion.
1) It seems like directory crea
Luis Héctor Chávez
2015/10/28 21:06:32
Done.
| |
68 file_task_runner_.get(), | |
69 FROM_HERE, | |
70 base::Bind(&EnsureParentDirectoryPresent, kArcBridgeSocketPath), | |
71 base::Bind(&ArcBridgeService::SocketConnect, | |
72 base::Unretained(this), kArcBridgeSocketPath)); | |
satorux1
2015/10/28 05:45:22
How about using WeakPtrFactory and remove use of U
Luis Héctor Chávez
2015/10/28 17:19:14
All other KeyedServices I saw used Unretained(), b
| |
73 } | |
74 | |
75 void ArcBridgeService::Shutdown() { | |
hidehiko
2015/10/28 17:48:45
Looks to have a race issue?
If this is called whi
Luis Héctor Chávez
2015/10/28 21:06:32
All state transitions are now guarded.
| |
76 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
77 if (state_ != ArcBridgeService::CONNECTED && | |
78 state_ != ArcBridgeService::STARTING && | |
79 state_ != ArcBridgeService::READY) | |
hidehiko
2015/10/28 17:48:45
Maybe logging?
Luis Héctor Chávez
2015/10/28 21:06:32
Done.
| |
80 return; | |
81 ipc_channel_->Close(); | |
82 base::PostTaskAndReplyWithResult( | |
83 file_task_runner_.get(), | |
84 FROM_HERE, | |
85 base::Bind(&base::DeleteFile, base::FilePath(kArcBridgeSocketPath), | |
86 false), | |
87 base::Bind(&ArcBridgeService::FinishShutdownAfterSocketDeleted, | |
88 base::Unretained(this))); | |
89 } | |
90 | |
91 void ArcBridgeService::AddObserver(Observer* observer) { | |
92 observer_list_.AddObserver(observer); | |
93 } | |
94 | |
95 void ArcBridgeService::RemoveObserver(Observer* observer) { | |
96 observer_list_.RemoveObserver(observer); | |
97 } | |
98 | |
99 void ArcBridgeService::SetEnabled(bool enabled) { | |
100 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
101 | |
102 if ((!enabled && state_ == ArcBridgeService::DISABLED) || | |
103 (enabled && state_ != ArcBridgeService::DISABLED)) | |
104 return; | |
105 if (state_ != ArcBridgeService::DISABLED) { | |
106 Shutdown(); | |
107 NotifyStateChanged(ArcBridgeService::DISABLED); | |
108 return; | |
109 } | |
110 NotifyStateChanged(ArcBridgeService::STOPPED); | |
111 } | |
112 | |
113 bool ArcBridgeService::RegisterInputDevice( | |
114 const std::string& name, const std::string& device_type, | |
115 base::ScopedFD fd) { | |
satorux1
2015/10/28 05:45:22
on which thread should this be called? Add a DCHEC
Luis Héctor Chávez
2015/10/28 17:19:14
It doesn't matter, IPC::ChannelProxy has a thread-
hidehiko
2015/10/28 17:48:45
FYI: I believe this runs on the browser thread. As
Luis Héctor Chávez
2015/10/28 21:06:32
This can run on any thread (you're the second to m
| |
116 return ipc_channel_->Send(new ArcInstanceMsg_RegisterInputDevice( | |
117 name, device_type, base::FileDescriptor(fd.Pass()))); | |
118 } | |
119 | |
120 void ArcBridgeService::SocketConnect(const std::string& socket_path, | |
121 bool directory_creation_success) { | |
122 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
123 | |
124 if (!directory_creation_success) { | |
125 LOG(ERROR) << "Error creating directory for " << socket_path; | |
126 NotifyStateChanged(ArcBridgeService::ERROR); | |
127 return; | |
128 } | |
129 | |
130 if (!Connect(IPC::ChannelHandle(socket_path), | |
131 IPC::Channel::MODE_OPEN_NAMED_SERVER)) { | |
132 LOG(ERROR) << "Error connecting to " << socket_path; | |
133 NotifyStateChanged(ArcBridgeService::ERROR); | |
134 return; | |
135 } | |
136 | |
137 base::PostTaskAndReplyWithResult( | |
138 file_task_runner_.get(), | |
139 FROM_HERE, | |
140 base::Bind(&SocketPermissions, socket_path), | |
141 base::Bind(&ArcBridgeService::FinishConnectAfterSocketPermissions, | |
142 base::Unretained(this), socket_path)); | |
143 } | |
144 | |
145 void ArcBridgeService::FinishConnectAfterSocketPermissions( | |
146 const std::string& socket_path, bool socket_permissions_success) { | |
147 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
148 | |
149 if (!socket_permissions_success) { | |
150 LOG(ERROR) << "Error setting socket permissions for " << socket_path; | |
151 NotifyStateChanged(ArcBridgeService::ERROR); | |
152 return; | |
153 } | |
154 | |
155 // This will fail if the ArcInstanceService is not running on Chrome OS. | |
156 // Use base::Unretained since this is a KeyedService. | |
157 chromeos::DBusThreadManager::Get()->GetArcInstanceClient()->StartInstance( | |
158 socket_path, | |
159 base::Bind(&ArcBridgeService::OnInstanceStarted, base::Unretained(this))); | |
160 } | |
161 | |
162 | |
163 bool ArcBridgeService::Connect(const IPC::ChannelHandle& handle, | |
164 IPC::Channel::Mode mode) { | |
165 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
166 | |
167 ipc_channel_ = IPC::ChannelProxy::Create(handle, mode, this, | |
168 ipc_thread_.task_runner().get()); | |
169 if (!ipc_channel_) | |
170 return false; | |
171 NotifyStateChanged(ArcBridgeService::CONNECTED); | |
172 return true; | |
173 } | |
174 | |
175 void ArcBridgeService::OnInstanceReady() { | |
176 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
177 NotifyStateChanged(ArcBridgeService::READY); | |
178 } | |
179 | |
180 void ArcBridgeService::NotifyStateChanged(State state) { | |
181 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
182 if (state_ == state) | |
183 return; | |
184 state_ = state; | |
185 FOR_EACH_OBSERVER(Observer, observer_list_, OnStateChanged(state_)); | |
186 } | |
187 | |
188 void ArcBridgeService::FinishShutdownAfterSocketDeleted(bool socket_deleted) { | |
189 NotifyStateChanged(ArcBridgeService::STOPPED); | |
190 if (state_ != ArcBridgeService::STARTING && state_ != ArcBridgeService::READY) | |
191 return; | |
192 chromeos::DBusThreadManager::Get()->GetArcInstanceClient()->StopInstance( | |
193 base::Bind(&ArcBridgeService::OnInstanceStopped, base::Unretained(this))); | |
194 } | |
195 | |
196 bool ArcBridgeService::OnMessageReceived(const IPC::Message& message) { | |
197 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
198 bool handled = true; | |
199 | |
200 IPC_BEGIN_MESSAGE_MAP(ArcBridgeService, message) | |
201 IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_InstanceReady, OnInstanceReady) | |
202 IPC_MESSAGE_UNHANDLED(handled = false) | |
203 IPC_END_MESSAGE_MAP() | |
204 | |
205 if (!handled) | |
206 LOG(ERROR) << "Invalid message with type = " << message.type(); | |
207 return handled; | |
208 } | |
209 | |
210 void ArcBridgeService::OnInstanceStarted( | |
211 chromeos::DBusMethodCallStatus status) { | |
212 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
213 if (status != chromeos::DBUS_METHOD_CALL_SUCCESS) { | |
214 LOG(ERROR) << "ARC instance unable to start. Shutting down the bridge"; | |
215 Shutdown(); | |
216 return; | |
217 } | |
218 NotifyStateChanged(ArcBridgeService::STARTING); | |
219 } | |
220 | |
221 void ArcBridgeService::OnInstanceStopped( | |
222 chromeos::DBusMethodCallStatus status) { | |
223 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
224 NotifyStateChanged(ArcBridgeService::STOPPED); | |
225 } | |
226 | |
227 } // namespace arc | |
OLD | NEW |