1 // Copyright 2018 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 "chromecast/device/bluetooth/le/remote_device_impl.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "chromecast/base/bind_to_task_runner.h"
11 #include "chromecast/device/bluetooth/bluetooth_util.h"
12 #include "chromecast/device/bluetooth/le/gatt_client_manager_impl.h"
13 #include "chromecast/device/bluetooth/le/remote_characteristic_impl.h"
14 #include "chromecast/device/bluetooth/le/remote_descriptor_impl.h"
15 #include "chromecast/device/bluetooth/le/remote_service_impl.h"
16
17 namespace chromecast {
18 namespace bluetooth {
19
20 #define RUN_ON_IO_THREAD(method, ...) \
21 io_task_runner_->PostTask( \
22 FROM_HERE, \
23 base::BindOnce(&RemoteDeviceImpl::method, this, ##__VA_ARGS__));
24
25 #define MAKE_SURE_IO_THREAD(method, ...) \
26 DCHECK(io_task_runner_); \
27 if (!io_task_runner_->BelongsToCurrentThread()) { \
28 RUN_ON_IO_THREAD(method, ##__VA_ARGS__) \
29 return; \
30 }
31
32 #define EXEC_CB_AND_RET(cb, ret, ...) \
33 do { \
34 if (cb) { \
35 std::move(cb).Run(ret, ##__VA_ARGS__); \
36 } \
37 return; \
38 } while (0)
39
40 #define CHECK_CONNECTED(cb) \
41 do { \
42 if (!connected_) { \
43 LOG(ERROR) << __func__ << "failed: Not connected"; \
44 EXEC_CB_AND_RET(cb, false); \
45 } \
46 } while (0)
47
48 #define LOG_EXEC_CB_AND_RET(cb, ret) \
49 do { \
50 if (!ret) { \
51 LOG(ERROR) << __func__ << "failed"; \
52 } \
53 EXEC_CB_AND_RET(cb, ret); \
54 } while (0)
55
56 // static
57 constexpr base::TimeDelta RemoteDeviceImpl::kCommandTimeout;
58
RemoteDeviceImpl(const bluetooth_v2_shlib::Addr & addr,base::WeakPtr<GattClientManagerImpl> gatt_client_manager,scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)59 RemoteDeviceImpl::RemoteDeviceImpl(
60 const bluetooth_v2_shlib::Addr& addr,
61 base::WeakPtr<GattClientManagerImpl> gatt_client_manager,
62 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
63 : gatt_client_manager_(gatt_client_manager),
64 addr_(addr),
65 io_task_runner_(io_task_runner) {
66 DCHECK(gatt_client_manager);
67 DCHECK(io_task_runner_->BelongsToCurrentThread());
68 }
69
70 RemoteDeviceImpl::~RemoteDeviceImpl() = default;
71
Connect(ConnectCallback cb)72 void RemoteDeviceImpl::Connect(ConnectCallback cb) {
73 MAKE_SURE_IO_THREAD(Connect, BindToCurrentSequence(std::move(cb)));
74 LOG(INFO) << "Connect(" << util::AddrLastByteString(addr_) << ")";
75
76 if (!gatt_client_manager_) {
77 LOG(ERROR) << __func__ << " failed: Destroyed";
78 EXEC_CB_AND_RET(cb, ConnectStatus::kGattClientManagerDestroyed);
79 }
80
81 if (connect_cb_) {
82 LOG(ERROR) << __func__ << " failed: Connection pending";
83 EXEC_CB_AND_RET(cb, ConnectStatus::kConnectPending);
84 }
85
86 gatt_client_manager_->NotifyConnect(addr_);
87 connect_cb_ = std::move(cb);
88 gatt_client_manager_->EnqueueConnectRequest(addr_, true);
89 }
90
Disconnect(StatusCallback cb)91 void RemoteDeviceImpl::Disconnect(StatusCallback cb) {
92 MAKE_SURE_IO_THREAD(Disconnect, BindToCurrentSequence(std::move(cb)));
93 LOG(INFO) << "Disconnect(" << util::AddrLastByteString(addr_) << ")";
94
95 if (!gatt_client_manager_) {
96 LOG(ERROR) << __func__ << " failed: Destroyed";
97 EXEC_CB_AND_RET(cb, false);
98 }
99
100 disconnect_pending_ = true;
101 disconnect_cb_ = std::move(cb);
102 gatt_client_manager_->EnqueueConnectRequest(addr_, false);
103 }
104
CreateBond(StatusCallback cb)105 void RemoteDeviceImpl::CreateBond(StatusCallback cb) {
106 MAKE_SURE_IO_THREAD(CreateBond, BindToCurrentSequence(std::move(cb)));
107 LOG(INFO) << "CreateBond(" << util::AddrLastByteString(addr_) << ")";
108 if (!gatt_client_manager_) {
109 LOG(ERROR) << __func__ << " failed: Destroyed";
110 EXEC_CB_AND_RET(cb, false);
111 }
112
113 if (!connected_) {
114 LOG(ERROR) << "Not connected";
115 EXEC_CB_AND_RET(cb, false);
116 }
117
118 if (create_bond_pending_ || remove_bond_pending_) {
119 // TODO(tiansong): b/120489954 Implement queuing and timeout logic.
120 LOG(ERROR) << __func__ << " failed: waiting for pending bond command";
121 EXEC_CB_AND_RET(cb, false);
122 }
123
124 if (bonded_) {
125 LOG(ERROR) << "Already bonded";
126 EXEC_CB_AND_RET(cb, false);
127 }
128
129 if (!gatt_client_manager_->gatt_client()->CreateBond(addr_)) {
130 LOG(ERROR) << __func__ << " failed";
131 EXEC_CB_AND_RET(cb, false);
132 }
133
134 create_bond_pending_ = true;
135 create_bond_cb_ = std::move(cb);
136 }
137
RemoveBond(StatusCallback cb)138 void RemoteDeviceImpl::RemoveBond(StatusCallback cb) {
139 MAKE_SURE_IO_THREAD(RemoveBond, BindToCurrentSequence(std::move(cb)));
140 LOG(INFO) << "RemoveBond(" << util::AddrLastByteString(addr_) << ")";
141 if (!gatt_client_manager_) {
142 LOG(ERROR) << __func__ << " failed: Destroyed";
143 EXEC_CB_AND_RET(cb, false);
144 }
145
146 if (create_bond_pending_ || remove_bond_pending_) {
147 // TODO(tiansong): b/120489954 Implement queuing and timeout logic.
148 LOG(ERROR) << __func__ << " failed: waiting for pending bond command";
149 EXEC_CB_AND_RET(cb, false);
150 }
151
152 if (!bonded_) {
153 LOG(WARNING) << "Not bonded";
154 }
155
156 if (!gatt_client_manager_->gatt_client()->RemoveBond(addr_)) {
157 LOG(ERROR) << __func__ << " failed";
158 EXEC_CB_AND_RET(cb, false);
159 }
160
161 remove_bond_pending_ = true;
162 remove_bond_cb_ = std::move(cb);
163 }
164
ReadRemoteRssi(RssiCallback cb)165 void RemoteDeviceImpl::ReadRemoteRssi(RssiCallback cb) {
166 MAKE_SURE_IO_THREAD(ReadRemoteRssi, BindToCurrentSequence(std::move(cb)));
167 if (!gatt_client_manager_) {
168 LOG(ERROR) << __func__ << " failed: Destroyed";
169 EXEC_CB_AND_RET(cb, false, 0);
170 }
171
172 if (rssi_pending_) {
173 LOG(ERROR) << "Read remote RSSI already pending";
174 EXEC_CB_AND_RET(cb, false, 0);
175 }
176
177 rssi_pending_ = true;
178 rssi_cb_ = std::move(cb);
179 gatt_client_manager_->EnqueueReadRemoteRssiRequest(addr_);
180 }
181
RequestMtu(int mtu,StatusCallback cb)182 void RemoteDeviceImpl::RequestMtu(int mtu, StatusCallback cb) {
183 MAKE_SURE_IO_THREAD(RequestMtu, mtu, BindToCurrentSequence(std::move(cb)));
184 LOG(INFO) << "RequestMtu(" << util::AddrLastByteString(addr_) << ", " << mtu
185 << ")";
186 DCHECK(cb);
187 if (!gatt_client_manager_) {
188 LOG(ERROR) << __func__ << " failed: Destroyed";
189 EXEC_CB_AND_RET(cb, false);
190 }
191 CHECK_CONNECTED(cb);
192 mtu_callbacks_.push(std::move(cb));
193 EnqueueOperation(
194 __func__, base::BindOnce(&RemoteDeviceImpl::RequestMtuImpl, this, mtu));
195 }
196
ConnectionParameterUpdate(int min_interval,int max_interval,int latency,int timeout,StatusCallback cb)197 void RemoteDeviceImpl::ConnectionParameterUpdate(int min_interval,
198 int max_interval,
199 int latency,
200 int timeout,
201 StatusCallback cb) {
202 MAKE_SURE_IO_THREAD(ConnectionParameterUpdate, min_interval, max_interval,
203 latency, timeout, BindToCurrentSequence(std::move(cb)));
204 LOG(INFO) << "ConnectionParameterUpdate(" << util::AddrLastByteString(addr_)
205 << ", " << min_interval << ", " << max_interval << ", " << latency
206 << ", " << timeout << ")";
207 if (!gatt_client_manager_) {
208 LOG(ERROR) << __func__ << " failed: Destroyed";
209 EXEC_CB_AND_RET(cb, false);
210 }
211 CHECK_CONNECTED(cb);
212 bool ret = gatt_client_manager_->gatt_client()->ConnectionParameterUpdate(
213 addr_, min_interval, max_interval, latency, timeout);
214 LOG_EXEC_CB_AND_RET(cb, ret);
215 }
216
IsConnected()217 bool RemoteDeviceImpl::IsConnected() {
218 return connected_ && !disconnect_pending_;
219 }
220
IsBonded()221 bool RemoteDeviceImpl::IsBonded() {
222 return bonded_;
223 }
224
GetMtu()225 int RemoteDeviceImpl::GetMtu() {
226 return mtu_;
227 }
228
GetServices(base::OnceCallback<void (std::vector<scoped_refptr<RemoteService>>)> cb)229 void RemoteDeviceImpl::GetServices(
230 base::OnceCallback<void(std::vector<scoped_refptr<RemoteService>>)> cb) {
231 MAKE_SURE_IO_THREAD(GetServices, BindToCurrentSequence(std::move(cb)));
232 auto ret = GetServicesSync();
233 EXEC_CB_AND_RET(cb, std::move(ret));
234 }
235
GetServicesSync()236 std::vector<scoped_refptr<RemoteService>> RemoteDeviceImpl::GetServicesSync() {
237 DCHECK(io_task_runner_->BelongsToCurrentThread());
238 std::vector<scoped_refptr<RemoteService>> services;
239 services.reserve(uuid_to_service_.size());
240 for (const auto& pair : uuid_to_service_)
241 services.push_back(pair.second);
242
243 return services;
244 }
245
GetServiceByUuid(const bluetooth_v2_shlib::Uuid & uuid,base::OnceCallback<void (scoped_refptr<RemoteService>)> cb)246 void RemoteDeviceImpl::GetServiceByUuid(
247 const bluetooth_v2_shlib::Uuid& uuid,
248 base::OnceCallback<void(scoped_refptr<RemoteService>)> cb) {
249 MAKE_SURE_IO_THREAD(GetServiceByUuid, uuid,
250 BindToCurrentSequence(std::move(cb)));
251 auto ret = GetServiceByUuidSync(uuid);
252 EXEC_CB_AND_RET(cb, std::move(ret));
253 }
254
addr() const255 const bluetooth_v2_shlib::Addr& RemoteDeviceImpl::addr() const {
256 return addr_;
257 }
258
ReadCharacteristic(scoped_refptr<RemoteCharacteristicImpl> characteristic,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,RemoteCharacteristic::ReadCallback cb)259 void RemoteDeviceImpl::ReadCharacteristic(
260 scoped_refptr<RemoteCharacteristicImpl> characteristic,
261 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
262 RemoteCharacteristic::ReadCallback cb) {
263 DCHECK(io_task_runner_->BelongsToCurrentThread());
264 handle_to_characteristic_read_cbs_[characteristic->handle()].push(
265 std::move(cb));
266
267 EnqueueOperation(
268 __func__, base::BindOnce(&RemoteDeviceImpl::ReadCharacteristicImpl, this,
269 std::move(characteristic), auth_req));
270 }
271
WriteCharacteristic(scoped_refptr<RemoteCharacteristicImpl> characteristic,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,bluetooth_v2_shlib::Gatt::WriteType write_type,std::vector<uint8_t> value,RemoteCharacteristic::StatusCallback cb)272 void RemoteDeviceImpl::WriteCharacteristic(
273 scoped_refptr<RemoteCharacteristicImpl> characteristic,
274 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
275 bluetooth_v2_shlib::Gatt::WriteType write_type,
276 std::vector<uint8_t> value,
277 RemoteCharacteristic::StatusCallback cb) {
278 DCHECK(io_task_runner_->BelongsToCurrentThread());
279 handle_to_characteristic_write_cbs_[characteristic->handle()].push(
280 std::move(cb));
281 EnqueueOperation(
282 __func__, base::BindOnce(&RemoteDeviceImpl::WriteCharacteristicImpl, this,
283 std::move(characteristic), auth_req, write_type,
284 std::move(value)));
285 }
286
ReadDescriptor(scoped_refptr<RemoteDescriptorImpl> descriptor,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,RemoteDescriptor::ReadCallback cb)287 void RemoteDeviceImpl::ReadDescriptor(
288 scoped_refptr<RemoteDescriptorImpl> descriptor,
289 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
290 RemoteDescriptor::ReadCallback cb) {
291 DCHECK(io_task_runner_->BelongsToCurrentThread());
292 handle_to_descriptor_read_cbs_[descriptor->handle()].push(std::move(cb));
293
294 EnqueueOperation(__func__,
295 base::BindOnce(&RemoteDeviceImpl::ReadDescriptorImpl, this,
296 std::move(descriptor), auth_req));
297 }
298
WriteDescriptor(scoped_refptr<RemoteDescriptorImpl> descriptor,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,std::vector<uint8_t> value,RemoteDescriptor::StatusCallback cb)299 void RemoteDeviceImpl::WriteDescriptor(
300 scoped_refptr<RemoteDescriptorImpl> descriptor,
301 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
302 std::vector<uint8_t> value,
303 RemoteDescriptor::StatusCallback cb) {
304 DCHECK(io_task_runner_->BelongsToCurrentThread());
305 handle_to_descriptor_write_cbs_[descriptor->handle()].push(std::move(cb));
306 EnqueueOperation(
307 __func__,
308 base::BindOnce(&RemoteDeviceImpl::WriteDescriptorImpl, this,
309 std::move(descriptor), auth_req, std::move(value)));
310 }
311
GetServiceByUuidSync(const bluetooth_v2_shlib::Uuid & uuid)312 scoped_refptr<RemoteService> RemoteDeviceImpl::GetServiceByUuidSync(
313 const bluetooth_v2_shlib::Uuid& uuid) {
314 DCHECK(io_task_runner_->BelongsToCurrentThread());
315 auto it = uuid_to_service_.find(uuid);
316 if (it == uuid_to_service_.end())
317 return nullptr;
318
319 return it->second;
320 }
321
SetConnected(bool connected)322 void RemoteDeviceImpl::SetConnected(bool connected) {
323 DCHECK(io_task_runner_->BelongsToCurrentThread());
324 // We only set connected = true and call the callback after services are
325 // discovered.
326 if (!connected) {
327 connected_ = false;
328 ConnectComplete(false);
329 }
330
331 if (disconnect_pending_) {
332 disconnect_pending_ = false;
333 if (disconnect_cb_) {
334 std::move(disconnect_cb_).Run(!connected);
335 }
336 }
337
338 if (!connected && rssi_pending_) {
339 LOG(ERROR) << "Read remote RSSI failed: disconnected";
340 if (rssi_cb_) {
341 std::move(rssi_cb_).Run(false, 0);
342 }
343 rssi_pending_ = false;
344 }
345
346 if (connected) {
347 if (!gatt_client_manager_) {
348 LOG(ERROR) << "Couldn't discover services: Destroyed";
349 return;
350 }
351
352 if (!gatt_client_manager_->gatt_client()->GetServices(addr_)) {
353 LOG(ERROR) << "Couldn't discover services, disconnecting";
354 Disconnect({});
355 ConnectComplete(false);
356 }
357 } else {
358 // Reset state after disconnection
359 mtu_ = kDefaultMtu;
360 ClearServices();
361 }
362 }
363
SetBonded(bool bonded)364 void RemoteDeviceImpl::SetBonded(bool bonded) {
365 DCHECK(io_task_runner_->BelongsToCurrentThread());
366
367 bonded_ = bonded;
368
369 if (create_bond_pending_) {
370 create_bond_pending_ = false;
371 if (create_bond_cb_) {
372 std::move(create_bond_cb_).Run(bonded);
373 }
374 }
375
376 if (remove_bond_pending_) {
377 remove_bond_pending_ = false;
378 if (remove_bond_cb_) {
379 std::move(remove_bond_cb_).Run(!bonded);
380 }
381 }
382 }
383
SetServicesDiscovered(bool discovered)384 void RemoteDeviceImpl::SetServicesDiscovered(bool discovered) {
385 DCHECK(io_task_runner_->BelongsToCurrentThread());
386 services_discovered_ = discovered;
387 if (!discovered) {
388 return;
389 }
390 connected_ = true;
391 ConnectComplete(true);
392 }
393
GetServicesDiscovered()394 bool RemoteDeviceImpl::GetServicesDiscovered() {
395 DCHECK(io_task_runner_->BelongsToCurrentThread());
396 return services_discovered_;
397 }
398
SetMtu(int mtu)399 void RemoteDeviceImpl::SetMtu(int mtu) {
400 DCHECK(io_task_runner_->BelongsToCurrentThread());
401 mtu_ = mtu;
402 if (!mtu_callbacks_.empty()) {
403 std::move(mtu_callbacks_.front()).Run(true);
404 mtu_callbacks_.pop();
405 NotifyQueueOperationComplete();
406 }
407 }
408
CharacteristicFromHandle(uint16_t handle)409 scoped_refptr<RemoteCharacteristic> RemoteDeviceImpl::CharacteristicFromHandle(
410 uint16_t handle) {
411 DCHECK(io_task_runner_->BelongsToCurrentThread());
412 auto it = handle_to_characteristic_.find(handle);
413 if (it == handle_to_characteristic_.end())
414 return nullptr;
415
416 return it->second;
417 }
418
OnCharacteristicRead(bool status,uint16_t handle,const std::vector<uint8_t> & value)419 void RemoteDeviceImpl::OnCharacteristicRead(bool status,
420 uint16_t handle,
421 const std::vector<uint8_t>& value) {
422 DCHECK(io_task_runner_->BelongsToCurrentThread());
423 auto it = handle_to_characteristic_read_cbs_.find(handle);
424 if (it == handle_to_characteristic_read_cbs_.end() || it->second.empty()) {
425 LOG(ERROR) << "No such characteristic read";
426 } else {
427 std::move(it->second.front()).Run(status, value);
428 it->second.pop();
429 }
430 NotifyQueueOperationComplete();
431 }
432
OnCharacteristicWrite(bool status,uint16_t handle)433 void RemoteDeviceImpl::OnCharacteristicWrite(bool status, uint16_t handle) {
434 DCHECK(io_task_runner_->BelongsToCurrentThread());
435 auto it = handle_to_characteristic_write_cbs_.find(handle);
436 if (it == handle_to_characteristic_write_cbs_.end() || it->second.empty()) {
437 LOG(ERROR) << "No such characteristic write";
438 } else {
439 std::move(it->second.front()).Run(status);
440 it->second.pop();
441 }
442 NotifyQueueOperationComplete();
443 }
444
OnDescriptorRead(bool status,uint16_t handle,const std::vector<uint8_t> & value)445 void RemoteDeviceImpl::OnDescriptorRead(bool status,
446 uint16_t handle,
447 const std::vector<uint8_t>& value) {
448 DCHECK(io_task_runner_->BelongsToCurrentThread());
449 auto it = handle_to_descriptor_read_cbs_.find(handle);
450 if (it == handle_to_descriptor_read_cbs_.end() || it->second.empty()) {
451 LOG(ERROR) << "No such descriptor read";
452 } else {
453 std::move(it->second.front()).Run(status, value);
454 it->second.pop();
455 }
456 NotifyQueueOperationComplete();
457 }
458
OnDescriptorWrite(bool status,uint16_t handle)459 void RemoteDeviceImpl::OnDescriptorWrite(bool status, uint16_t handle) {
460 DCHECK(io_task_runner_->BelongsToCurrentThread());
461 auto it = handle_to_descriptor_write_cbs_.find(handle);
462 if (it == handle_to_descriptor_write_cbs_.end() || it->second.empty()) {
463 LOG(ERROR) << "No such descriptor write";
464 } else {
465 std::move(it->second.front()).Run(status);
466 it->second.pop();
467 }
468 NotifyQueueOperationComplete();
469 }
470
OnGetServices(const std::vector<bluetooth_v2_shlib::Gatt::Service> & services)471 void RemoteDeviceImpl::OnGetServices(
472 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
473 DCHECK(io_task_runner_->BelongsToCurrentThread());
474 ClearServices();
475 OnServicesAdded(services);
476 }
477
OnServicesRemoved(uint16_t start_handle,uint16_t end_handle)478 void RemoteDeviceImpl::OnServicesRemoved(uint16_t start_handle,
479 uint16_t end_handle) {
480 DCHECK(io_task_runner_->BelongsToCurrentThread());
481 for (auto it = uuid_to_service_.begin(); it != uuid_to_service_.end();) {
482 if (it->second->handle() >= start_handle &&
483 it->second->handle() <= end_handle) {
484 for (auto& characteristic : it->second->GetCharacteristics()) {
485 handle_to_characteristic_.erase(characteristic->handle());
486 }
487 it = uuid_to_service_.erase(it);
488 } else {
489 ++it;
490 }
491 }
492 }
493
OnServicesAdded(const std::vector<bluetooth_v2_shlib::Gatt::Service> & services)494 void RemoteDeviceImpl::OnServicesAdded(
495 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
496 DCHECK(io_task_runner_->BelongsToCurrentThread());
497 for (const auto& service : services) {
498 uuid_to_service_[service.uuid] = new RemoteServiceImpl(
499 this, gatt_client_manager_, service, io_task_runner_);
500 }
501
502 for (const auto& pair : uuid_to_service_) {
503 for (auto& characteristic : pair.second->GetCharacteristics()) {
504 handle_to_characteristic_.emplace(
505 characteristic->handle(),
506 static_cast<RemoteCharacteristicImpl*>(characteristic.get()));
507 }
508 }
509 }
510
OnReadRemoteRssiComplete(bool status,int rssi)511 void RemoteDeviceImpl::OnReadRemoteRssiComplete(bool status, int rssi) {
512 DCHECK(io_task_runner_->BelongsToCurrentThread());
513 rssi_pending_ = false;
514 if (rssi_cb_) {
515 std::move(rssi_cb_).Run(status, rssi);
516 }
517 }
518
ConnectComplete(bool success)519 void RemoteDeviceImpl::ConnectComplete(bool success) {
520 DCHECK(io_task_runner_->BelongsToCurrentThread());
521 if (connect_cb_) {
522 std::move(connect_cb_)
523 .Run(success ? ConnectStatus::kSuccess : ConnectStatus::kFailure);
524 }
525 }
526
EnqueueOperation(const std::string & name,base::OnceClosure op)527 void RemoteDeviceImpl::EnqueueOperation(const std::string& name,
528 base::OnceClosure op) {
529 DCHECK(io_task_runner_->BelongsToCurrentThread());
530 command_queue_.emplace_back(name, std::move(op));
531
532 // Run the operation if this is the only operation in the queue. Otherwise, it
533 // will be executed when the current operation completes.
534 if (command_queue_.size() == 1) {
535 RunNextOperation();
536 }
537 }
538
NotifyQueueOperationComplete()539 void RemoteDeviceImpl::NotifyQueueOperationComplete() {
540 DCHECK(io_task_runner_->BelongsToCurrentThread());
541 if (command_queue_.empty()) {
542 LOG(ERROR) << "Command queue is empty, device might be disconnected";
543 return;
544 }
545 command_queue_.pop_front();
546 command_timeout_timer_.Stop();
547
548 // Run the next operation if there is one in the queue.
549 if (!command_queue_.empty()) {
550 RunNextOperation();
551 }
552 }
553
RunNextOperation()554 void RemoteDeviceImpl::RunNextOperation() {
555 DCHECK(io_task_runner_->BelongsToCurrentThread());
556 if (command_queue_.empty()) {
557 LOG(ERROR) << "Command queue is empty, device might be disconnected";
558 return;
559 }
560 auto& front = command_queue_.front();
561 command_timeout_timer_.Start(
562 FROM_HERE, kCommandTimeout,
563 base::BindRepeating(&RemoteDeviceImpl::OnCommandTimeout, this,
564 front.first));
565 std::move(front.second).Run();
566 }
567
RequestMtuImpl(int mtu)568 void RemoteDeviceImpl::RequestMtuImpl(int mtu) {
569 DCHECK(io_task_runner_->BelongsToCurrentThread());
570 if (gatt_client_manager_->gatt_client()->RequestMtu(addr_, mtu)) {
571 return;
572 }
573
574 LOG(ERROR) << __func__ << " failed";
575 DCHECK(!mtu_callbacks_.empty());
576 std::move(mtu_callbacks_.front()).Run(false);
577 mtu_callbacks_.pop();
578 NotifyQueueOperationComplete();
579 }
580
ReadCharacteristicImpl(scoped_refptr<RemoteCharacteristicImpl> characteristic,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req)581 void RemoteDeviceImpl::ReadCharacteristicImpl(
582 scoped_refptr<RemoteCharacteristicImpl> characteristic,
583 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req) {
584 DCHECK(io_task_runner_->BelongsToCurrentThread());
585 if (gatt_client_manager_->gatt_client()->ReadCharacteristic(
586 addr(), characteristic->characteristic(), auth_req)) {
587 return;
588 }
589
590 LOG(ERROR) << __func__ << " failed";
591 auto it = handle_to_characteristic_read_cbs_.find(characteristic->handle());
592 DCHECK(it != handle_to_characteristic_read_cbs_.end());
593 DCHECK(!it->second.empty());
594 std::move(it->second.front()).Run(false, {});
595 it->second.pop();
596 NotifyQueueOperationComplete();
597 }
598
WriteCharacteristicImpl(scoped_refptr<RemoteCharacteristicImpl> characteristic,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,bluetooth_v2_shlib::Gatt::WriteType write_type,std::vector<uint8_t> value)599 void RemoteDeviceImpl::WriteCharacteristicImpl(
600 scoped_refptr<RemoteCharacteristicImpl> characteristic,
601 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
602 bluetooth_v2_shlib::Gatt::WriteType write_type,
603 std::vector<uint8_t> value) {
604 DCHECK(io_task_runner_->BelongsToCurrentThread());
605 if (gatt_client_manager_->gatt_client()->WriteCharacteristic(
606 addr(), characteristic->characteristic(), auth_req, write_type,
607 value)) {
608 return;
609 }
610
611 LOG(ERROR) << __func__ << " failed";
612 auto it = handle_to_characteristic_write_cbs_.find(characteristic->handle());
613 DCHECK(it != handle_to_characteristic_write_cbs_.end());
614 DCHECK(!it->second.empty());
615 std::move(it->second.front()).Run(false);
616 it->second.pop();
617 NotifyQueueOperationComplete();
618 }
619
ReadDescriptorImpl(scoped_refptr<RemoteDescriptorImpl> descriptor,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req)620 void RemoteDeviceImpl::ReadDescriptorImpl(
621 scoped_refptr<RemoteDescriptorImpl> descriptor,
622 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req) {
623 DCHECK(io_task_runner_->BelongsToCurrentThread());
624 if (gatt_client_manager_->gatt_client()->ReadDescriptor(
625 addr(), descriptor->descriptor(), auth_req)) {
626 return;
627 }
628
629 LOG(ERROR) << __func__ << " failed";
630 auto it = handle_to_descriptor_read_cbs_.find(descriptor->handle());
631 DCHECK(it != handle_to_descriptor_read_cbs_.end());
632 DCHECK(!it->second.empty());
633 std::move(it->second.front()).Run(false, {});
634 it->second.pop();
635 NotifyQueueOperationComplete();
636 }
637
WriteDescriptorImpl(scoped_refptr<RemoteDescriptorImpl> descriptor,bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,std::vector<uint8_t> value)638 void RemoteDeviceImpl::WriteDescriptorImpl(
639 scoped_refptr<RemoteDescriptorImpl> descriptor,
640 bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
641 std::vector<uint8_t> value) {
642 DCHECK(io_task_runner_->BelongsToCurrentThread());
643 if (gatt_client_manager_->gatt_client()->WriteDescriptor(
644 addr(), descriptor->descriptor(), auth_req, value)) {
645 return;
646 }
647
648 LOG(ERROR) << __func__ << " failed";
649 auto it = handle_to_descriptor_write_cbs_.find(descriptor->handle());
650 DCHECK(it != handle_to_descriptor_write_cbs_.end());
651 DCHECK(!it->second.empty());
652 std::move(it->second.front()).Run(false);
653 it->second.pop();
654 NotifyQueueOperationComplete();
655 }
656
ClearServices()657 void RemoteDeviceImpl::ClearServices() {
658 for (auto& item : handle_to_characteristic_) {
659 item.second->Invalidate();
660 }
661
662 uuid_to_service_.clear();
663 handle_to_characteristic_.clear();
664 command_queue_.clear();
665 command_timeout_timer_.Stop();
666
667 while (!mtu_callbacks_.empty()) {
668 LOG(ERROR) << "RequestMtu failed: disconnected";
669 std::move(mtu_callbacks_.front()).Run(false);
670 mtu_callbacks_.pop();
671 }
672
673 for (auto& item : handle_to_characteristic_read_cbs_) {
674 auto& queue = item.second;
675 while (!queue.empty()) {
676 LOG(ERROR) << "Characteristic read failed: disconnected";
677 std::move(queue.front()).Run(false, {});
678 queue.pop();
679 }
680 }
681 handle_to_characteristic_read_cbs_.clear();
682
683 for (auto& item : handle_to_characteristic_write_cbs_) {
684 auto& queue = item.second;
685 while (!queue.empty()) {
686 LOG(ERROR) << "Characteristic write failed: disconnected";
687 std::move(queue.front()).Run(false);
688 queue.pop();
689 }
690 }
691 handle_to_characteristic_write_cbs_.clear();
692
693 for (auto& item : handle_to_descriptor_read_cbs_) {
694 auto& queue = item.second;
695 while (!queue.empty()) {
696 LOG(ERROR) << "Descriptor read failed: disconnected";
697 std::move(queue.front()).Run(false, {});
698 queue.pop();
699 }
700 }
701 handle_to_descriptor_read_cbs_.clear();
702
703 for (auto& item : handle_to_descriptor_write_cbs_) {
704 auto& queue = item.second;
705 while (!queue.empty()) {
706 LOG(ERROR) << "Descriptor write failed: disconnected";
707 std::move(queue.front()).Run(false);
708 queue.pop();
709 }
710 }
711 handle_to_descriptor_write_cbs_.clear();
712 }
713
OnCommandTimeout(const std::string & name)714 void RemoteDeviceImpl::OnCommandTimeout(const std::string& name) {
715 DCHECK(io_task_runner_->BelongsToCurrentThread());
716 LOG(ERROR) << name << "(" << util::AddrLastByteString(addr_) << ")"
717 << " timed out. Disconnecting";
718 Disconnect(base::DoNothing());
719 }
720
721 } // namespace bluetooth
722 } // namespace chromecast
723