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