1 // Copyright 2020 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.
5 #include "services/device/serial/bluetooth_serial_port_impl.h"
10 #include "base/callback_helpers.h"
11 #include "base/command_line.h"
12 #include "base/containers/contains.h"
13 #include "net/base/io_buffer.h"
14 #include "services/device/public/cpp/bluetooth/bluetooth_utils.h"
15 #include "services/device/public/cpp/serial/serial_switches.h"
20 void BluetoothSerialPortImpl::Open(
21 scoped_refptr<BluetoothAdapter> adapter,
22 const std::string& address,
23 const BluetoothUUID& service_class_id,
24 mojom::SerialConnectionOptionsPtr options,
25 mojo::PendingRemote<mojom::SerialPortClient> client,
26 mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher,
27 OpenCallback callback) {
28 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
29 switches::kEnableBluetoothSerialPortProfileInSerialApi));
31 // This BluetoothSerialPortImpl is owned by its |receiver_| and |watcher_| and
32 // will self-destruct on connection failure.
33 auto* port = new BluetoothSerialPortImpl(
34 std::move(adapter), address, std::move(options), std::move(client),
36 port->OpenSocket(service_class_id, std::move(callback));
39 BluetoothSerialPortImpl::BluetoothSerialPortImpl(
40 scoped_refptr<BluetoothAdapter> adapter,
41 const std::string& address,
42 mojom::SerialConnectionOptionsPtr options,
43 mojo::PendingRemote<mojom::SerialPortClient> client,
44 mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher)
45 : watcher_(std::move(watcher)),
46 client_(std::move(client)),
47 in_stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
48 out_stream_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
49 bluetooth_adapter_(std::move(adapter)),
51 options_(std::move(options)) {
52 if (watcher_.is_bound()) {
53 watcher_.set_disconnect_handler(
54 base::BindOnce([](BluetoothSerialPortImpl* self) { delete self; },
55 base::Unretained(this)));
59 BluetoothSerialPortImpl::~BluetoothSerialPortImpl() {
60 if (bluetooth_socket_)
61 bluetooth_socket_->Disconnect(base::DoNothing());
64 void BluetoothSerialPortImpl::OpenSocket(const BluetoothUUID& service_class_id,
65 OpenCallback callback) {
66 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
67 BluetoothDevice* device = bluetooth_adapter_->GetDevice(address_);
69 std::move(callback).Run(mojo::NullRemote());
74 auto split_callback = base::SplitOnceCallback(std::move(callback));
75 device->ConnectToService(
77 base::BindOnce(&BluetoothSerialPortImpl::OnSocketConnected,
78 weak_ptr_factory_.GetWeakPtr(),
79 std::move(split_callback.first)),
80 base::BindOnce(&BluetoothSerialPortImpl::OnSocketConnectedError,
81 weak_ptr_factory_.GetWeakPtr(),
82 std::move(split_callback.second)));
85 void BluetoothSerialPortImpl::OnSocketConnected(
86 OpenCallback callback,
87 scoped_refptr<BluetoothSocket> socket) {
88 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
90 bluetooth_socket_ = std::move(socket);
91 mojo::PendingRemote<mojom::SerialPort> port =
92 receiver_.BindNewPipeAndPassRemote();
93 receiver_.set_disconnect_handler(
94 base::BindOnce([](BluetoothSerialPortImpl* self) { delete self; },
95 base::Unretained(this)));
96 std::move(callback).Run(std::move(port));
99 void BluetoothSerialPortImpl::OnSocketConnectedError(
100 OpenCallback callback,
101 const std::string& message) {
102 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
103 std::move(callback).Run(mojo::NullRemote());
107 void BluetoothSerialPortImpl::StartWriting(
108 mojo::ScopedDataPipeConsumerHandle consumer) {
109 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
112 receiver_.ReportBadMessage("Data pipe consumer still open.");
116 if (!bluetooth_socket_) {
117 receiver_.ReportBadMessage("No Bluetooth socket.");
121 in_stream_watcher_.Cancel();
122 in_stream_ = std::move(consumer);
123 in_stream_watcher_.Watch(
125 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
126 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
127 base::BindRepeating(&BluetoothSerialPortImpl::WriteToSocket,
128 weak_ptr_factory_.GetWeakPtr()));
130 in_stream_watcher_.ArmOrNotify();
133 void BluetoothSerialPortImpl::StartReading(
134 mojo::ScopedDataPipeProducerHandle producer) {
135 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
137 mojo::ReportBadMessage("Data pipe producer still open.");
141 if (!bluetooth_socket_) {
142 mojo::ReportBadMessage("No Bluetooth socket.");
146 out_stream_watcher_.Cancel();
147 out_stream_ = std::move(producer);
149 out_stream_watcher_.Watch(
151 MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
152 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
153 base::BindRepeating(&BluetoothSerialPortImpl::ReadFromSocketAndWriteOut,
154 weak_ptr_factory_.GetWeakPtr()));
156 out_stream_watcher_.ArmOrNotify();
159 void BluetoothSerialPortImpl::ReadFromSocketAndWriteOut(
161 const mojo::HandleSignalsState& state) {
162 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
165 DCHECK(!read_pending_);
168 case MOJO_RESULT_SHOULD_WAIT:
169 // If there is no space to write, wait for more space.
170 out_stream_watcher_.ArmOrNotify();
172 case MOJO_RESULT_FAILED_PRECONDITION:
173 case MOJO_RESULT_CANCELLED:
174 // The |out_stream_| has been closed.
175 out_stream_watcher_.Cancel();
179 NOTREACHED() << "Unexpected Mojo result: " << result;
183 void BluetoothSerialPortImpl::ResetPendingWriteBuffer() {
184 pending_write_buffer_ = base::span<char>();
187 void BluetoothSerialPortImpl::ResetReceiveBuffer() {
188 receive_buffer_size_ = 0;
189 receive_buffer_next_byte_pos_ = 0;
190 receive_buffer_.reset();
193 void BluetoothSerialPortImpl::ReadMore() {
194 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
195 DCHECK(out_stream_.is_valid());
196 DCHECK(!read_pending_);
198 void* buffer = nullptr;
199 uint32_t buffer_num_bytes = 0;
200 // The |buffer| is owned by |out_stream_|.
201 MojoResult result = out_stream_->BeginWriteData(&buffer, &buffer_num_bytes,
202 MOJO_WRITE_DATA_FLAG_NONE);
203 if (result == MOJO_RESULT_SHOULD_WAIT) {
204 out_stream_watcher_.ArmOrNotify();
207 if (result != MOJO_RESULT_OK) {
208 out_stream_watcher_.Cancel();
213 if (!bluetooth_socket_) {
214 mojo::ReportBadMessage("No Bluetooth socket.");
218 if (receive_buffer_) {
219 const size_t num_remaining_bytes =
220 receive_buffer_size_ - receive_buffer_next_byte_pos_;
221 const size_t bytes_to_copy =
222 std::min(num_remaining_bytes, size_t{buffer_num_bytes});
224 receive_buffer_->data() + receive_buffer_next_byte_pos_,
225 receive_buffer_->data() + receive_buffer_next_byte_pos_ + bytes_to_copy,
226 reinterpret_cast<char*>(buffer));
227 out_stream_->EndWriteData(bytes_to_copy);
228 if (bytes_to_copy == num_remaining_bytes) { // If copied the last byte.
229 ResetReceiveBuffer();
231 receive_buffer_next_byte_pos_ += buffer_num_bytes;
233 out_stream_watcher_.ArmOrNotify();
236 read_pending_ = true;
237 pending_write_buffer_ =
238 base::make_span(reinterpret_cast<char*>(buffer), buffer_num_bytes);
239 bluetooth_socket_->Receive(
241 base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketReceive,
242 weak_ptr_factory_.GetWeakPtr()),
243 base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketReceiveError,
244 weak_ptr_factory_.GetWeakPtr()));
247 void BluetoothSerialPortImpl::OnBluetoothSocketReceive(
248 int num_bytes_received,
249 scoped_refptr<net::IOBuffer> receive_buffer) {
250 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
251 DCHECK_GT(num_bytes_received, 0);
252 DCHECK(receive_buffer->data());
254 const bool receive_completed_after_flush = pending_write_buffer_.empty();
255 read_pending_ = false;
257 if (receive_completed_after_flush) {
259 // The prior pipe was flushed while a read was in-flight. Now that
260 // StartReading() has been called, put this received data in the receive
261 // buffer which will prepend to the next read output and call ReadMore()
262 // to start consuming receive_buffer_.
263 receive_buffer_size_ = num_bytes_received;
264 receive_buffer_next_byte_pos_ = 0;
265 receive_buffer_ = std::move(receive_buffer);
271 // Note: Some platform implementations of BluetoothSocket::Receive ignore the
272 // buffer size parameter. This means that |num_bytes_received| could be
273 // larger than |pending_write_buffer_|. Check to avoid buffer overflow.
275 size_t bytes_to_copy = std::min(pending_write_buffer_.size(),
276 static_cast<size_t>(num_bytes_received));
277 std::copy(receive_buffer->data(), receive_buffer->data() + bytes_to_copy,
278 pending_write_buffer_.data());
279 out_stream_->EndWriteData(bytes_to_copy);
280 if (pending_write_buffer_.size() < static_cast<size_t>(num_bytes_received)) {
281 receive_buffer_size_ = num_bytes_received;
282 receive_buffer_next_byte_pos_ = pending_write_buffer_.size();
283 receive_buffer_ = std::move(receive_buffer);
285 ResetPendingWriteBuffer();
290 void BluetoothSerialPortImpl::OnBluetoothSocketReceiveError(
291 BluetoothSocket::ErrorReason error_reason,
292 const std::string& error_message) {
293 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
295 read_pending_ = false;
296 ResetPendingWriteBuffer();
300 DCHECK(error_reason != BluetoothSocket::ErrorReason::kIOPending);
301 switch (error_reason) {
302 case BluetoothSocket::ErrorReason::kDisconnected:
303 client_->OnReadError(mojom::SerialReceiveError::DISCONNECTED);
305 case BluetoothSocket::ErrorReason::kIOPending:
308 case BluetoothSocket::ErrorReason::kSystemError:
309 client_->OnReadError(mojom::SerialReceiveError::SYSTEM_ERROR);
314 out_stream_->EndWriteData(0);
315 out_stream_watcher_.Cancel();
317 ResetReceiveBuffer();
321 void BluetoothSerialPortImpl::WriteToSocket(
323 const mojo::HandleSignalsState& state) {
324 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
327 DCHECK(!write_pending_);
330 case MOJO_RESULT_SHOULD_WAIT:
331 // If there is no space to write, wait for more space.
332 in_stream_watcher_.ArmOrNotify();
334 case MOJO_RESULT_FAILED_PRECONDITION:
335 case MOJO_RESULT_CANCELLED:
336 // The |in_stream_| has been closed.
337 in_stream_watcher_.Cancel();
341 std::move(drain_callback_).Run();
344 NOTREACHED() << "Unexpected Mojo result: " << result;
348 void BluetoothSerialPortImpl::WriteMore() {
349 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
350 DCHECK(in_stream_.is_valid());
351 DCHECK(!write_pending_);
353 const void* buffer = nullptr;
354 uint32_t buffer_size = 0;
355 // |buffer| is owned by |in_stream_|.
356 MojoResult result = in_stream_->BeginReadData(&buffer, &buffer_size,
357 MOJO_WRITE_DATA_FLAG_NONE);
358 if (result == MOJO_RESULT_SHOULD_WAIT) {
359 in_stream_watcher_.ArmOrNotify();
362 if (result == MOJO_RESULT_FAILED_PRECONDITION) {
363 in_stream_watcher_.Cancel();
366 std::move(drain_callback_).Run();
369 if (result != MOJO_RESULT_OK) {
370 in_stream_watcher_.Cancel();
375 if (!bluetooth_socket_) {
376 mojo::ReportBadMessage("No Bluetooth socket.");
380 write_pending_ = true;
381 // Copying the buffer because we might want to close in_stream_, thus
382 // invalidating |buffer|, which is passed to Send().
383 auto io_buffer = base::MakeRefCounted<net::IOBuffer>(buffer_size);
384 std::copy(static_cast<const char*>(buffer),
385 static_cast<const char*>(buffer) + buffer_size, io_buffer->data());
387 // The call to EndReadData() will be delayed until after Send() completes.
388 bluetooth_socket_->Send(
389 io_buffer, buffer_size,
390 base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketSend,
391 weak_ptr_factory_.GetWeakPtr()),
392 base::BindOnce(&BluetoothSerialPortImpl::OnBluetoothSocketSendError,
393 weak_ptr_factory_.GetWeakPtr()));
396 void BluetoothSerialPortImpl::OnBluetoothSocketSend(int num_bytes_sent) {
397 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
398 DCHECK_GE(num_bytes_sent, 0);
400 write_pending_ = false;
402 if (!flush_next_write_) {
404 in_stream_->EndReadData(static_cast<uint32_t>(num_bytes_sent));
406 flush_next_write_ = false;
408 // If |in_stream_| is valid then StartWriting() has been called.
414 void BluetoothSerialPortImpl::OnBluetoothSocketSendError(
415 const std::string& error_message) {
416 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
418 write_pending_ = false;
419 flush_next_write_ = false;
423 client_->OnSendError(mojom::SerialSendError::SYSTEM_ERROR);
425 in_stream_->EndReadData(0);
426 in_stream_watcher_.Cancel();
431 void BluetoothSerialPortImpl::OnSocketDisconnected(CloseCallback callback) {
432 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
433 std::move(callback).Run();
434 bluetooth_socket_.reset(); // Avoid calling Disconnect() twice.
438 void BluetoothSerialPortImpl::Flush(mojom::SerialPortFlushMode mode,
439 FlushCallback callback) {
440 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
442 case mojom::SerialPortFlushMode::kReceiveAndTransmit:
443 // Do nothing. This case exists to support the chrome.serial.flush()
444 // method and is not used by the Web Serial API.
446 case mojom::SerialPortFlushMode::kReceive:
448 out_stream_->EndWriteData(0);
449 out_stream_watcher_.Cancel();
451 ResetReceiveBuffer();
452 ResetPendingWriteBuffer();
454 case mojom::SerialPortFlushMode::kTransmit:
455 if (write_pending_) {
456 flush_next_write_ = true;
457 in_stream_->EndReadData(0);
459 in_stream_watcher_.Cancel();
464 std::move(callback).Run();
467 void BluetoothSerialPortImpl::Drain(DrainCallback callback) {
468 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
470 std::move(callback).Run();
474 drain_callback_ = std::move(callback);
477 void BluetoothSerialPortImpl::GetControlSignals(
478 GetControlSignalsCallback callback) {
479 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
480 auto signals = mojom::SerialPortControlSignals::New();
481 std::move(callback).Run(std::move(signals));
484 void BluetoothSerialPortImpl::SetControlSignals(
485 mojom::SerialHostControlSignalsPtr signals,
486 SetControlSignalsCallback callback) {
487 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
488 std::move(callback).Run(true);
491 void BluetoothSerialPortImpl::ConfigurePort(
492 mojom::SerialConnectionOptionsPtr options,
493 ConfigurePortCallback callback) {
494 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
495 options_ = std::move(options);
496 std::move(callback).Run(true);
499 void BluetoothSerialPortImpl::GetPortInfo(GetPortInfoCallback callback) {
500 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
501 auto info = mojom::SerialConnectionInfo::New(
502 /*bitrate=*/options_->bitrate, /*data_bits=*/options_->data_bits,
503 /*parity_bit=*/options_->parity_bit, /*stop_bits=*/options_->stop_bits,
504 /*cts_flow_control=*/options_->cts_flow_control);
505 std::move(callback).Run(std::move(info));
508 void BluetoothSerialPortImpl::Close(bool flush, CloseCallback callback) {
509 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
510 // It is safe to ignore |flush| because we get the semantics of a flush simply
511 // by disconnecting the socket. There are no hardware buffers to clear.
512 bluetooth_socket_->Disconnect(
513 base::BindOnce(&BluetoothSerialPortImpl::OnSocketDisconnected,
514 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
517 } // namespace device