Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / services / device / serial / serial_port_impl.cc
1 // Copyright 2017 The Chromium Authors
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 "services/device/serial/serial_port_impl.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/task/single_thread_task_runner.h"
13 #include "services/device/serial/serial_io_handler.h"
14
15 namespace device {
16
17 // static
18 void SerialPortImpl::Open(
19     const base::FilePath& path,
20     mojom::SerialConnectionOptionsPtr options,
21     mojo::PendingRemote<mojom::SerialPortClient> client,
22     mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
23     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
24     OpenCallback callback) {
25   // This SerialPortImpl is owned by |receiver_| and |watcher_| and will
26   // self-destruct on close.
27   auto* port = new SerialPortImpl(
28       device::SerialIoHandler::Create(path, std::move(ui_task_runner)),
29       std::move(client), std::move(watcher));
30   port->OpenPort(*options, std::move(callback));
31 }
32
33 // static
34 void SerialPortImpl::OpenForTesting(
35     scoped_refptr<SerialIoHandler> io_handler,
36     mojom::SerialConnectionOptionsPtr options,
37     mojo::PendingRemote<mojom::SerialPortClient> client,
38     mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
39     OpenCallback callback) {
40   // This SerialPortImpl is owned by |receiver| and |watcher| and will
41   // self-destruct on close.
42   auto* port = new SerialPortImpl(std::move(io_handler), std::move(client),
43                                   std::move(watcher));
44   port->OpenPort(*options, std::move(callback));
45 }
46
47 SerialPortImpl::SerialPortImpl(
48     scoped_refptr<SerialIoHandler> io_handler,
49     mojo::PendingRemote<mojom::SerialPortClient> client,
50     mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher)
51     : io_handler_(std::move(io_handler)),
52       client_(std::move(client)),
53       watcher_(std::move(watcher)),
54       in_stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
55       out_stream_watcher_(FROM_HERE,
56                           mojo::SimpleWatcher::ArmingPolicy::MANUAL) {
57   if (watcher_.is_bound()) {
58     watcher_.set_disconnect_handler(base::BindOnce(
59         [](SerialPortImpl* self) { delete self; }, base::Unretained(this)));
60   }
61 }
62
63 SerialPortImpl::~SerialPortImpl() {
64   // Cancel I/O operations so that |io_handler_| drops its self-reference.
65   io_handler_->Close(base::DoNothing());
66 }
67
68 void SerialPortImpl::OpenPort(const mojom::SerialConnectionOptions& options,
69                               OpenCallback callback) {
70   io_handler_->Open(
71       options, base::BindOnce(&SerialPortImpl::PortOpened,
72                               weak_factory_.GetWeakPtr(), std::move(callback)));
73 }
74
75 void SerialPortImpl::PortOpened(OpenCallback callback, bool success) {
76   mojo::PendingRemote<SerialPort> port;
77   if (success) {
78     port = receiver_.BindNewPipeAndPassRemote();
79     receiver_.set_disconnect_handler(base::BindOnce(
80         [](SerialPortImpl* self) { delete self; }, base::Unretained(this)));
81   }
82
83   std::move(callback).Run(std::move(port));
84
85   if (!success)
86     delete this;
87 }
88
89 void SerialPortImpl::StartWriting(mojo::ScopedDataPipeConsumerHandle consumer) {
90   if (in_stream_) {
91     receiver_.ReportBadMessage("Data pipe consumer still open.");
92     return;
93   }
94
95   in_stream_watcher_.Cancel();
96   in_stream_ = std::move(consumer);
97   in_stream_watcher_.Watch(
98       in_stream_.get(),
99       MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
100       MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
101       base::BindRepeating(&SerialPortImpl::WriteToPort,
102                           weak_factory_.GetWeakPtr()));
103   in_stream_watcher_.ArmOrNotify();
104 }
105
106 void SerialPortImpl::StartReading(mojo::ScopedDataPipeProducerHandle producer) {
107   if (out_stream_) {
108     receiver_.ReportBadMessage("Data pipe producer still open.");
109     return;
110   }
111
112   out_stream_watcher_.Cancel();
113   out_stream_ = std::move(producer);
114   out_stream_watcher_.Watch(
115       out_stream_.get(),
116       MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
117       MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
118       base::BindRepeating(&SerialPortImpl::ReadFromPortAndWriteOut,
119                           weak_factory_.GetWeakPtr()));
120   out_stream_watcher_.ArmOrNotify();
121 }
122
123 void SerialPortImpl::Flush(mojom::SerialPortFlushMode mode,
124                            FlushCallback callback) {
125   switch (mode) {
126     case mojom::SerialPortFlushMode::kReceiveAndTransmit:
127       // Do nothing. This case exists to support the chrome.serial.flush()
128       // method.
129       break;
130     case mojom::SerialPortFlushMode::kReceive:
131       io_handler_->CancelRead(mojom::SerialReceiveError::NONE);
132       break;
133     case mojom::SerialPortFlushMode::kTransmit:
134       io_handler_->CancelWrite(mojom::SerialSendError::NONE);
135       break;
136   }
137
138   io_handler_->Flush(mode);
139
140   switch (mode) {
141     case mojom::SerialPortFlushMode::kReceiveAndTransmit:
142       // Do nothing. This case exists to support the chrome.serial.flush()
143       // method.
144       break;
145     case mojom::SerialPortFlushMode::kReceive:
146       if (io_handler_->IsReadPending()) {
147         // Delay closing |out_stream_| because |io_handler_| still holds a
148         // pointer into the shared memory owned by the pipe.
149         read_flush_callback_ = std::move(callback);
150         return;
151       }
152
153       out_stream_watcher_.Cancel();
154       out_stream_.reset();
155       break;
156     case mojom::SerialPortFlushMode::kTransmit:
157       if (io_handler_->IsWritePending()) {
158         // Delay closing |in_stream_| because |io_handler_| still holds a
159         // pointer into the shared memory owned by the pipe.
160         write_flush_callback_ = std::move(callback);
161         return;
162       }
163
164       in_stream_watcher_.Cancel();
165       in_stream_.reset();
166       break;
167   }
168
169   std::move(callback).Run();
170 }
171
172 void SerialPortImpl::Drain(DrainCallback callback) {
173   if (!in_stream_) {
174     std::move(callback).Run();
175     return;
176   }
177
178   drain_callback_ = std::move(callback);
179 }
180
181 void SerialPortImpl::GetControlSignals(GetControlSignalsCallback callback) {
182   std::move(callback).Run(io_handler_->GetControlSignals());
183 }
184
185 void SerialPortImpl::SetControlSignals(
186     mojom::SerialHostControlSignalsPtr signals,
187     SetControlSignalsCallback callback) {
188   std::move(callback).Run(io_handler_->SetControlSignals(*signals));
189 }
190
191 void SerialPortImpl::ConfigurePort(mojom::SerialConnectionOptionsPtr options,
192                                    ConfigurePortCallback callback) {
193   std::move(callback).Run(io_handler_->ConfigurePort(*options));
194   // Cancel pending reading as the new configure options are applied.
195   io_handler_->CancelRead(mojom::SerialReceiveError::NONE);
196 }
197
198 void SerialPortImpl::GetPortInfo(GetPortInfoCallback callback) {
199   std::move(callback).Run(io_handler_->GetPortInfo());
200 }
201
202 void SerialPortImpl::Close(bool flush, CloseCallback callback) {
203   if (flush) {
204     io_handler_->Flush(mojom::SerialPortFlushMode::kReceiveAndTransmit);
205   }
206
207   io_handler_->Close(base::BindOnce(&SerialPortImpl::PortClosed,
208                                     weak_factory_.GetWeakPtr(),
209                                     std::move(callback)));
210 }
211
212 void SerialPortImpl::WriteToPort(MojoResult result,
213                                  const mojo::HandleSignalsState& state) {
214   const void* buffer;
215   uint32_t num_bytes;
216
217   if (result == MOJO_RESULT_OK) {
218     DCHECK(in_stream_);
219     result = in_stream_->BeginReadData(&buffer, &num_bytes,
220                                        MOJO_WRITE_DATA_FLAG_NONE);
221   }
222   if (result == MOJO_RESULT_OK) {
223     io_handler_->Write(
224         base::make_span(reinterpret_cast<const uint8_t*>(buffer), num_bytes),
225         base::BindOnce(&SerialPortImpl::OnWriteToPortCompleted,
226                        weak_factory_.GetWeakPtr(), num_bytes));
227     return;
228   }
229   if (result == MOJO_RESULT_SHOULD_WAIT) {
230     // If there is no space to write, wait for more space.
231     in_stream_watcher_.ArmOrNotify();
232     return;
233   }
234   if (result == MOJO_RESULT_FAILED_PRECONDITION ||
235       result == MOJO_RESULT_CANCELLED) {
236     // The |in_stream_| has been closed.
237     in_stream_watcher_.Cancel();
238     in_stream_.reset();
239
240     if (drain_callback_) {
241       io_handler_->Drain();
242       std::move(drain_callback_).Run();
243     }
244     return;
245   }
246   // The code should not reach other cases.
247   NOTREACHED();
248 }
249
250 void SerialPortImpl::OnWriteToPortCompleted(uint32_t bytes_expected,
251                                             uint32_t bytes_sent,
252                                             mojom::SerialSendError error) {
253   DCHECK(in_stream_);
254   in_stream_->EndReadData(bytes_sent);
255
256   if (error != mojom::SerialSendError::NONE) {
257     in_stream_watcher_.Cancel();
258     in_stream_.reset();
259     if (client_) {
260       client_->OnSendError(error);
261     }
262     return;
263   }
264
265   in_stream_watcher_.ArmOrNotify();
266 }
267
268 void SerialPortImpl::ReadFromPortAndWriteOut(
269     MojoResult result,
270     const mojo::HandleSignalsState& state) {
271   void* buffer;
272   uint32_t num_bytes;
273   if (result == MOJO_RESULT_OK) {
274     DCHECK(out_stream_);
275     result = out_stream_->BeginWriteData(&buffer, &num_bytes,
276                                          MOJO_WRITE_DATA_FLAG_NONE);
277   }
278   if (result == MOJO_RESULT_OK) {
279     io_handler_->Read(
280         base::make_span(reinterpret_cast<uint8_t*>(buffer), num_bytes),
281         base::BindOnce(&SerialPortImpl::WriteToOutStream,
282                        weak_factory_.GetWeakPtr()));
283     return;
284   }
285   if (result == MOJO_RESULT_SHOULD_WAIT) {
286     // If there is no space to write, wait for more space.
287     out_stream_watcher_.ArmOrNotify();
288     return;
289   }
290   if (result == MOJO_RESULT_FAILED_PRECONDITION ||
291       result == MOJO_RESULT_CANCELLED) {
292     // The |out_stream_| has been closed.
293     out_stream_watcher_.Cancel();
294     out_stream_.reset();
295     return;
296   }
297   // The code should not reach other cases.
298   NOTREACHED() << "Unexpected Mojo result: " << result;
299 }
300
301 void SerialPortImpl::WriteToOutStream(uint32_t bytes_read,
302                                       mojom::SerialReceiveError error) {
303   DCHECK(out_stream_);
304   out_stream_->EndWriteData(bytes_read);
305
306   if (error != mojom::SerialReceiveError::NONE) {
307     out_stream_watcher_.Cancel();
308     out_stream_.reset();
309     if (client_)
310       client_->OnReadError(error);
311     if (read_flush_callback_)
312       std::move(read_flush_callback_).Run();
313     return;
314   }
315
316   if (read_flush_callback_) {
317     std::move(read_flush_callback_).Run();
318     out_stream_watcher_.Cancel();
319     out_stream_.reset();
320     return;
321   }
322
323   out_stream_watcher_.ArmOrNotify();
324 }
325
326 void SerialPortImpl::PortClosed(CloseCallback callback) {
327   std::move(callback).Run();
328   delete this;
329 }
330
331 }  // namespace device