Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / services / device / serial / serial_io_handler.cc
1 // Copyright 2014 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_io_handler.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/files/file_path.h"
13 #include "base/location.h"
14 #include "base/strings/string_util.h"
15 #include "base/task/task_traits.h"
16 #include "base/task/thread_pool.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "build/build_config.h"
19 #include "components/device_event_log/device_event_log.h"
20
21 #if BUILDFLAG(IS_CHROMEOS)
22 #include "chromeos/dbus/permission_broker/permission_broker_client.h"  // nogncheck
23 #endif  // BUILDFLAG(IS_CHROMEOS)
24
25 namespace device {
26
27 SerialIoHandler::SerialIoHandler(
28     const base::FilePath& port,
29     scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
30     : port_(port), ui_thread_task_runner_(ui_thread_task_runner) {
31   options_.bitrate = 9600;
32   options_.data_bits = mojom::SerialDataBits::EIGHT;
33   options_.parity_bit = mojom::SerialParityBit::NO_PARITY;
34   options_.stop_bits = mojom::SerialStopBits::ONE;
35   options_.cts_flow_control = false;
36   options_.has_cts_flow_control = true;
37 }
38
39 SerialIoHandler::~SerialIoHandler() {
40   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
41   Close(base::DoNothing());
42 }
43
44 void SerialIoHandler::Open(const mojom::SerialConnectionOptions& options,
45                            OpenCompleteCallback callback) {
46   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
47   DCHECK(!open_complete_);
48   DCHECK(!port_.empty());
49   open_complete_ = std::move(callback);
50   DCHECK(ui_thread_task_runner_.get());
51   MergeConnectionOptions(options);
52
53 #if BUILDFLAG(IS_CHROMEOS)
54   // Note: dbus clients are destroyed in PostDestroyThreads so passing |client|
55   // as unretained is safe.
56   auto* client = chromeos::PermissionBrokerClient::Get();
57   DCHECK(client) << "Could not get permission_broker client.";
58   // PermissionBrokerClient should be called on the UI thread.
59   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
60       base::ThreadTaskRunnerHandle::Get();
61   ui_thread_task_runner_->PostTask(
62       FROM_HERE,
63       base::BindOnce(&chromeos::PermissionBrokerClient::OpenPath,
64                      base::Unretained(client), port_.value(),
65                      base::BindRepeating(&SerialIoHandler::OnPathOpened, this,
66                                          task_runner),
67                      base::BindRepeating(&SerialIoHandler::OnPathOpenError,
68                                          this, task_runner)));
69 #else
70   base::ThreadPool::PostTask(
71       FROM_HERE,
72       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
73       base::BindOnce(&SerialIoHandler::StartOpen, this,
74                      base::ThreadTaskRunnerHandle::Get()));
75 #endif  // BUILDFLAG(IS_CHROMEOS)
76 }
77
78 #if BUILDFLAG(IS_CHROMEOS)
79
80 void SerialIoHandler::OnPathOpened(
81     scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
82     base::ScopedFD fd) {
83   base::File file(std::move(fd));
84   io_thread_task_runner->PostTask(
85       FROM_HERE,
86       base::BindOnce(&SerialIoHandler::FinishOpen, this, std::move(file)));
87 }
88
89 void SerialIoHandler::OnPathOpenError(
90     scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
91     const std::string& error_name,
92     const std::string& error_message) {
93   io_thread_task_runner->PostTask(
94       FROM_HERE, base::BindOnce(&SerialIoHandler::ReportPathOpenError, this,
95                                 error_name, error_message));
96 }
97
98 void SerialIoHandler::ReportPathOpenError(const std::string& error_name,
99                                           const std::string& error_message) {
100   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
101   DCHECK(open_complete_);
102   SERIAL_LOG(ERROR) << "Permission broker failed to open '" << port_
103                     << "': " << error_name << ": " << error_message;
104   std::move(open_complete_).Run(false);
105 }
106
107 #endif  // BUILDFLAG(IS_CHROMEOS)
108
109 void SerialIoHandler::MergeConnectionOptions(
110     const mojom::SerialConnectionOptions& options) {
111   if (options.bitrate) {
112     options_.bitrate = options.bitrate;
113   }
114   if (options.data_bits != mojom::SerialDataBits::NONE) {
115     options_.data_bits = options.data_bits;
116   }
117   if (options.parity_bit != mojom::SerialParityBit::NONE) {
118     options_.parity_bit = options.parity_bit;
119   }
120   if (options.stop_bits != mojom::SerialStopBits::NONE) {
121     options_.stop_bits = options.stop_bits;
122   }
123   if (options.has_cts_flow_control) {
124     DCHECK(options_.has_cts_flow_control);
125     options_.cts_flow_control = options.cts_flow_control;
126   }
127 }
128
129 void SerialIoHandler::StartOpen(
130     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
131   DCHECK(open_complete_);
132   DCHECK(!file_.IsValid());
133   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
134               base::File::FLAG_WIN_EXCLUSIVE_READ | base::File::FLAG_WRITE |
135               base::File::FLAG_WIN_EXCLUSIVE_WRITE | base::File::FLAG_ASYNC |
136               base::File::FLAG_TERMINAL_DEVICE;
137   base::File file(port_, flags);
138   io_task_runner->PostTask(
139       FROM_HERE,
140       base::BindOnce(&SerialIoHandler::FinishOpen, this, std::move(file)));
141 }
142
143 void SerialIoHandler::FinishOpen(base::File file) {
144   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
145   DCHECK(open_complete_);
146   if (!file.IsValid()) {
147     SERIAL_LOG(ERROR) << "Failed to open serial port: "
148                       << base::File::ErrorToString(file.error_details());
149     std::move(open_complete_).Run(false);
150     return;
151   }
152
153   file_ = std::move(file);
154
155   bool success = PostOpen() && ConfigurePortImpl();
156   if (!success)
157     Close(base::DoNothing());
158
159   std::move(open_complete_).Run(success);
160 }
161
162 bool SerialIoHandler::PostOpen() {
163   return true;
164 }
165
166 void SerialIoHandler::PreClose() {}
167
168 void SerialIoHandler::Close(base::OnceClosure callback) {
169   if (file_.IsValid()) {
170     CancelRead(mojom::SerialReceiveError::DISCONNECTED);
171     CancelWrite(mojom::SerialSendError::DISCONNECTED);
172     PreClose();
173     base::ThreadPool::PostTaskAndReply(
174         FROM_HERE,
175         {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
176         base::BindOnce(&SerialIoHandler::DoClose, std::move(file_)),
177         std::move(callback));
178   } else {
179     std::move(callback).Run();
180   }
181 }
182
183 // static
184 void SerialIoHandler::DoClose(base::File port) {
185   // port closed by destructor.
186 }
187
188 void SerialIoHandler::Read(base::span<uint8_t> buffer,
189                            ReadCompleteCallback callback) {
190   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
191   DCHECK(!IsReadPending());
192
193   pending_read_buffer_ = buffer;
194   pending_read_callback_ = std::move(callback);
195   read_canceled_ = false;
196   AddRef();
197
198   if (!file().IsValid()) {
199     ReadCompleted(0, mojom::SerialReceiveError::DISCONNECTED);
200     return;
201   }
202
203   ReadImpl();
204 }
205
206 void SerialIoHandler::Write(base::span<const uint8_t> buffer,
207                             WriteCompleteCallback callback) {
208   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
209   DCHECK(!IsWritePending());
210
211   pending_write_buffer_ = buffer;
212   pending_write_callback_ = std::move(callback);
213   write_canceled_ = false;
214   AddRef();
215
216   if (!file().IsValid()) {
217     WriteCompleted(0, mojom::SerialSendError::DISCONNECTED);
218     return;
219   }
220
221   WriteImpl();
222 }
223
224 void SerialIoHandler::ReadCompleted(int bytes_read,
225                                     mojom::SerialReceiveError error) {
226   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
227   DCHECK(IsReadPending());
228   pending_read_buffer_ = base::span<uint8_t>();
229   std::move(pending_read_callback_).Run(bytes_read, error);
230   Release();
231 }
232
233 void SerialIoHandler::WriteCompleted(int bytes_written,
234                                      mojom::SerialSendError error) {
235   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
236   DCHECK(IsWritePending());
237   pending_write_buffer_ = base::span<const uint8_t>();
238   std::move(pending_write_callback_).Run(bytes_written, error);
239   Release();
240 }
241
242 bool SerialIoHandler::IsReadPending() const {
243   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
244   return !pending_read_callback_.is_null();
245 }
246
247 bool SerialIoHandler::IsWritePending() const {
248   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
249   return !pending_write_callback_.is_null();
250 }
251
252 void SerialIoHandler::CancelRead(mojom::SerialReceiveError reason) {
253   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
254   if (IsReadPending() && !read_canceled_) {
255     read_canceled_ = true;
256     read_cancel_reason_ = reason;
257     CancelReadImpl();
258   }
259 }
260
261 void SerialIoHandler::CancelWrite(mojom::SerialSendError reason) {
262   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
263   if (IsWritePending() && !write_canceled_) {
264     write_canceled_ = true;
265     write_cancel_reason_ = reason;
266     CancelWriteImpl();
267   }
268 }
269
270 bool SerialIoHandler::ConfigurePort(
271     const mojom::SerialConnectionOptions& options) {
272   MergeConnectionOptions(options);
273   return ConfigurePortImpl();
274 }
275
276 }  // namespace device