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