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 "device/bluetooth/cast/bluetooth_adapter_cast.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/no_destructor.h"
13 #include "base/task/post_task.h"
14 #include "base/threading/sequenced_task_runner_handle.h"
15 #include "chromecast/device/bluetooth/bluetooth_util.h"
16 #include "chromecast/device/bluetooth/le/gatt_client_manager.h"
17 #include "chromecast/device/bluetooth/le/le_scan_manager.h"
18 #include "chromecast/device/bluetooth/le/remote_characteristic.h"
19 #include "chromecast/device/bluetooth/le/remote_device.h"
20 #include "chromecast/device/bluetooth/le/remote_service.h"
21 #include "device/bluetooth/bluetooth_device.h"
22 #include "device/bluetooth/bluetooth_discovery_filter.h"
23 #include "device/bluetooth/bluetooth_discovery_session_outcome.h"
24 #include "device/bluetooth/cast/bluetooth_device_cast.h"
25 #include "device/bluetooth/cast/bluetooth_utils.h"
26 
27 namespace device {
28 namespace {
29 
GetFactory()30 BluetoothAdapterCast::FactoryCb& GetFactory() {
31   static base::NoDestructor<BluetoothAdapterCast::FactoryCb> factory_cb;
32   return *factory_cb;
33 }
34 
35 }  // namespace
36 
DiscoveryParams(std::unique_ptr<device::BluetoothDiscoveryFilter> filter,base::Closure success_callback,DiscoverySessionErrorCallback error_callback)37 BluetoothAdapterCast::DiscoveryParams::DiscoveryParams(
38     std::unique_ptr<device::BluetoothDiscoveryFilter> filter,
39     base::Closure success_callback,
40     DiscoverySessionErrorCallback error_callback)
41     : filter(std::move(filter)),
42       success_callback(success_callback),
43       error_callback(std::move(error_callback)) {}
44 
45 BluetoothAdapterCast::DiscoveryParams::DiscoveryParams(
46     DiscoveryParams&& params) noexcept = default;
47 BluetoothAdapterCast::DiscoveryParams& BluetoothAdapterCast::DiscoveryParams::
48 operator=(DiscoveryParams&& params) = default;
49 BluetoothAdapterCast::DiscoveryParams::~DiscoveryParams() = default;
50 
BluetoothAdapterCast(chromecast::bluetooth::GattClientManager * gatt_client_manager,chromecast::bluetooth::LeScanManager * le_scan_manager)51 BluetoothAdapterCast::BluetoothAdapterCast(
52     chromecast::bluetooth::GattClientManager* gatt_client_manager,
53     chromecast::bluetooth::LeScanManager* le_scan_manager)
54     : gatt_client_manager_(gatt_client_manager),
55       le_scan_manager_(le_scan_manager),
56       weak_factory_(this) {
57   DCHECK(gatt_client_manager_);
58   DCHECK(le_scan_manager_);
59   gatt_client_manager_->AddObserver(this);
60   le_scan_manager_->AddObserver(this);
61 }
62 
~BluetoothAdapterCast()63 BluetoothAdapterCast::~BluetoothAdapterCast() {
64   gatt_client_manager_->RemoveObserver(this);
65   le_scan_manager_->RemoveObserver(this);
66 }
67 
GetAddress() const68 std::string BluetoothAdapterCast::GetAddress() const {
69   // TODO(slan|bcf): Right now, we aren't surfacing the address of the GATT
70   // client to the caller, because there is no apparent need and this
71   // information is potentially PII. Implement this when it's needed.
72   return std::string();
73 }
74 
GetName() const75 std::string BluetoothAdapterCast::GetName() const {
76   return name_;
77 }
78 
SetName(const std::string & name,const base::Closure & callback,const ErrorCallback & error_callback)79 void BluetoothAdapterCast::SetName(const std::string& name,
80                                    const base::Closure& callback,
81                                    const ErrorCallback& error_callback) {
82   name_ = name;
83   callback.Run();
84 }
85 
IsInitialized() const86 bool BluetoothAdapterCast::IsInitialized() const {
87   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
88   return initialized_;
89 }
90 
IsPresent() const91 bool BluetoothAdapterCast::IsPresent() const {
92   // The BluetoothAdapter is always present on Cast devices.
93   return true;
94 }
95 
IsPowered() const96 bool BluetoothAdapterCast::IsPowered() const {
97   return powered_;
98 }
99 
SetPowered(bool powered,const base::Closure & callback,const ErrorCallback & error_callback)100 void BluetoothAdapterCast::SetPowered(bool powered,
101                                       const base::Closure& callback,
102                                       const ErrorCallback& error_callback) {
103   // This class cannot actually change the powered state of the BT stack.
104   // We simulate these changes for the benefit of testing. However, we may
105   // want to actually delegate this call to the bluetooth service, at least
106   // as a signal of the client's intent.
107   // TODO(slan): Determine whether this would be useful.
108   powered_ = powered;
109   NotifyAdapterPoweredChanged(powered_);
110   callback.Run();
111 }
112 
IsDiscoverable() const113 bool BluetoothAdapterCast::IsDiscoverable() const {
114   DVLOG(2) << __func__ << " GATT server mode not supported";
115   return false;
116 }
117 
SetDiscoverable(bool discoverable,const base::Closure & callback,const ErrorCallback & error_callback)118 void BluetoothAdapterCast::SetDiscoverable(
119     bool discoverable,
120     const base::Closure& callback,
121     const ErrorCallback& error_callback) {
122   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
123   error_callback.Run();
124 }
125 
IsDiscovering() const126 bool BluetoothAdapterCast::IsDiscovering() const {
127   return num_discovery_sessions_ > 0;
128 }
129 
GetUUIDs() const130 BluetoothAdapter::UUIDList BluetoothAdapterCast::GetUUIDs() const {
131   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
132   return UUIDList();
133 }
134 
CreateRfcommService(const BluetoothUUID & uuid,const ServiceOptions & options,const CreateServiceCallback & callback,const CreateServiceErrorCallback & error_callback)135 void BluetoothAdapterCast::CreateRfcommService(
136     const BluetoothUUID& uuid,
137     const ServiceOptions& options,
138     const CreateServiceCallback& callback,
139     const CreateServiceErrorCallback& error_callback) {
140   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
141   error_callback.Run("Not Implemented");
142 }
143 
CreateL2capService(const BluetoothUUID & uuid,const ServiceOptions & options,const CreateServiceCallback & callback,const CreateServiceErrorCallback & error_callback)144 void BluetoothAdapterCast::CreateL2capService(
145     const BluetoothUUID& uuid,
146     const ServiceOptions& options,
147     const CreateServiceCallback& callback,
148     const CreateServiceErrorCallback& error_callback) {
149   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
150   error_callback.Run("Not Implemented");
151 }
152 
RegisterAdvertisement(std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,const CreateAdvertisementCallback & callback,const AdvertisementErrorCallback & error_callback)153 void BluetoothAdapterCast::RegisterAdvertisement(
154     std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
155     const CreateAdvertisementCallback& callback,
156     const AdvertisementErrorCallback& error_callback) {
157   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
158   error_callback.Run(BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
159 }
160 
SetAdvertisingInterval(const base::TimeDelta & min,const base::TimeDelta & max,const base::Closure & callback,const AdvertisementErrorCallback & error_callback)161 void BluetoothAdapterCast::SetAdvertisingInterval(
162     const base::TimeDelta& min,
163     const base::TimeDelta& max,
164     const base::Closure& callback,
165     const AdvertisementErrorCallback& error_callback) {
166   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
167   error_callback.Run(BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
168 }
169 
ResetAdvertising(const base::Closure & callback,const AdvertisementErrorCallback & error_callback)170 void BluetoothAdapterCast::ResetAdvertising(
171     const base::Closure& callback,
172     const AdvertisementErrorCallback& error_callback) {
173   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
174   error_callback.Run(BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM);
175 }
176 
GetGattService(const std::string & identifier) const177 BluetoothLocalGattService* BluetoothAdapterCast::GetGattService(
178     const std::string& identifier) const {
179   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
180   return nullptr;
181 }
182 
GetWeakPtr()183 base::WeakPtr<BluetoothAdapter> BluetoothAdapterCast::GetWeakPtr() {
184   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
185   return weak_factory_.GetWeakPtr();
186 }
187 
GetCastWeakPtr()188 base::WeakPtr<BluetoothAdapterCast> BluetoothAdapterCast::GetCastWeakPtr() {
189   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
190   return weak_factory_.GetWeakPtr();
191 }
192 
SetPoweredImpl(bool powered)193 bool BluetoothAdapterCast::SetPoweredImpl(bool powered) {
194   NOTREACHED() << "This method is not invoked when SetPowered() is overridden.";
195   return true;
196 }
197 
StartScanWithFilter(std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,DiscoverySessionResultCallback callback)198 void BluetoothAdapterCast::StartScanWithFilter(
199     std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
200     DiscoverySessionResultCallback callback) {
201   // The discovery filter is unused for now, as the Cast bluetooth stack does
202   // not expose scan filters yet. However, implementation of filtering would
203   // save numerous UI<->IO threadhops by eliminating unnecessary calls to
204   // GetDevice().
205   // TODO(bcf|slan): Wire this up once scan filters are implemented.
206   (void)discovery_filter;
207 
208   auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
209 
210   // Add this request to the queue.
211   pending_discovery_requests_.emplace(BluetoothAdapterCast::DiscoveryParams(
212       std::move(discovery_filter),
213       base::BindRepeating(copyable_callback, /*is_error=*/false,
214                           UMABluetoothDiscoverySessionOutcome::SUCCESS),
215       base::BindOnce(copyable_callback, /*is_error=*/true)));
216 
217   // If the queue length is greater than 1 (i.e. there was a pending request
218   // when this method was called), exit early. This request will be processed
219   // after the pending requests.
220   if (pending_discovery_requests_.size() > 1u)
221     return;
222 
223   // There is no active discovery session, and no pending requests. Enable
224   // scanning.
225   le_scan_manager_->RequestScan(base::BindOnce(
226       &BluetoothAdapterCast::OnScanEnabled, weak_factory_.GetWeakPtr()));
227 }
228 
UpdateFilter(std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,DiscoverySessionResultCallback callback)229 void BluetoothAdapterCast::UpdateFilter(
230     std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
231     DiscoverySessionResultCallback callback) {
232   // The discovery filter is unused for now, as the Cast bluetooth stack does
233   // not expose scan filters yet. However, implementation of filtering would
234   // save numerous UI<->IO threadhops by eliminating unnecessary calls to
235   // GetDevice().
236   // TODO(bcf|slan): Wire this up once scan filters are implemented.
237 
238   // If calling update then there must be other sessions actively scanning
239   // besides this one.
240   DCHECK_GT(NumDiscoverySessions(), 1);
241 
242   // Since filters are not used simply return success.
243   std::move(callback).Run(/*is_error=*/false,
244                           UMABluetoothDiscoverySessionOutcome::SUCCESS);
245 }
246 
StopScan(DiscoverySessionResultCallback callback)247 void BluetoothAdapterCast::StopScan(DiscoverySessionResultCallback callback) {
248   DCHECK(scan_handle_);
249   scan_handle_.reset();
250   std::move(callback).Run(/*is_error*/ false,
251                           UMABluetoothDiscoverySessionOutcome::SUCCESS);
252 }
253 
RemovePairingDelegateInternal(BluetoothDevice::PairingDelegate * pairing_delegate)254 void BluetoothAdapterCast::RemovePairingDelegateInternal(
255     BluetoothDevice::PairingDelegate* pairing_delegate) {
256   // TODO(slan): Implement this or properly stub.
257   NOTIMPLEMENTED();
258 }
259 
OnConnectChanged(scoped_refptr<chromecast::bluetooth::RemoteDevice> device,bool connected)260 void BluetoothAdapterCast::OnConnectChanged(
261     scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
262     bool connected) {
263   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
264 
265   std::string address = GetCanonicalBluetoothAddress(device->addr());
266   DVLOG(1) << __func__ << " " << address << " connected: " << connected;
267 
268   // This method could be called before this device is detected in a scan and
269   // GetDevice() is called. Add it if needed.
270   if (devices_.find(address) == devices_.end())
271     AddDevice(std::move(device));
272 
273   BluetoothDeviceCast* cast_device = GetCastDevice(address);
274   cast_device->SetConnected(connected);
275 }
276 
OnMtuChanged(scoped_refptr<chromecast::bluetooth::RemoteDevice> device,int mtu)277 void BluetoothAdapterCast::OnMtuChanged(
278     scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
279     int mtu) {
280   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
281 
282   DVLOG(3) << __func__ << " " << GetCanonicalBluetoothAddress(device->addr())
283            << " mtu: " << mtu;
284 }
285 
OnCharacteristicNotification(scoped_refptr<chromecast::bluetooth::RemoteDevice> device,scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,std::vector<uint8_t> value)286 void BluetoothAdapterCast::OnCharacteristicNotification(
287     scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
288     scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,
289     std::vector<uint8_t> value) {
290   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
291 
292   std::string address = GetCanonicalBluetoothAddress(device->addr());
293   BluetoothDeviceCast* cast_device = GetCastDevice(address);
294   if (!cast_device)
295     return;
296 
297   cast_device->UpdateCharacteristicValue(
298       std::move(characteristic), std::move(value),
299       base::BindOnce(
300           &BluetoothAdapterCast::NotifyGattCharacteristicValueChanged,
301           weak_factory_.GetWeakPtr()));
302 }
303 
OnNewScanResult(chromecast::bluetooth::LeScanResult result)304 void BluetoothAdapterCast::OnNewScanResult(
305     chromecast::bluetooth::LeScanResult result) {
306   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
307   DVLOG(3) << __func__;
308 
309   std::string address = GetCanonicalBluetoothAddress(result.addr);
310 
311   // If we haven't created a BluetoothDeviceCast for this address yet, we need
312   // to send an async request to |gatt_client_manager_| for a handle to the
313   // device.
314   if (devices_.find(address) == devices_.end()) {
315     bool first_time_seen =
316         pending_scan_results_.find(address) == pending_scan_results_.end();
317     // These results will be used to construct the BluetoothDeviceCast.
318     pending_scan_results_[address].push_back(result);
319 
320     // Only send a request if this is the first time we've seen this |address|
321     // in a scan. This may happen if we pick up additional GAP advertisements
322     // while the first request is in-flight.
323     if (first_time_seen) {
324       gatt_client_manager_->GetDevice(
325           result.addr, base::BindOnce(&BluetoothAdapterCast::OnGetDevice,
326                                       weak_factory_.GetWeakPtr()));
327     }
328     return;
329   }
330 
331   // Update the device with the ScanResult.
332   BluetoothDeviceCast* device = GetCastDevice(address);
333   if (device->UpdateWithScanResult(result)) {
334     for (auto& observer : observers_)
335       observer.DeviceChanged(this, device);
336   }
337 }
338 
OnScanEnableChanged(bool enabled)339 void BluetoothAdapterCast::OnScanEnableChanged(bool enabled) {
340   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
341   // If the scan function has been disabled during discovery, something has
342   // gone wrong. We should consider re-enabling it here.
343   LOG_IF(WARNING, IsDiscovering() && !enabled)
344       << "BLE scan has been disabled during WebBluetooth discovery!";
345 }
346 
GetCastDevice(const std::string & address)347 BluetoothDeviceCast* BluetoothAdapterCast::GetCastDevice(
348     const std::string& address) {
349   auto it = devices_.find(address);
350   return it == devices_.end()
351              ? nullptr
352              : static_cast<BluetoothDeviceCast*>(it->second.get());
353 }
354 
AddDevice(scoped_refptr<chromecast::bluetooth::RemoteDevice> remote_device)355 void BluetoothAdapterCast::AddDevice(
356     scoped_refptr<chromecast::bluetooth::RemoteDevice> remote_device) {
357   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
358 
359   // This method should not be called if we already have a BluetoothDeviceCast
360   // registered for this device.
361   std::string address = GetCanonicalBluetoothAddress(remote_device->addr());
362   DCHECK(devices_.find(address) == devices_.end());
363 
364   devices_[address] =
365       std::make_unique<BluetoothDeviceCast>(this, remote_device);
366   BluetoothDeviceCast* device = GetCastDevice(address);
367 
368   const auto scan_results = std::move(pending_scan_results_[address]);
369   pending_scan_results_.erase(address);
370 
371   // Update the device with the ScanResults.
372   for (const auto& result : scan_results)
373     device->UpdateWithScanResult(result);
374 
375   // Update the observers of the new device.
376   for (auto& observer : observers_)
377     observer.DeviceAdded(this, device);
378 }
379 
OnScanEnabled(std::unique_ptr<chromecast::bluetooth::LeScanManager::ScanHandle> scan_handle)380 void BluetoothAdapterCast::OnScanEnabled(
381     std::unique_ptr<chromecast::bluetooth::LeScanManager::ScanHandle>
382         scan_handle) {
383   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
384   if (!scan_handle) {
385     LOG(WARNING) << "Failed to start scan.";
386 
387     // Run the error callback.
388     DCHECK(!pending_discovery_requests_.empty());
389     std::move(pending_discovery_requests_.front().error_callback)
390         .Run(UMABluetoothDiscoverySessionOutcome::FAILED);
391     pending_discovery_requests_.pop();
392 
393     // If there is another pending request, try again.
394     if (pending_discovery_requests_.size() > 0u) {
395       le_scan_manager_->RequestScan(base::BindOnce(
396           &BluetoothAdapterCast::OnScanEnabled, weak_factory_.GetWeakPtr()));
397     }
398     return;
399   }
400 
401   scan_handle_ = std::move(scan_handle);
402 
403   // The scan has been successfully enabled. Request the initial scan results
404   // from the scan manager.
405   le_scan_manager_->GetScanResults(base::BindOnce(
406       &BluetoothAdapterCast::OnGetScanResults, weak_factory_.GetWeakPtr()));
407 
408   // For each pending request, increment the count and run the success callback.
409   while (!pending_discovery_requests_.empty()) {
410     num_discovery_sessions_++;
411     pending_discovery_requests_.front().success_callback.Run();
412     pending_discovery_requests_.pop();
413   }
414 }
415 
OnGetDevice(scoped_refptr<chromecast::bluetooth::RemoteDevice> remote_device)416 void BluetoothAdapterCast::OnGetDevice(
417     scoped_refptr<chromecast::bluetooth::RemoteDevice> remote_device) {
418   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
419 
420   std::string address = GetCanonicalBluetoothAddress(remote_device->addr());
421 
422   // This callback could run before or after the device becomes connected and
423   // OnConnectChanged() is called for a particular device. If that happened,
424   // |remote_device| already has a handle. In this case, there should be no
425   // |pending_scan_results_| and we should fast-return.
426   if (devices_.find(address) != devices_.end()) {
427     DCHECK(pending_scan_results_.find(address) == pending_scan_results_.end());
428     return;
429   }
430 
431   // If there is not a device already, there should be at least one ScanResult
432   // which triggered the GetDevice() call.
433   DCHECK(pending_scan_results_.find(address) != pending_scan_results_.end());
434   AddDevice(std::move(remote_device));
435 }
436 
OnGetScanResults(std::vector<chromecast::bluetooth::LeScanResult> results)437 void BluetoothAdapterCast::OnGetScanResults(
438     std::vector<chromecast::bluetooth::LeScanResult> results) {
439   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
440 
441   for (auto& result : results)
442     OnNewScanResult(result);
443 }
444 
InitializeAsynchronously(InitCallback callback)445 void BluetoothAdapterCast::InitializeAsynchronously(InitCallback callback) {
446   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
447   initialized_ = true;
448   std::move(callback).Run();
449 }
450 
451 // static
SetFactory(FactoryCb factory_cb)452 void BluetoothAdapterCast::SetFactory(FactoryCb factory_cb) {
453   FactoryCb& factory = GetFactory();
454   DCHECK(!factory);
455   factory = std::move(factory_cb);
456 }
457 
458 // static
ResetFactoryForTest()459 void BluetoothAdapterCast::ResetFactoryForTest() {
460   GetFactory().Reset();
461 }
462 
463 // static
Create(InitCallback callback)464 base::WeakPtr<BluetoothAdapter> BluetoothAdapterCast::Create(
465     InitCallback callback) {
466   FactoryCb& factory = GetFactory();
467   DCHECK(factory) << "SetFactory() must be called before this method!";
468   base::WeakPtr<BluetoothAdapterCast> weak_ptr = factory.Run();
469 
470   // BluetoothAdapterFactory assumes that |init_callback| will be called
471   // asynchronously the first time, and that IsInitialized() will return false.
472   // Post init_callback to this sequence so that it gets called back later.
473   base::SequencedTaskRunnerHandle::Get()->PostTask(
474       FROM_HERE, base::BindOnce(&BluetoothAdapterCast::InitializeAsynchronously,
475                                 weak_ptr, std::move(callback)));
476   return weak_ptr;
477 }
478 
479 // static
CreateAdapter(InitCallback init_callback)480 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
481     InitCallback init_callback) {
482   return BluetoothAdapterCast::Create(std::move(init_callback));
483 }
484 
485 }  // namespace device
486