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