| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 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-conne
ctgatt | |
| 10 | |
| 11 // ID Not In Map Note: | 5 // ID Not In Map Note: |
| 12 // A service, characteristic, or descriptor ID not in the corresponding | 6 // A service, characteristic, or descriptor ID not in the corresponding |
| 13 // BluetoothDispatcherHost map [service_to_device_, characteristic_to_service_, | 7 // BluetoothDispatcherHost map [service_to_device_, characteristic_to_service_, |
| 14 // descriptor_to_characteristic_] implies a hostile renderer because a renderer | 8 // descriptor_to_characteristic_] implies a hostile renderer because a renderer |
| 15 // obtains the corresponding ID from this class and it will be added to the map | 9 // obtains the corresponding ID from this class and it will be added to the map |
| 16 // at that time. | 10 // at that time. |
| 17 | 11 |
| 18 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" | 12 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
| 19 | 13 |
| 20 #include "base/bind.h" | 14 #include "base/bind.h" |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 } | 270 } |
| 277 | 271 |
| 278 const int thread_id; | 272 const int thread_id; |
| 279 const int request_id; | 273 const int request_id; |
| 280 const std::vector<BluetoothScanFilter> filters; | 274 const std::vector<BluetoothScanFilter> filters; |
| 281 const std::vector<BluetoothUUID> optional_services; | 275 const std::vector<BluetoothUUID> optional_services; |
| 282 scoped_ptr<BluetoothChooser> chooser; | 276 scoped_ptr<BluetoothChooser> chooser; |
| 283 scoped_ptr<device::BluetoothDiscoverySession> discovery_session; | 277 scoped_ptr<device::BluetoothDiscoverySession> discovery_session; |
| 284 }; | 278 }; |
| 285 | 279 |
| 280 struct BluetoothDispatcherHost::CacheQueryResult { |
| 281 CacheQueryResult() |
| 282 : device(nullptr), |
| 283 service(nullptr), |
| 284 characteristic(nullptr), |
| 285 outcome(CacheQueryOutcome::SUCCESS) {} |
| 286 ~CacheQueryResult() {} |
| 287 WebBluetoothError GetWebError() { |
| 288 switch (outcome) { |
| 289 case CacheQueryOutcome::SUCCESS: |
| 290 case CacheQueryOutcome::BAD_RENDERER: |
| 291 NOTIMPLEMENTED(); |
| 292 return WebBluetoothError::DeviceNoLongerInRange; |
| 293 case CacheQueryOutcome::NO_DEVICE: |
| 294 return WebBluetoothError::DeviceNoLongerInRange; |
| 295 case CacheQueryOutcome::NO_SERVICE: |
| 296 return WebBluetoothError::ServiceNoLongerExists; |
| 297 case CacheQueryOutcome::NO_CHARACTERISTIC: |
| 298 return WebBluetoothError::CharacteristicNoLongerExists; |
| 299 } |
| 300 } |
| 301 |
| 302 device::BluetoothDevice* device; |
| 303 device::BluetoothGattService* service; |
| 304 device::BluetoothGattCharacteristic* characteristic; |
| 305 CacheQueryOutcome outcome; |
| 306 }; |
| 307 |
| 286 void BluetoothDispatcherHost::set_adapter( | 308 void BluetoothDispatcherHost::set_adapter( |
| 287 scoped_refptr<device::BluetoothAdapter> adapter) { | 309 scoped_refptr<device::BluetoothAdapter> adapter) { |
| 288 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 310 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 289 connections_.clear(); | 311 connections_.clear(); |
| 290 if (adapter_.get()) | 312 if (adapter_.get()) |
| 291 adapter_->RemoveObserver(this); | 313 adapter_->RemoveObserver(this); |
| 292 adapter_ = adapter; | 314 adapter_ = adapter; |
| 293 if (adapter_.get()) | 315 if (adapter_.get()) |
| 294 adapter_->AddObserver(this); | 316 adapter_->AddObserver(this); |
| 295 } | 317 } |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 int request_id, | 532 int request_id, |
| 511 const std::string& device_instance_id) { | 533 const std::string& device_instance_id) { |
| 512 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 534 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 513 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT); | 535 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT); |
| 514 const base::TimeTicks start_time = base::TimeTicks::Now(); | 536 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 515 | 537 |
| 516 // TODO(ortuno): Right now it's pointless to check if the domain has access to | 538 // TODO(ortuno): Right now it's pointless to check if the domain has access to |
| 517 // the device, because any domain can connect to any device. But once | 539 // the device, because any domain can connect to any device. But once |
| 518 // permissions are implemented we should check that the domain has access to | 540 // permissions are implemented we should check that the domain has access to |
| 519 // the device. https://crbug.com/484745 | 541 // the device. https://crbug.com/484745 |
| 520 device::BluetoothDevice* device = adapter_->GetDevice(device_instance_id); | 542 |
| 521 if (device == nullptr) { // See "NETWORK_ERROR Note" above. | 543 CacheQueryResult query_result = CacheQueryResult(); |
| 522 RecordConnectGATTOutcome(UMAConnectGATTOutcome::NO_DEVICE); | 544 QueryCacheForDevice(device_instance_id, query_result); |
| 523 Send(new BluetoothMsg_ConnectGATTError( | 545 |
| 524 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); | 546 if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| 547 RecordConnectGATTOutcome(query_result.outcome); |
| 548 Send(new BluetoothMsg_ConnectGATTError(thread_id, request_id, |
| 549 query_result.GetWebError())); |
| 525 return; | 550 return; |
| 526 } | 551 } |
| 527 device->CreateGattConnection( | 552 |
| 553 query_result.device->CreateGattConnection( |
| 528 base::Bind(&BluetoothDispatcherHost::OnGATTConnectionCreated, | 554 base::Bind(&BluetoothDispatcherHost::OnGATTConnectionCreated, |
| 529 weak_ptr_on_ui_thread_, thread_id, request_id, | 555 weak_ptr_on_ui_thread_, thread_id, request_id, |
| 530 device_instance_id, start_time), | 556 device_instance_id, start_time), |
| 531 base::Bind(&BluetoothDispatcherHost::OnCreateGATTConnectionError, | 557 base::Bind(&BluetoothDispatcherHost::OnCreateGATTConnectionError, |
| 532 weak_ptr_on_ui_thread_, thread_id, request_id, | 558 weak_ptr_on_ui_thread_, thread_id, request_id, |
| 533 device_instance_id, start_time)); | 559 device_instance_id, start_time)); |
| 534 } | 560 } |
| 535 | 561 |
| 536 void BluetoothDispatcherHost::OnGetPrimaryService( | 562 void BluetoothDispatcherHost::OnGetPrimaryService( |
| 537 int thread_id, | 563 int thread_id, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 558 | 584 |
| 559 void BluetoothDispatcherHost::OnGetCharacteristic( | 585 void BluetoothDispatcherHost::OnGetCharacteristic( |
| 560 int thread_id, | 586 int thread_id, |
| 561 int request_id, | 587 int request_id, |
| 562 const std::string& service_instance_id, | 588 const std::string& service_instance_id, |
| 563 const std::string& characteristic_uuid) { | 589 const std::string& characteristic_uuid) { |
| 564 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 590 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 565 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_CHARACTERISTIC); | 591 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_CHARACTERISTIC); |
| 566 RecordGetCharacteristicCharacteristic(characteristic_uuid); | 592 RecordGetCharacteristicCharacteristic(characteristic_uuid); |
| 567 | 593 |
| 568 auto device_iter = service_to_device_.find(service_instance_id); | 594 CacheQueryResult query_result = CacheQueryResult(); |
| 569 // Kill the renderer, see "ID Not In Map Note" above. | 595 QueryCacheForService(service_instance_id, query_result); |
| 570 if (device_iter == service_to_device_.end()) { | 596 |
| 571 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_SERVICE_ID); | 597 if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
| 572 return; | 598 return; |
| 573 } | 599 } |
| 574 | 600 |
| 575 // TODO(ortuno): Check if domain has access to device. | 601 if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| 576 // https://crbug.com/493459 | 602 RecordGetCharacteristicOutcome(query_result.outcome); |
| 577 device::BluetoothDevice* device = | 603 Send(new BluetoothMsg_GetCharacteristicError(thread_id, request_id, |
| 578 adapter_->GetDevice(device_iter->second /* device_instance_id */); | 604 query_result.GetWebError())); |
| 579 | |
| 580 if (device == nullptr) { // See "NETWORK_ERROR Note" above. | |
| 581 RecordGetCharacteristicOutcome(UMAGetCharacteristicOutcome::NO_DEVICE); | |
| 582 Send(new BluetoothMsg_GetCharacteristicError( | |
| 583 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); | |
| 584 return; | |
| 585 } | |
| 586 | |
| 587 // TODO(ortuno): Check if domain has access to service | |
| 588 // http://crbug.com/493460 | |
| 589 device::BluetoothGattService* service = | |
| 590 device->GetGattService(service_instance_id); | |
| 591 if (!service) { | |
| 592 RecordGetCharacteristicOutcome(UMAGetCharacteristicOutcome::NO_SERVICE); | |
| 593 Send(new BluetoothMsg_GetCharacteristicError( | |
| 594 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists)); | |
| 595 return; | 605 return; |
| 596 } | 606 } |
| 597 | 607 |
| 598 for (BluetoothGattCharacteristic* characteristic : | 608 for (BluetoothGattCharacteristic* characteristic : |
| 599 service->GetCharacteristics()) { | 609 query_result.service->GetCharacteristics()) { |
| 600 if (characteristic->GetUUID().canonical_value() == characteristic_uuid) { | 610 if (characteristic->GetUUID().canonical_value() == characteristic_uuid) { |
| 601 const std::string& characteristic_instance_id = | 611 const std::string& characteristic_instance_id = |
| 602 characteristic->GetIdentifier(); | 612 characteristic->GetIdentifier(); |
| 603 | 613 |
| 604 auto insert_result = characteristic_to_service_.insert( | 614 auto insert_result = characteristic_to_service_.insert( |
| 605 make_pair(characteristic_instance_id, service_instance_id)); | 615 make_pair(characteristic_instance_id, service_instance_id)); |
| 606 | 616 |
| 607 // If value is already in map, DCHECK it's valid. | 617 // If value is already in map, DCHECK it's valid. |
| 608 if (!insert_result.second) | 618 if (!insert_result.second) |
| 609 DCHECK(insert_result.first->second == service_instance_id); | 619 DCHECK(insert_result.first->second == service_instance_id); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 622 } | 632 } |
| 623 | 633 |
| 624 void BluetoothDispatcherHost::OnReadValue( | 634 void BluetoothDispatcherHost::OnReadValue( |
| 625 int thread_id, | 635 int thread_id, |
| 626 int request_id, | 636 int request_id, |
| 627 const std::string& characteristic_instance_id) { | 637 const std::string& characteristic_instance_id) { |
| 628 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 638 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 629 RecordWebBluetoothFunctionCall( | 639 RecordWebBluetoothFunctionCall( |
| 630 UMAWebBluetoothFunction::CHARACTERISTIC_READ_VALUE); | 640 UMAWebBluetoothFunction::CHARACTERISTIC_READ_VALUE); |
| 631 | 641 |
| 632 auto characteristic_iter = | 642 CacheQueryResult query_result = CacheQueryResult(); |
| 633 characteristic_to_service_.find(characteristic_instance_id); | 643 QueryCacheForCharacteristic(characteristic_instance_id, query_result); |
| 634 | 644 |
| 635 // Kill the renderer, see "ID Not In Map Note" above. | 645 if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
| 636 if (characteristic_iter == characteristic_to_service_.end()) { | |
| 637 bad_message::ReceivedBadMessage(this, | |
| 638 bad_message::BDH_INVALID_CHARACTERISTIC_ID); | |
| 639 return; | |
| 640 } | |
| 641 const std::string& service_instance_id = characteristic_iter->second; | |
| 642 | |
| 643 auto device_iter = service_to_device_.find(service_instance_id); | |
| 644 | |
| 645 CHECK(device_iter != service_to_device_.end()); | |
| 646 | |
| 647 device::BluetoothDevice* device = | |
| 648 adapter_->GetDevice(device_iter->second /* device_instance_id */); | |
| 649 if (device == nullptr) { // See "NETWORK_ERROR Note" above. | |
| 650 RecordCharacteristicReadValueOutcome(UMAGATTOperationOutcome::NO_DEVICE); | |
| 651 Send(new BluetoothMsg_ReadCharacteristicValueError( | |
| 652 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); | |
| 653 return; | 646 return; |
| 654 } | 647 } |
| 655 | 648 |
| 656 BluetoothGattService* service = device->GetGattService(service_instance_id); | 649 if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| 657 if (service == nullptr) { | 650 RecordCharacteristicReadValueOutcome(query_result.outcome); |
| 658 RecordCharacteristicReadValueOutcome(UMAGATTOperationOutcome::NO_SERVICE); | |
| 659 Send(new BluetoothMsg_ReadCharacteristicValueError( | 651 Send(new BluetoothMsg_ReadCharacteristicValueError( |
| 660 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists)); | 652 thread_id, request_id, query_result.GetWebError())); |
| 661 return; | 653 return; |
| 662 } | 654 } |
| 663 | 655 |
| 664 BluetoothGattCharacteristic* characteristic = | 656 query_result.characteristic->ReadRemoteCharacteristic( |
| 665 service->GetCharacteristic(characteristic_instance_id); | |
| 666 if (characteristic == nullptr) { | |
| 667 RecordCharacteristicReadValueOutcome( | |
| 668 UMAGATTOperationOutcome::NO_CHARACTERISTIC); | |
| 669 Send(new BluetoothMsg_ReadCharacteristicValueError( | |
| 670 thread_id, request_id, | |
| 671 WebBluetoothError::CharacteristicNoLongerExists)); | |
| 672 return; | |
| 673 } | |
| 674 | |
| 675 characteristic->ReadRemoteCharacteristic( | |
| 676 base::Bind(&BluetoothDispatcherHost::OnCharacteristicValueRead, | 657 base::Bind(&BluetoothDispatcherHost::OnCharacteristicValueRead, |
| 677 weak_ptr_on_ui_thread_, thread_id, request_id), | 658 weak_ptr_on_ui_thread_, thread_id, request_id), |
| 678 base::Bind(&BluetoothDispatcherHost::OnCharacteristicReadValueError, | 659 base::Bind(&BluetoothDispatcherHost::OnCharacteristicReadValueError, |
| 679 weak_ptr_on_ui_thread_, thread_id, request_id)); | 660 weak_ptr_on_ui_thread_, thread_id, request_id)); |
| 680 } | 661 } |
| 681 | 662 |
| 682 void BluetoothDispatcherHost::OnWriteValue( | 663 void BluetoothDispatcherHost::OnWriteValue( |
| 683 int thread_id, | 664 int thread_id, |
| 684 int request_id, | 665 int request_id, |
| 685 const std::string& characteristic_instance_id, | 666 const std::string& characteristic_instance_id, |
| 686 const std::vector<uint8_t>& value) { | 667 const std::vector<uint8_t>& value) { |
| 687 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 668 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 688 RecordWebBluetoothFunctionCall( | 669 RecordWebBluetoothFunctionCall( |
| 689 UMAWebBluetoothFunction::CHARACTERISTIC_WRITE_VALUE); | 670 UMAWebBluetoothFunction::CHARACTERISTIC_WRITE_VALUE); |
| 690 | 671 |
| 691 // Length check per step 3 of writeValue algorithm: | 672 // Length check per step 3 of writeValue algorithm: |
| 692 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattcharac
teristic-writevalue | 673 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattcharac
teristic-writevalue |
| 693 // We perform the length check on the renderer side. So if we | 674 // We perform the length check on the renderer side. So if we |
| 694 // get a value with length > 512, we can assume it's a hostile | 675 // get a value with length > 512, we can assume it's a hostile |
| 695 // renderer and kill it. | 676 // renderer and kill it. |
| 696 if (value.size() > 512) { | 677 if (value.size() > 512) { |
| 697 bad_message::ReceivedBadMessage( | 678 bad_message::ReceivedBadMessage( |
| 698 this, bad_message::BDH_INVALID_WRITE_VALUE_LENGTH); | 679 this, bad_message::BDH_INVALID_WRITE_VALUE_LENGTH); |
| 699 return; | 680 return; |
| 700 } | 681 } |
| 701 | 682 |
| 702 auto characteristic_iter = | 683 CacheQueryResult query_result = CacheQueryResult(); |
| 703 characteristic_to_service_.find(characteristic_instance_id); | 684 QueryCacheForCharacteristic(characteristic_instance_id, query_result); |
| 704 | 685 |
| 705 // Kill the renderer, see "ID Not In Map Note" above. | 686 if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
| 706 if (characteristic_iter == characteristic_to_service_.end()) { | |
| 707 bad_message::ReceivedBadMessage(this, | |
| 708 bad_message::BDH_INVALID_CHARACTERISTIC_ID); | |
| 709 return; | |
| 710 } | |
| 711 const std::string& service_instance_id = characteristic_iter->second; | |
| 712 | |
| 713 auto device_iter = service_to_device_.find(service_instance_id); | |
| 714 | |
| 715 CHECK(device_iter != service_to_device_.end()); | |
| 716 | |
| 717 device::BluetoothDevice* device = | |
| 718 adapter_->GetDevice(device_iter->second /* device_instance_id */); | |
| 719 if (device == nullptr) { // See "NETWORK_ERROR Note" above. | |
| 720 RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::NO_DEVICE); | |
| 721 Send(new BluetoothMsg_WriteCharacteristicValueError( | |
| 722 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); | |
| 723 return; | 687 return; |
| 724 } | 688 } |
| 725 | 689 |
| 726 BluetoothGattService* service = device->GetGattService(service_instance_id); | 690 if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| 727 if (service == nullptr) { | 691 RecordCharacteristicWriteValueOutcome(query_result.outcome); |
| 728 RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::NO_SERVICE); | |
| 729 Send(new BluetoothMsg_WriteCharacteristicValueError( | 692 Send(new BluetoothMsg_WriteCharacteristicValueError( |
| 730 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists)); | 693 thread_id, request_id, query_result.GetWebError())); |
| 731 return; | 694 return; |
| 732 } | 695 } |
| 733 | 696 |
| 734 BluetoothGattCharacteristic* characteristic = | 697 query_result.characteristic->WriteRemoteCharacteristic( |
| 735 service->GetCharacteristic(characteristic_instance_id); | |
| 736 if (characteristic == nullptr) { | |
| 737 RecordCharacteristicWriteValueOutcome( | |
| 738 UMAGATTOperationOutcome::NO_CHARACTERISTIC); | |
| 739 Send(new BluetoothMsg_WriteCharacteristicValueError( | |
| 740 thread_id, request_id, | |
| 741 WebBluetoothError::CharacteristicNoLongerExists)); | |
| 742 return; | |
| 743 } | |
| 744 characteristic->WriteRemoteCharacteristic( | |
| 745 value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess, | 698 value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess, |
| 746 weak_ptr_on_ui_thread_, thread_id, request_id), | 699 weak_ptr_on_ui_thread_, thread_id, request_id), |
| 747 base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed, | 700 base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed, |
| 748 weak_ptr_on_ui_thread_, thread_id, request_id)); | 701 weak_ptr_on_ui_thread_, thread_id, request_id)); |
| 749 } | 702 } |
| 750 | 703 |
| 751 void BluetoothDispatcherHost::OnStartNotifications( | 704 void BluetoothDispatcherHost::OnStartNotifications( |
| 752 int thread_id, | 705 int thread_id, |
| 753 int request_id, | 706 int request_id, |
| 754 const std::string& characteristic_instance_id) { | 707 const std::string& characteristic_instance_id) { |
| 755 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 708 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 756 RecordWebBluetoothFunctionCall( | 709 RecordWebBluetoothFunctionCall( |
| 757 UMAWebBluetoothFunction::CHARACTERISTIC_START_NOTIFICATIONS); | 710 UMAWebBluetoothFunction::CHARACTERISTIC_START_NOTIFICATIONS); |
| 758 | 711 |
| 759 // BluetoothDispatcher will never send a request for a characteristic | 712 // BluetoothDispatcher will never send a request for a characteristic |
| 760 // already subscribed to notifications. | 713 // already subscribed to notifications. |
| 761 if (characteristic_id_to_notify_session_.find(characteristic_instance_id) != | 714 if (characteristic_id_to_notify_session_.find(characteristic_instance_id) != |
| 762 characteristic_id_to_notify_session_.end()) { | 715 characteristic_id_to_notify_session_.end()) { |
| 763 bad_message::ReceivedBadMessage( | 716 bad_message::ReceivedBadMessage( |
| 764 this, bad_message::BDH_CHARACTERISTIC_ALREADY_SUBSCRIBED); | 717 this, bad_message::BDH_CHARACTERISTIC_ALREADY_SUBSCRIBED); |
| 765 return; | 718 return; |
| 766 } | 719 } |
| 767 | 720 |
| 768 // TODO(ortuno): Check if notify/indicate bit is set. | 721 // TODO(ortuno): Check if notify/indicate bit is set. |
| 769 // http://crbug.com/538869 | 722 // http://crbug.com/538869 |
| 770 | 723 |
| 771 auto characteristic_iter = | 724 CacheQueryResult query_result = CacheQueryResult(); |
| 772 characteristic_to_service_.find(characteristic_instance_id); | 725 QueryCacheForCharacteristic(characteristic_instance_id, query_result); |
| 773 | 726 |
| 774 // Kill the renderer, see "ID Not In Map Note" above. | 727 if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
| 775 if (characteristic_iter == characteristic_to_service_.end()) { | |
| 776 bad_message::ReceivedBadMessage(this, | |
| 777 bad_message::BDH_INVALID_CHARACTERISTIC_ID); | |
| 778 return; | 728 return; |
| 779 } | 729 } |
| 780 | 730 |
| 781 const std::string& service_instance_id = characteristic_iter->second; | 731 if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| 782 auto device_iter = service_to_device_.find(service_instance_id); | 732 RecordStartNotificationsOutcome(query_result.outcome); |
| 783 CHECK(device_iter != service_to_device_.end()); | 733 Send(new BluetoothMsg_StartNotificationsError(thread_id, request_id, |
| 784 | 734 query_result.GetWebError())); |
| 785 device::BluetoothDevice* device = | |
| 786 adapter_->GetDevice(device_iter->second /* device_instance_id */); | |
| 787 if (device == nullptr) { // See "NETWORK_ERROR Note" above. | |
| 788 RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_DEVICE); | |
| 789 Send(new BluetoothMsg_StartNotificationsError( | |
| 790 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); | |
| 791 return; | 735 return; |
| 792 } | 736 } |
| 793 | 737 |
| 794 BluetoothGattService* service = device->GetGattService(service_instance_id); | 738 query_result.characteristic->StartNotifySession( |
| 795 if (service == nullptr) { | |
| 796 RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_SERVICE); | |
| 797 Send(new BluetoothMsg_StartNotificationsError( | |
| 798 thread_id, request_id, WebBluetoothError::ServiceNoLongerExists)); | |
| 799 return; | |
| 800 } | |
| 801 | |
| 802 BluetoothGattCharacteristic* characteristic = | |
| 803 service->GetCharacteristic(characteristic_instance_id); | |
| 804 if (characteristic == nullptr) { | |
| 805 RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_CHARACTERISTIC); | |
| 806 Send(new BluetoothMsg_StartNotificationsError( | |
| 807 thread_id, request_id, | |
| 808 WebBluetoothError::CharacteristicNoLongerExists)); | |
| 809 return; | |
| 810 } | |
| 811 | |
| 812 characteristic->StartNotifySession( | |
| 813 base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionSuccess, | 739 base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionSuccess, |
| 814 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), | 740 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), |
| 815 base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionFailed, | 741 base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionFailed, |
| 816 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); | 742 weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); |
| 817 } | 743 } |
| 818 | 744 |
| 819 void BluetoothDispatcherHost::OnStopNotifications( | 745 void BluetoothDispatcherHost::OnStopNotifications( |
| 820 int thread_id, | 746 int thread_id, |
| 821 int request_id, | 747 int request_id, |
| 822 const std::string& characteristic_instance_id) { | 748 const std::string& characteristic_instance_id) { |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1019 TranslateConnectError(error_code))); | 945 TranslateConnectError(error_code))); |
| 1020 } | 946 } |
| 1021 | 947 |
| 1022 void BluetoothDispatcherHost::OnServicesDiscovered( | 948 void BluetoothDispatcherHost::OnServicesDiscovered( |
| 1023 int thread_id, | 949 int thread_id, |
| 1024 int request_id, | 950 int request_id, |
| 1025 const std::string& device_instance_id, | 951 const std::string& device_instance_id, |
| 1026 const std::string& service_uuid) { | 952 const std::string& service_uuid) { |
| 1027 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 953 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1028 | 954 |
| 1029 device::BluetoothDevice* device = adapter_->GetDevice(device_instance_id); | 955 CacheQueryResult query_result = CacheQueryResult(); |
| 1030 if (device == nullptr) { // See "NETWORK_ERROR Note" above. | 956 QueryCacheForDevice(device_instance_id, query_result); |
| 1031 RecordGetPrimaryServiceOutcome(UMAGetPrimaryServiceOutcome::NO_DEVICE); | 957 |
| 1032 Send(new BluetoothMsg_GetPrimaryServiceError( | 958 if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| 1033 thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); | 959 RecordGetPrimaryServiceOutcome(query_result.outcome); |
| 960 Send(new BluetoothMsg_GetPrimaryServiceError(thread_id, request_id, |
| 961 query_result.GetWebError())); |
| 1034 return; | 962 return; |
| 1035 } | 963 } |
| 1036 | 964 |
| 1037 VLOG(1) << "Looking for service: " << service_uuid; | 965 VLOG(1) << "Looking for service: " << service_uuid; |
| 1038 for (BluetoothGattService* service : device->GetGattServices()) { | 966 for (BluetoothGattService* service : query_result.device->GetGattServices()) { |
| 1039 VLOG(1) << "Service in cache: " << service->GetUUID().canonical_value(); | 967 VLOG(1) << "Service in cache: " << service->GetUUID().canonical_value(); |
| 1040 if (service->GetUUID().canonical_value() == service_uuid) { | 968 if (service->GetUUID().canonical_value() == service_uuid) { |
| 1041 // TODO(ortuno): Use generated instance ID instead. | 969 // TODO(ortuno): Use generated instance ID instead. |
| 1042 // https://crbug.com/495379 | 970 // https://crbug.com/495379 |
| 1043 const std::string& service_identifier = service->GetIdentifier(); | 971 const std::string& service_identifier = service->GetIdentifier(); |
| 1044 auto insert_result = service_to_device_.insert( | 972 auto insert_result = service_to_device_.insert( |
| 1045 make_pair(service_identifier, device_instance_id)); | 973 make_pair(service_identifier, device_instance_id)); |
| 1046 | 974 |
| 1047 // If a value is already in map, DCHECK it's valid. | 975 // If a value is already in map, DCHECK it's valid. |
| 1048 if (!insert_result.second) | 976 if (!insert_result.second) |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 } | 1050 } |
| 1123 | 1051 |
| 1124 void BluetoothDispatcherHost::OnStopNotifySession( | 1052 void BluetoothDispatcherHost::OnStopNotifySession( |
| 1125 int thread_id, | 1053 int thread_id, |
| 1126 int request_id, | 1054 int request_id, |
| 1127 const std::string& characteristic_instance_id) { | 1055 const std::string& characteristic_instance_id) { |
| 1128 characteristic_id_to_notify_session_.erase(characteristic_instance_id); | 1056 characteristic_id_to_notify_session_.erase(characteristic_instance_id); |
| 1129 Send(new BluetoothMsg_StopNotificationsSuccess(thread_id, request_id)); | 1057 Send(new BluetoothMsg_StopNotificationsSuccess(thread_id, request_id)); |
| 1130 } | 1058 } |
| 1131 | 1059 |
| 1060 void BluetoothDispatcherHost::QueryCacheForDevice( |
| 1061 const std::string& device_instance_id, |
| 1062 CacheQueryResult& result) { |
| 1063 result.device = adapter_->GetDevice(device_instance_id); |
| 1064 // When a device can't be found in the BluetoothAdapter, that generally |
| 1065 // indicates that it's gone out of range. We reject with a NetworkError in |
| 1066 // that case. |
| 1067 // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-con
nectgatt |
| 1068 if (result.device == nullptr) { |
| 1069 result.outcome = CacheQueryOutcome::NO_DEVICE; |
| 1070 } |
| 1071 } |
| 1072 |
| 1073 void BluetoothDispatcherHost::QueryCacheForService( |
| 1074 const std::string& service_instance_id, |
| 1075 CacheQueryResult& result) { |
| 1076 auto device_iter = service_to_device_.find(service_instance_id); |
| 1077 |
| 1078 // Kill the renderer, see "ID Not In Map Note" above. |
| 1079 if (device_iter == service_to_device_.end()) { |
| 1080 bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_SERVICE_ID); |
| 1081 result.outcome = CacheQueryOutcome::BAD_RENDERER; |
| 1082 return; |
| 1083 } |
| 1084 |
| 1085 // TODO(ortuno): Check if domain has access to device. |
| 1086 // https://crbug.com/493459 |
| 1087 |
| 1088 QueryCacheForDevice(device_iter->second, result); |
| 1089 |
| 1090 if (result.outcome != CacheQueryOutcome::SUCCESS) { |
| 1091 return; |
| 1092 } |
| 1093 |
| 1094 result.service = result.device->GetGattService(service_instance_id); |
| 1095 if (result.service == nullptr) { |
| 1096 result.outcome = CacheQueryOutcome::NO_SERVICE; |
| 1097 } |
| 1098 } |
| 1099 |
| 1100 void BluetoothDispatcherHost::QueryCacheForCharacteristic( |
| 1101 const std::string& characteristic_instance_id, |
| 1102 CacheQueryResult& result) { |
| 1103 auto characteristic_iter = |
| 1104 characteristic_to_service_.find(characteristic_instance_id); |
| 1105 |
| 1106 // Kill the renderer, see "ID Not In Map Note" above. |
| 1107 if (characteristic_iter == characteristic_to_service_.end()) { |
| 1108 bad_message::ReceivedBadMessage(this, |
| 1109 bad_message::BDH_INVALID_CHARACTERISTIC_ID); |
| 1110 result.outcome = CacheQueryOutcome::BAD_RENDERER; |
| 1111 return; |
| 1112 } |
| 1113 |
| 1114 QueryCacheForService(characteristic_iter->second, result); |
| 1115 if (result.outcome != CacheQueryOutcome::SUCCESS) { |
| 1116 return; |
| 1117 } |
| 1118 |
| 1119 result.characteristic = |
| 1120 result.service->GetCharacteristic(characteristic_instance_id); |
| 1121 |
| 1122 if (result.characteristic == nullptr) { |
| 1123 result.outcome = CacheQueryOutcome::NO_CHARACTERISTIC; |
| 1124 } |
| 1125 } |
| 1126 |
| 1132 void BluetoothDispatcherHost::ShowBluetoothOverviewLink() { | 1127 void BluetoothDispatcherHost::ShowBluetoothOverviewLink() { |
| 1133 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1128 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1134 NOTIMPLEMENTED(); | 1129 NOTIMPLEMENTED(); |
| 1135 } | 1130 } |
| 1136 | 1131 |
| 1137 void BluetoothDispatcherHost::ShowBluetoothPairingLink() { | 1132 void BluetoothDispatcherHost::ShowBluetoothPairingLink() { |
| 1138 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1133 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1139 NOTIMPLEMENTED(); | 1134 NOTIMPLEMENTED(); |
| 1140 } | 1135 } |
| 1141 | 1136 |
| 1142 void BluetoothDispatcherHost::ShowBluetoothAdapterOffLink() { | 1137 void BluetoothDispatcherHost::ShowBluetoothAdapterOffLink() { |
| 1143 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 1138 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 1144 NOTIMPLEMENTED(); | 1139 NOTIMPLEMENTED(); |
| 1145 } | 1140 } |
| 1146 | 1141 |
| 1147 } // namespace content | 1142 } // namespace content |
| OLD | NEW |