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

Side by Side Diff: media/capture/video/chromeos/arc_camera3_service.cc

Issue 2878233002: media: add ArcCamera3Service Mojo service (Closed)
Patch Set: rebase on latest patch set of issue 2837273004 Created 3 years, 6 months 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 2017 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 "media/capture/video/chromeos/arc_camera3_service.h"
6
7 #include <fcntl.h>
8 #include <grp.h>
9 #include <poll.h>
10 #include <sys/uio.h>
11
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "mojo/edk/embedder/embedder.h"
16 #include "mojo/edk/embedder/named_platform_handle.h"
17 #include "mojo/edk/embedder/named_platform_handle_utils.h"
18 #include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
19 #include "mojo/edk/embedder/platform_channel_pair.h"
20 #include "mojo/edk/embedder/platform_channel_utils_posix.h"
21 #include "mojo/edk/embedder/platform_handle_vector.h"
22 #include "mojo/edk/embedder/scoped_platform_handle.h"
23
24 namespace media {
25
26 namespace {
27
28 const base::FilePath::CharType kArcCamera3SocketPath[] =
29 "/var/run/camera/camera3.sock";
30 const char kArcCameraGroup[] = "arc-camera";
31
32 // Creates a pipe. Returns true on success, otherwise false.
33 // On success, |read_fd| will be set to the fd of the read side, and
34 // |write_fd| will be set to the one of write side.
35 static bool CreatePipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) {
36 int fds[2];
37 if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) {
38 PLOG(ERROR) << "pipe2 failed: ";
39 return false;
40 }
41
42 read_fd->reset(fds[0]);
43 write_fd->reset(fds[1]);
44 return true;
45 }
46
47 // Waits until |raw_socket_fd| is readable.
48 // The operation may be cancelled originally triggered by user interaction to
49 // disable ARC, or ARC instance is unexpectedly stopped (e.g. crash).
50 // To notify such a situation, |raw_cancel_fd| is also passed to here, and the
51 // write side will be closed in such a case.
52 static bool WaitForSocketReadable(int raw_socket_fd, int raw_cancel_fd) {
53 struct pollfd fds[2] = {
54 {raw_socket_fd, POLLIN, 0}, {raw_cancel_fd, POLLIN, 0},
55 };
56
57 if (HANDLE_EINTR(poll(fds, arraysize(fds), -1)) <= 0) {
58 PLOG(ERROR) << "poll failed: ";
59 return false;
60 }
61
62 if (fds[1].revents) {
63 VLOG(1) << "Stop() was called";
64 return false;
65 }
66
67 DCHECK(fds[0].revents);
68 return true;
69 }
70
71 class MojoCameraClient : public ArcCamera3Service::CameraClientObserver {
72 public:
73 explicit MojoCameraClient(arc::mojom::ArcCamera3ClientPtr client)
74 : client_(std::move(client)) {}
75
76 void NotifyCameraHalRegistered(
77 arc::mojom::CameraModulePtr camera_module) override {
78 client_->NotifyCameraHalRegistered(std::move(camera_module));
79 }
80
81 arc::mojom::ArcCamera3ClientPtr& client() { return client_; }
82
83 private:
84 arc::mojom::ArcCamera3ClientPtr client_;
85 DISALLOW_IMPLICIT_CONSTRUCTORS(MojoCameraClient);
86 };
87
88 } // namespace
89
90 ArcCamera3Service::CameraHal::CameraHal(arc::mojom::ArcCamera3HalPtr camera_hal)
91 : camera_hal_(std::move(camera_hal)) {}
92
93 void ArcCamera3Service::CameraHal::OpenCameraHal(
94 arc::mojom::CameraModuleRequest camera_module_request) {
95 camera_hal_->OpenCameraHal(std::move(camera_module_request));
96 }
97
98 // static
99 ArcCamera3Service* ArcCamera3Service::GetInstance() {
100 return base::Singleton<ArcCamera3Service>::get();
101 }
102
103 bool ArcCamera3Service::Start() {
104 DCHECK(!proxy_thread_.IsRunning());
105 DCHECK(!blocking_io_thread_.IsRunning());
106
107 if (!proxy_thread_.Start()) {
108 LOG(ERROR) << "Failed to start proxy thread";
109 return false;
110 }
111 if (!blocking_io_thread_.Start()) {
112 LOG(ERROR) << "Failed to start blocking IO thread";
113 return false;
114 }
115 proxy_task_runner_ = proxy_thread_.task_runner();
116 blocking_io_task_runner_ = blocking_io_thread_.task_runner();
117
118 blocking_io_task_runner_->PostTask(
119 FROM_HERE,
120 base::Bind(&ArcCamera3Service::CreateSocket, base::Unretained(this)));
121 return true;
122 }
123
124 void ArcCamera3Service::AddClientObserver(
125 std::unique_ptr<CameraClientObserver> observer) {
126 DCHECK(proxy_thread_.IsRunning());
127 proxy_thread_.task_runner()->PostTask(
128 FROM_HERE,
129 base::BindOnce(&ArcCamera3Service::AddClientObserverOnProxyThread,
130 base::Unretained(this), base::Passed(&observer)));
131 }
132
133 ArcCamera3Service::ArcCamera3Service()
134 : proxy_thread_("ProxyThread"), blocking_io_thread_("BlockingIOThread") {}
135
136 ArcCamera3Service::~ArcCamera3Service() {
137 VLOG(1) << "Stopping ArcCamera3Service...";
138 proxy_thread_.task_runner()->PostTask(
139 FROM_HERE, base::Bind(&ArcCamera3Service::StopOnProxyThread,
140 base::Unretained(this)));
141 proxy_thread_.Stop();
142 blocking_io_thread_.Stop();
143 VLOG(1) << "ArcCamera3Service stopped";
144 }
145
146 void ArcCamera3Service::CreateSocket() {
147 DCHECK(blocking_io_task_runner_->BelongsToCurrentThread());
148
149 base::FilePath socket_path(kArcCamera3SocketPath);
150 mojo::edk::ScopedPlatformHandle socket_fd = mojo::edk::CreateServerHandle(
151 mojo::edk::NamedPlatformHandle(socket_path.value()));
152 if (!socket_fd.is_valid()) {
153 LOG(ERROR) << "Failed to create the socket file: " << kArcCamera3SocketPath;
154 return;
155 }
156
157 // Change permissions on the socket.
158 struct group arc_camera_group;
159 struct group* result = nullptr;
160 char buf[1024];
161 if (HANDLE_EINTR(getgrnam_r(kArcCameraGroup, &arc_camera_group, buf,
162 sizeof(buf), &result)) < 0) {
163 PLOG(ERROR) << "getgrnam_r failed: ";
164 return;
165 }
166
167 if (!result) {
168 LOG(ERROR) << "Group '" << kArcCameraGroup << "' not found";
169 return;
170 }
171
172 if (HANDLE_EINTR(chown(kArcCamera3SocketPath, -1, arc_camera_group.gr_gid)) <
173 0) {
174 PLOG(ERROR) << "chown failed: ";
175 return;
176 }
177
178 if (!base::SetPosixFilePermissions(socket_path, 0660)) {
179 PLOG(ERROR) << "Could not set permissions: " << socket_path.value() << ": ";
180 return;
181 }
182
183 blocking_io_task_runner_->PostTask(
184 FROM_HERE, base::Bind(&ArcCamera3Service::CreateServiceLoop,
185 base::Unretained(this), base::Passed(&socket_fd)));
186 }
187
188 void ArcCamera3Service::CreateServiceLoop(
189 mojo::edk::ScopedPlatformHandle socket_fd) {
190 DCHECK(blocking_io_task_runner_->BelongsToCurrentThread());
191 DCHECK(!proxy_fd_.is_valid());
192 DCHECK(!cancel_pipe_.is_valid());
193 DCHECK(socket_fd.is_valid());
194
195 proxy_fd_ = std::move(socket_fd);
196
197 base::ScopedFD cancel_fd;
198 if (!CreatePipe(&cancel_fd, &cancel_pipe_)) {
199 LOG(ERROR) << "Failed to create cancel pipe";
200 return;
201 }
202
203 blocking_io_task_runner_->PostTask(
204 FROM_HERE, base::Bind(&ArcCamera3Service::WaitForIncomingConnection,
205 base::Unretained(this), base::Passed(&cancel_fd)));
206 VLOG(1) << "ArcCamera3Service started";
207 }
208
209 void ArcCamera3Service::WaitForIncomingConnection(base::ScopedFD cancel_fd) {
210 DCHECK(blocking_io_task_runner_->BelongsToCurrentThread());
211 DCHECK(proxy_fd_.is_valid());
212 VLOG(1) << "Waiting for incoming connection...";
213
214 if (!proxy_fd_.is_valid()) {
215 LOG(ERROR) << "Invalid proxy fd";
216 return;
217 }
218
219 if (!WaitForSocketReadable(proxy_fd_.get().handle, cancel_fd.get())) {
220 VLOG(1) << "Quit ArcCamera3Service IO thread";
221 return;
222 }
223
224 mojo::edk::ScopedPlatformHandle accepted_fd;
225 if (mojo::edk::ServerAcceptConnection(proxy_fd_.get(), &accepted_fd, false) &&
226 accepted_fd.is_valid()) {
227 VLOG(1) << "Accepted a connection";
228 // Hardcode pid 0 since it is unused in mojo.
229 const base::ProcessHandle kUnusedChildProcessHandle = 0;
230 mojo::edk::PlatformChannelPair channel_pair;
231 mojo::edk::OutgoingBrokerClientInvitation invitation;
232
233 std::string token = mojo::edk::GenerateRandomToken();
234 mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe(token);
235
236 invitation.Send(
237 kUnusedChildProcessHandle,
238 mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
239 channel_pair.PassServerHandle()));
240
241 mojo::edk::ScopedPlatformHandleVectorPtr handles(
242 new mojo::edk::PlatformHandleVector{
243 channel_pair.PassClientHandle().release()});
244
245 struct iovec iov = {const_cast<char*>(token.c_str()), token.length()};
246 ssize_t result = mojo::edk::PlatformChannelSendmsgWithHandles(
247 accepted_fd.get(), &iov, 1, handles->data(), handles->size());
248 if (result == -1) {
249 PLOG(ERROR) << "sendmsg failed: ";
250 } else {
251 proxy_task_runner_->PostTask(
252 FROM_HERE, base::Bind(&ArcCamera3Service::OnPeerConnected,
253 base::Unretained(this), base::Passed(&pipe)));
254 }
255 }
256
257 // Continue waiting for new connections.
258 blocking_io_task_runner_->PostTask(
259 FROM_HERE, base::Bind(&ArcCamera3Service::WaitForIncomingConnection,
260 base::Unretained(this), base::Passed(&cancel_fd)));
261 }
262
263 void ArcCamera3Service::RegisterCameraHal(
264 arc::mojom::ArcCamera3HalPtr camera_hal) {
265 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
266 DCHECK(!camera_hal_);
267 camera_hal.set_connection_error_handler(base::Bind(
268 &ArcCamera3Service::OnCameraHalConnectionError, base::Unretained(this)));
269 camera_hal_.reset(new CameraHal(std::move(camera_hal)));
270 VLOG(1) << "Camera HAL registered";
271 for (auto& observer : client_observers_) {
272 arc::mojom::CameraModulePtr camera_module_ptr;
273 arc::mojom::CameraModuleRequest camera_module_request =
274 mojo::MakeRequest(&camera_module_ptr);
275 camera_hal_->OpenCameraHal(std::move(camera_module_request));
276 observer->NotifyCameraHalRegistered(std::move(camera_module_ptr));
277 }
278 }
279
280 void ArcCamera3Service::RegisterClient(arc::mojom::ArcCamera3ClientPtr client) {
281 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
282 MojoCameraClient* camera_client = new MojoCameraClient(std::move(client));
283 std::unique_ptr<CameraClientObserver> client_observer(camera_client);
284 camera_client->client().set_connection_error_handler(base::Bind(
285 &ArcCamera3Service::OnMojoClientConnectionError, base::Unretained(this),
286 base::Unretained(client_observer.get())));
287 AddClientObserver(std::move(client_observer));
288 VLOG(1) << "New mojo client registered";
289 }
290
291 void ArcCamera3Service::AddClientObserverOnProxyThread(
292 std::unique_ptr<CameraClientObserver> observer) {
293 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
294 if (camera_hal_) {
295 arc::mojom::CameraModulePtr camera_module_ptr;
296 arc::mojom::CameraModuleRequest camera_module_request =
297 mojo::MakeRequest(&camera_module_ptr);
298 camera_hal_->OpenCameraHal(std::move(camera_module_request));
299 observer->NotifyCameraHalRegistered(std::move(camera_module_ptr));
300 }
301 client_observers_.insert(std::move(observer));
302 }
303
304 void ArcCamera3Service::OnPeerConnected(
305 mojo::ScopedMessagePipeHandle message_pipe) {
306 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
307 auto binding = base::MakeUnique<mojo::Binding<arc::mojom::ArcCamera3Service>>(
308 this, mojo::InterfaceRequest<arc::mojom::ArcCamera3Service>(
309 std::move(message_pipe)));
310 bindings_.push_back(std::move(binding));
311 VLOG(1) << "New binding added";
312 }
313
314 void ArcCamera3Service::OnCameraHalConnectionError() {
315 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
316 VLOG(1) << "Camera HAL connection lost";
317 camera_hal_.reset();
318 }
319
320 void ArcCamera3Service::OnMojoClientConnectionError(
321 CameraClientObserver* client_observer) {
322 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
323 for (auto& it : client_observers_) {
324 if (it.get() == client_observer) {
325 client_observers_.erase(it);
326 VLOG(1) << "Mojo client connection lost";
327 break;
328 }
329 }
330 }
331
332 void ArcCamera3Service::StopOnProxyThread() {
333 DCHECK(proxy_task_runner_->BelongsToCurrentThread());
334 base::DeleteFile(base::FilePath(kArcCamera3SocketPath),
335 /* recursive */ false);
336 // Close |cancel_pipe_| to quit the loop in WaitForIncomingConnection.
337 cancel_pipe_.reset();
338 client_observers_.clear();
339 camera_hal_.reset();
340 bindings_.clear();
341 }
342
343 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/chromeos/arc_camera3_service.h ('k') | media/capture/video/chromeos/camera_device_delegate_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698