Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / bluetooth / bluetooth_dispatcher_host.cc
blob86fdf9f366be1a843106f7a032b3e43b575b2f00
1 // Copyright 2014 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.
5 // NETWORK_ERROR Note:
6 // When a device can't be found in the BluetoothAdapter, that generally
7 // indicates that it's gone out of range. We reject with a NetworkError in that
8 // case.
9 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-connectgatt
11 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/browser/bad_message.h"
16 #include "content/browser/frame_host/render_frame_host_impl.h"
17 #include "content/common/bluetooth/bluetooth_messages.h"
18 #include "device/bluetooth/bluetooth_adapter.h"
19 #include "device/bluetooth/bluetooth_adapter_factory.h"
20 #include "device/bluetooth/bluetooth_device.h"
21 #include "device/bluetooth/bluetooth_discovery_session.h"
22 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
23 #include "device/bluetooth/bluetooth_gatt_service.h"
25 using blink::WebBluetoothError;
26 using device::BluetoothAdapter;
27 using device::BluetoothAdapterFactory;
28 using device::BluetoothGattCharacteristic;
29 using device::BluetoothGattService;
30 using device::BluetoothUUID;
32 namespace {
34 // These types of errors aren't as common. We log them to understand
35 // how common they are and if we need to investigate more.
36 enum class BluetoothGATTError {
37 UNKNOWN,
38 FAILED,
39 IN_PROGRESS,
40 NOT_PAIRED,
41 // Add errors above this line and update corresponding histograms.xml enum.
42 MAX_ERROR,
45 enum class UMARequestDeviceOutcome {
46 SUCCESS = 0,
47 NO_BLUETOOTH_ADAPTER = 1,
48 NO_RENDER_FRAME = 2,
49 DISCOVERY_START_FAILED = 3,
50 DISCOVERY_STOP_FAILED = 4,
51 NO_MATCHING_DEVICES_FOUND = 5,
52 // NOTE: Add new requestDevice() outcomes immediately above this line. Make
53 // sure to update the enum list in tools/histogram/histograms.xml accordingly.
54 COUNT
57 void RecordRequestDeviceOutcome(UMARequestDeviceOutcome outcome) {
58 UMA_HISTOGRAM_ENUMERATION("Bluetooth.RequestDevice.Outcome",
59 static_cast<int>(outcome),
60 static_cast<int>(UMARequestDeviceOutcome::COUNT));
63 // TODO(ortuno): Once we have a chooser for scanning and the right
64 // callback for discovered services we should delete these constants.
65 // https://crbug.com/436280 and https://crbug.com/484504
66 const int kDelayTime = 5; // 5 seconds for scanning and discovering
67 const int kTestingDelayTime = 0; // No need to wait during tests
69 // Defined at
70 // https://webbluetoothchrome.github.io/web-bluetooth/#dfn-matches-a-filter
71 bool MatchesFilter(const std::set<BluetoothUUID>& device_uuids,
72 const content::BluetoothScanFilter& filter) {
73 if (filter.services.empty())
74 return false;
75 for (const BluetoothUUID& service : filter.services) {
76 if (!ContainsKey(device_uuids, service)) {
77 return false;
80 return true;
83 bool MatchesFilters(const device::BluetoothDevice& device,
84 const std::vector<content::BluetoothScanFilter>& filters) {
85 const std::vector<BluetoothUUID>& device_uuid_list = device.GetUUIDs();
86 const std::set<BluetoothUUID> device_uuids(device_uuid_list.begin(),
87 device_uuid_list.end());
88 for (const content::BluetoothScanFilter& filter : filters) {
89 if (MatchesFilter(device_uuids, filter)) {
90 return true;
93 return false;
96 void AddToHistogram(BluetoothGATTError error) {
97 UMA_HISTOGRAM_ENUMERATION("Bluetooth.GATTErrors", static_cast<int>(error),
98 static_cast<int>(BluetoothGATTError::MAX_ERROR));
101 WebBluetoothError TranslateConnectError(
102 device::BluetoothDevice::ConnectErrorCode error_code) {
103 switch (error_code) {
104 case device::BluetoothDevice::ERROR_UNKNOWN:
105 return WebBluetoothError::ConnectUnknownError;
106 case device::BluetoothDevice::ERROR_INPROGRESS:
107 return WebBluetoothError::ConnectAlreadyInProgress;
108 case device::BluetoothDevice::ERROR_FAILED:
109 return WebBluetoothError::ConnectUnknownFailure;
110 case device::BluetoothDevice::ERROR_AUTH_FAILED:
111 return WebBluetoothError::ConnectAuthFailed;
112 case device::BluetoothDevice::ERROR_AUTH_CANCELED:
113 return WebBluetoothError::ConnectAuthCanceled;
114 case device::BluetoothDevice::ERROR_AUTH_REJECTED:
115 return WebBluetoothError::ConnectAuthRejected;
116 case device::BluetoothDevice::ERROR_AUTH_TIMEOUT:
117 return WebBluetoothError::ConnectAuthTimeout;
118 case device::BluetoothDevice::ERROR_UNSUPPORTED_DEVICE:
119 return WebBluetoothError::ConnectUnsupportedDevice;
121 NOTREACHED();
122 return WebBluetoothError::UntranslatedConnectErrorCode;
125 blink::WebBluetoothError TranslateGATTError(
126 BluetoothGattService::GattErrorCode error_code) {
127 switch (error_code) {
128 case BluetoothGattService::GATT_ERROR_UNKNOWN:
129 AddToHistogram(BluetoothGATTError::UNKNOWN);
130 return blink::WebBluetoothError::GATTUnknownError;
131 case BluetoothGattService::GATT_ERROR_FAILED:
132 AddToHistogram(BluetoothGATTError::FAILED);
133 return blink::WebBluetoothError::GATTUnknownFailure;
134 case BluetoothGattService::GATT_ERROR_IN_PROGRESS:
135 AddToHistogram(BluetoothGATTError::IN_PROGRESS);
136 return blink::WebBluetoothError::GATTOperationInProgress;
137 case BluetoothGattService::GATT_ERROR_INVALID_LENGTH:
138 return blink::WebBluetoothError::GATTInvalidAttributeLength;
139 case BluetoothGattService::GATT_ERROR_NOT_PERMITTED:
140 return blink::WebBluetoothError::GATTNotPermitted;
141 case BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED:
142 return blink::WebBluetoothError::GATTNotAuthorized;
143 case BluetoothGattService::GATT_ERROR_NOT_PAIRED:
144 AddToHistogram(BluetoothGATTError::NOT_PAIRED);
145 return blink::WebBluetoothError::GATTNotPaired;
146 case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED:
147 return blink::WebBluetoothError::GATTNotSupported;
149 NOTREACHED();
150 return blink::WebBluetoothError::GATTUntranslatedErrorCode;
153 } // namespace
155 namespace content {
157 BluetoothDispatcherHost::BluetoothDispatcherHost(int render_process_id)
158 : BrowserMessageFilter(BluetoothMsgStart),
159 render_process_id_(render_process_id),
160 weak_ptr_factory_(this) {
161 DCHECK_CURRENTLY_ON(BrowserThread::UI);
162 current_delay_time_ = kDelayTime;
163 if (BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
164 BluetoothAdapterFactory::GetAdapter(
165 base::Bind(&BluetoothDispatcherHost::set_adapter,
166 weak_ptr_factory_.GetWeakPtr()));
169 void BluetoothDispatcherHost::OnDestruct() const {
170 // See class comment: UI Thread Note.
171 BrowserThread::DeleteOnUIThread::Destruct(this);
174 void BluetoothDispatcherHost::OverrideThreadForMessage(
175 const IPC::Message& message,
176 content::BrowserThread::ID* thread) {
177 // See class comment: UI Thread Note.
178 *thread = BrowserThread::UI;
181 bool BluetoothDispatcherHost::OnMessageReceived(const IPC::Message& message) {
182 DCHECK_CURRENTLY_ON(BrowserThread::UI);
183 bool handled = true;
184 IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcherHost, message)
185 IPC_MESSAGE_HANDLER(BluetoothHostMsg_RequestDevice, OnRequestDevice)
186 IPC_MESSAGE_HANDLER(BluetoothHostMsg_ConnectGATT, OnConnectGATT)
187 IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetPrimaryService, OnGetPrimaryService)
188 IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic)
189 IPC_MESSAGE_HANDLER(BluetoothHostMsg_ReadValue, OnReadValue)
190 IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue)
191 IPC_MESSAGE_UNHANDLED(handled = false)
192 IPC_END_MESSAGE_MAP()
193 return handled;
196 void BluetoothDispatcherHost::SetBluetoothAdapterForTesting(
197 scoped_refptr<device::BluetoothAdapter> mock_adapter) {
198 DCHECK_CURRENTLY_ON(BrowserThread::UI);
199 current_delay_time_ = kTestingDelayTime;
200 set_adapter(mock_adapter.Pass());
203 BluetoothDispatcherHost::~BluetoothDispatcherHost() {
204 DCHECK_CURRENTLY_ON(BrowserThread::UI);
205 // Clear adapter, releasing observer references.
206 set_adapter(scoped_refptr<device::BluetoothAdapter>());
209 // Stores information associated with an in-progress requestDevice call. This
210 // will include the state of the active chooser dialog in a future patch.
211 struct BluetoothDispatcherHost::RequestDeviceSession {
212 RequestDeviceSession(const std::vector<BluetoothScanFilter>& filters,
213 const std::vector<BluetoothUUID>& optional_services)
214 : filters(filters), optional_services(optional_services) {}
216 std::vector<BluetoothScanFilter> filters;
217 std::vector<BluetoothUUID> optional_services;
220 void BluetoothDispatcherHost::set_adapter(
221 scoped_refptr<device::BluetoothAdapter> adapter) {
222 DCHECK_CURRENTLY_ON(BrowserThread::UI);
223 if (adapter_.get())
224 adapter_->RemoveObserver(this);
225 adapter_ = adapter;
226 if (adapter_.get())
227 adapter_->AddObserver(this);
230 static scoped_ptr<device::BluetoothDiscoveryFilter> ComputeScanFilter(
231 const std::vector<BluetoothScanFilter>& filters) {
232 std::set<BluetoothUUID> services;
233 for (const BluetoothScanFilter& filter : filters) {
234 services.insert(filter.services.begin(), filter.services.end());
236 scoped_ptr<device::BluetoothDiscoveryFilter> discovery_filter(
237 new device::BluetoothDiscoveryFilter(
238 device::BluetoothDiscoveryFilter::TRANSPORT_DUAL));
239 for (const BluetoothUUID& service : services) {
240 discovery_filter->AddUUID(service);
242 return discovery_filter.Pass();
245 void BluetoothDispatcherHost::OnRequestDevice(
246 int thread_id,
247 int request_id,
248 int frame_routing_id,
249 const std::vector<BluetoothScanFilter>& filters,
250 const std::vector<BluetoothUUID>& optional_services) {
251 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
253 RenderFrameHostImpl* render_frame_host =
254 RenderFrameHostImpl::FromID(render_process_id_, frame_routing_id);
256 if (!render_frame_host) {
257 DLOG(WARNING)
258 << "Got a requestDevice IPC without a matching RenderFrameHost: "
259 << render_process_id_ << ", " << frame_routing_id;
260 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_RENDER_FRAME);
261 Send(new BluetoothMsg_RequestDeviceError(
262 thread_id, request_id, WebBluetoothError::RequestDeviceWithoutFrame));
265 // TODO(scheib): Device selection UI: crbug.com/436280
266 // TODO(scheib): Utilize BluetoothAdapter::Observer::DeviceAdded/Removed.
267 if (adapter_.get()) {
268 if (!request_device_sessions_
269 .insert(std::make_pair(
270 std::make_pair(thread_id, request_id),
271 RequestDeviceSession(filters, optional_services)))
272 .second) {
273 LOG(ERROR) << "2 requestDevice() calls with the same thread_id ("
274 << thread_id << ") and request_id (" << request_id
275 << ") shouldn't arrive at the same BluetoothDispatcherHost.";
276 bad_message::ReceivedBadMessage(
277 this, bad_message::BDH_DUPLICATE_REQUEST_DEVICE_ID);
279 adapter_->StartDiscoverySessionWithFilter(
280 ComputeScanFilter(filters),
281 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStarted,
282 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id),
283 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStartedError,
284 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id));
285 } else {
286 DLOG(WARNING) << "No BluetoothAdapter. Can't serve requestDevice.";
287 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_BLUETOOTH_ADAPTER);
288 Send(new BluetoothMsg_RequestDeviceError(
289 thread_id, request_id, WebBluetoothError::NoBluetoothAdapter));
291 return;
294 void BluetoothDispatcherHost::OnConnectGATT(
295 int thread_id,
296 int request_id,
297 const std::string& device_instance_id) {
298 DCHECK_CURRENTLY_ON(BrowserThread::UI);
299 // TODO(ortuno): Right now it's pointless to check if the domain has access to
300 // the device, because any domain can connect to any device. But once
301 // permissions are implemented we should check that the domain has access to
302 // the device. https://crbug.com/484745
303 device::BluetoothDevice* device = adapter_->GetDevice(device_instance_id);
304 if (device == nullptr) { // See "NETWORK_ERROR Note" above.
305 Send(new BluetoothMsg_ConnectGATTError(
306 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange));
307 return;
309 device->CreateGattConnection(
310 base::Bind(&BluetoothDispatcherHost::OnGATTConnectionCreated,
311 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id,
312 device_instance_id),
313 base::Bind(&BluetoothDispatcherHost::OnCreateGATTConnectionError,
314 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id,
315 device_instance_id));
318 void BluetoothDispatcherHost::OnGetPrimaryService(
319 int thread_id,
320 int request_id,
321 const std::string& device_instance_id,
322 const std::string& service_uuid) {
323 DCHECK_CURRENTLY_ON(BrowserThread::UI);
324 // TODO(ortuno): Check if device_instance_id is in "allowed devices"
325 // https://crbug.com/493459
326 // TODO(ortuno): Check if service_uuid is in "allowed services"
327 // https://crbug.com/493460
328 // For now just wait a fixed time and call OnServiceDiscovered.
329 // TODO(ortuno): Use callback once it's implemented http://crbug.com/484504
330 BrowserThread::PostDelayedTask(
331 BrowserThread::UI, FROM_HERE,
332 base::Bind(&BluetoothDispatcherHost::OnServicesDiscovered,
333 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id,
334 device_instance_id, service_uuid),
335 base::TimeDelta::FromSeconds(current_delay_time_));
338 void BluetoothDispatcherHost::OnGetCharacteristic(
339 int thread_id,
340 int request_id,
341 const std::string& service_instance_id,
342 const std::string& characteristic_uuid) {
343 DCHECK_CURRENTLY_ON(BrowserThread::UI);
345 auto device_iter = service_to_device_.find(service_instance_id);
346 // A service_instance_id not in the map implies a hostile renderer
347 // because a renderer obtains the service id from this class and
348 // it will be added to the map at that time.
349 if (device_iter == service_to_device_.end()) {
350 // Kill the renderer
351 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_SERVICE_ID);
352 return;
355 // TODO(ortuno): Check if domain has access to device.
356 // https://crbug.com/493459
357 device::BluetoothDevice* device =
358 adapter_->GetDevice(device_iter->second /* device_instance_id */);
360 if (device == nullptr) { // See "NETWORK_ERROR Note" above.
361 Send(new BluetoothMsg_GetCharacteristicError(
362 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange));
363 return;
366 // TODO(ortuno): Check if domain has access to service
367 // http://crbug.com/493460
368 device::BluetoothGattService* service =
369 device->GetGattService(service_instance_id);
370 if (!service) {
371 Send(new BluetoothMsg_GetCharacteristicError(
372 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists));
373 return;
376 for (BluetoothGattCharacteristic* characteristic :
377 service->GetCharacteristics()) {
378 if (characteristic->GetUUID().canonical_value() == characteristic_uuid) {
379 const std::string& characteristic_instance_id =
380 characteristic->GetIdentifier();
382 auto insert_result = characteristic_to_service_.insert(
383 make_pair(characteristic_instance_id, service_instance_id));
385 // If value is already in map, DCHECK it's valid.
386 if (!insert_result.second)
387 DCHECK(insert_result.first->second == service_instance_id);
389 // TODO(ortuno): Use generated instance ID instead.
390 // https://crbug.com/495379
391 Send(new BluetoothMsg_GetCharacteristicSuccess(
392 thread_id, request_id, characteristic_instance_id));
393 return;
396 Send(new BluetoothMsg_GetCharacteristicError(
397 thread_id, request_id, WebBluetoothError::CharacteristicNotFound));
400 void BluetoothDispatcherHost::OnReadValue(
401 int thread_id,
402 int request_id,
403 const std::string& characteristic_instance_id) {
404 DCHECK_CURRENTLY_ON(BrowserThread::UI);
406 auto characteristic_iter =
407 characteristic_to_service_.find(characteristic_instance_id);
408 // A characteristic_instance_id not in the map implies a hostile renderer
409 // because a renderer obtains the characteristic id from this class and
410 // it will be added to the map at that time.
411 if (characteristic_iter == characteristic_to_service_.end()) {
412 // Kill the renderer
413 bad_message::ReceivedBadMessage(this,
414 bad_message::BDH_INVALID_CHARACTERISTIC_ID);
415 return;
417 const std::string& service_instance_id = characteristic_iter->second;
419 auto device_iter = service_to_device_.find(service_instance_id);
421 CHECK(device_iter != service_to_device_.end());
423 device::BluetoothDevice* device =
424 adapter_->GetDevice(device_iter->second /* device_instance_id */);
425 if (device == nullptr) { // See "NETWORK_ERROR Note" above.
426 Send(new BluetoothMsg_ReadCharacteristicValueError(
427 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange));
428 return;
431 BluetoothGattService* service = device->GetGattService(service_instance_id);
432 if (service == nullptr) {
433 Send(new BluetoothMsg_ReadCharacteristicValueError(
434 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists));
435 return;
438 BluetoothGattCharacteristic* characteristic =
439 service->GetCharacteristic(characteristic_instance_id);
440 if (characteristic == nullptr) {
441 Send(new BluetoothMsg_ReadCharacteristicValueError(
442 thread_id, request_id,
443 WebBluetoothError::CharacteristicNoLongerExists));
444 return;
447 characteristic->ReadRemoteCharacteristic(
448 base::Bind(&BluetoothDispatcherHost::OnCharacteristicValueRead,
449 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id),
450 base::Bind(&BluetoothDispatcherHost::OnCharacteristicReadValueError,
451 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id));
454 void BluetoothDispatcherHost::OnWriteValue(
455 int thread_id,
456 int request_id,
457 const std::string& characteristic_instance_id,
458 const std::vector<uint8_t>& value) {
459 DCHECK_CURRENTLY_ON(BrowserThread::UI);
461 // Length check per step 3 of writeValue algorithm:
462 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattcharacteristic-writevalue
463 // We perform the length check on the renderer side. So if we
464 // get a value with length > 512, we can assume it's a hostile
465 // renderer and kill it.
466 if (value.size() > 512) {
467 bad_message::ReceivedBadMessage(
468 this, bad_message::BDH_INVALID_WRITE_VALUE_LENGTH);
469 return;
472 auto characteristic_iter =
473 characteristic_to_service_.find(characteristic_instance_id);
474 // A characteristic_instance_id not in the map implies a hostile renderer
475 // because a renderer obtains the characteristic id from this class and
476 // it will be added to the map at that time.
477 if (characteristic_iter == characteristic_to_service_.end()) {
478 bad_message::ReceivedBadMessage(this,
479 bad_message::BDH_INVALID_CHARACTERISTIC_ID);
480 return;
482 const std::string& service_instance_id = characteristic_iter->second;
484 auto device_iter = service_to_device_.find(service_instance_id);
486 CHECK(device_iter != service_to_device_.end());
488 device::BluetoothDevice* device =
489 adapter_->GetDevice(device_iter->second /* device_instance_id */);
490 if (device == nullptr) { // See "NETWORK_ERROR Note" above.
491 Send(new BluetoothMsg_WriteCharacteristicValueError(
492 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange));
493 return;
496 BluetoothGattService* service = device->GetGattService(service_instance_id);
497 if (service == nullptr) {
498 Send(new BluetoothMsg_WriteCharacteristicValueError(
499 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists));
500 return;
503 BluetoothGattCharacteristic* characteristic =
504 service->GetCharacteristic(characteristic_instance_id);
505 if (characteristic == nullptr) {
506 Send(new BluetoothMsg_WriteCharacteristicValueError(
507 thread_id, request_id,
508 WebBluetoothError::CharacteristicNoLongerExists));
509 return;
511 characteristic->WriteRemoteCharacteristic(
512 value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess,
513 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id),
514 base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed,
515 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id));
518 void BluetoothDispatcherHost::OnDiscoverySessionStarted(
519 int thread_id,
520 int request_id,
521 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
522 DCHECK_CURRENTLY_ON(BrowserThread::UI);
523 BrowserThread::PostDelayedTask(
524 BrowserThread::UI, FROM_HERE,
525 base::Bind(&BluetoothDispatcherHost::StopDiscoverySession,
526 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id,
527 base::Passed(&discovery_session)),
528 base::TimeDelta::FromSeconds(current_delay_time_));
531 void BluetoothDispatcherHost::OnDiscoverySessionStartedError(int thread_id,
532 int request_id) {
533 DCHECK_CURRENTLY_ON(BrowserThread::UI);
534 DLOG(WARNING) << "BluetoothDispatcherHost::OnDiscoverySessionStartedError";
535 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::DISCOVERY_START_FAILED);
536 Send(new BluetoothMsg_RequestDeviceError(
537 thread_id, request_id, WebBluetoothError::DiscoverySessionStartFailed));
538 request_device_sessions_.erase(std::make_pair(thread_id, request_id));
541 void BluetoothDispatcherHost::StopDiscoverySession(
542 int thread_id,
543 int request_id,
544 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
545 DCHECK_CURRENTLY_ON(BrowserThread::UI);
546 discovery_session->Stop(
547 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStopped,
548 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id),
549 base::Bind(&BluetoothDispatcherHost::OnDiscoverySessionStoppedError,
550 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id));
553 void BluetoothDispatcherHost::OnDiscoverySessionStopped(int thread_id,
554 int request_id) {
555 DCHECK_CURRENTLY_ON(BrowserThread::UI);
556 auto session =
557 request_device_sessions_.find(std::make_pair(thread_id, request_id));
558 CHECK(session != request_device_sessions_.end());
559 BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
560 for (device::BluetoothDevice* device : devices) {
561 if (MatchesFilters(*device, session->second.filters)) {
562 content::BluetoothDevice device_ipc(
563 device->GetAddress(), // instance_id
564 device->GetName(), // name
565 device->GetBluetoothClass(), // device_class
566 device->GetVendorIDSource(), // vendor_id_source
567 device->GetVendorID(), // vendor_id
568 device->GetProductID(), // product_id
569 device->GetDeviceID(), // product_version
570 device->IsPaired(), // paired
571 content::BluetoothDevice::UUIDsFromBluetoothUUIDs(
572 device->GetUUIDs())); // uuids
573 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS);
574 Send(new BluetoothMsg_RequestDeviceSuccess(thread_id, request_id,
575 device_ipc));
576 request_device_sessions_.erase(session);
577 return;
580 RecordRequestDeviceOutcome(
581 UMARequestDeviceOutcome::NO_MATCHING_DEVICES_FOUND);
582 Send(new BluetoothMsg_RequestDeviceError(thread_id, request_id,
583 WebBluetoothError::NoDevicesFound));
584 request_device_sessions_.erase(session);
587 void BluetoothDispatcherHost::OnDiscoverySessionStoppedError(int thread_id,
588 int request_id) {
589 DCHECK_CURRENTLY_ON(BrowserThread::UI);
590 DLOG(WARNING) << "BluetoothDispatcherHost::OnDiscoverySessionStoppedError";
591 RecordRequestDeviceOutcome(UMARequestDeviceOutcome::DISCOVERY_STOP_FAILED);
592 Send(new BluetoothMsg_RequestDeviceError(
593 thread_id, request_id, WebBluetoothError::DiscoverySessionStopFailed));
594 request_device_sessions_.erase(std::make_pair(thread_id, request_id));
597 void BluetoothDispatcherHost::OnGATTConnectionCreated(
598 int thread_id,
599 int request_id,
600 const std::string& device_instance_id,
601 scoped_ptr<device::BluetoothGattConnection> connection) {
602 // TODO(ortuno): Save the BluetoothGattConnection so we can disconnect
603 // from it.
604 Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id,
605 device_instance_id));
608 void BluetoothDispatcherHost::OnCreateGATTConnectionError(
609 int thread_id,
610 int request_id,
611 const std::string& device_instance_id,
612 device::BluetoothDevice::ConnectErrorCode error_code) {
613 // There was an error creating the ATT Bearer so we reject with
614 // NetworkError.
615 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-connectgatt
616 Send(new BluetoothMsg_ConnectGATTError(thread_id, request_id,
617 TranslateConnectError(error_code)));
620 void BluetoothDispatcherHost::OnServicesDiscovered(
621 int thread_id,
622 int request_id,
623 const std::string& device_instance_id,
624 const std::string& service_uuid) {
625 DCHECK_CURRENTLY_ON(BrowserThread::UI);
627 device::BluetoothDevice* device = adapter_->GetDevice(device_instance_id);
628 if (device == nullptr) { // See "NETWORK_ERROR Note" above.
629 Send(new BluetoothMsg_GetPrimaryServiceError(
630 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange));
631 return;
633 for (BluetoothGattService* service : device->GetGattServices()) {
634 if (service->GetUUID().canonical_value() == service_uuid) {
635 // TODO(ortuno): Use generated instance ID instead.
636 // https://crbug.com/495379
637 const std::string& service_identifier = service->GetIdentifier();
638 auto insert_result = service_to_device_.insert(
639 make_pair(service_identifier, device_instance_id));
641 // If a value is already in map, DCHECK it's valid.
642 if (!insert_result.second)
643 DCHECK(insert_result.first->second == device_instance_id);
645 Send(new BluetoothMsg_GetPrimaryServiceSuccess(thread_id, request_id,
646 service_identifier));
647 return;
650 Send(new BluetoothMsg_GetPrimaryServiceError(
651 thread_id, request_id, WebBluetoothError::ServiceNotFound));
654 void BluetoothDispatcherHost::OnCharacteristicValueRead(
655 int thread_id,
656 int request_id,
657 const std::vector<uint8>& value) {
658 Send(new BluetoothMsg_ReadCharacteristicValueSuccess(thread_id, request_id,
659 value));
662 void BluetoothDispatcherHost::OnCharacteristicReadValueError(
663 int thread_id,
664 int request_id,
665 device::BluetoothGattService::GattErrorCode error_code) {
666 Send(new BluetoothMsg_ReadCharacteristicValueError(
667 thread_id, request_id, TranslateGATTError(error_code)));
670 void BluetoothDispatcherHost::OnWriteValueSuccess(int thread_id,
671 int request_id) {
672 Send(new BluetoothMsg_WriteCharacteristicValueSuccess(thread_id, request_id));
675 void BluetoothDispatcherHost::OnWriteValueFailed(
676 int thread_id,
677 int request_id,
678 device::BluetoothGattService::GattErrorCode error_code) {
679 Send(new BluetoothMsg_WriteCharacteristicValueError(
680 thread_id, request_id, TranslateGATTError(error_code)));
683 } // namespace content