| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 // ID Not In Map Note: | 5 // ID Not In Map Note: |
| 6 // A service, characteristic, or descriptor ID not in the corresponding | 6 // A service, characteristic, or descriptor ID not in the corresponding |
| 7 // BluetoothDispatcherHost map [service_id_to_device_address_, | 7 // BluetoothDispatcherHost map [service_id_to_device_address_, |
| 8 // characteristic_id_to_service_id_, descriptor_to_characteristic_] implies a | 8 // characteristic_id_to_service_id_, descriptor_to_characteristic_] implies a |
| 9 // hostile renderer because a renderer obtains the corresponding ID from this | 9 // hostile renderer because a renderer obtains the corresponding ID from this |
| 10 // class and it will be added to the map at that time. | 10 // class and it will be added to the map at that time. |
| 11 | 11 |
| 12 #include "content/browser/bluetooth/web_bluetooth_service_impl.h" | 12 #include "content/browser/bluetooth/web_bluetooth_service_impl.h" |
| 13 | 13 |
| 14 #include <algorithm> | 14 #include <algorithm> |
| 15 | 15 |
| 16 #include "base/thread_task_runner_handle.h" | 16 #include "base/thread_task_runner_handle.h" |
| 17 #include "content/browser/bluetooth/bluetooth_blacklist.h" | 17 #include "content/browser/bluetooth/bluetooth_blacklist.h" |
| 18 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" | 18 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
| 19 #include "content/browser/bluetooth/frame_connected_bluetooth_devices.h" |
| 19 #include "content/browser/renderer_host/render_process_host_impl.h" | 20 #include "content/browser/renderer_host/render_process_host_impl.h" |
| 20 #include "content/public/browser/navigation_handle.h" | 21 #include "content/public/browser/navigation_handle.h" |
| 21 #include "content/public/browser/render_frame_host.h" | 22 #include "content/public/browser/render_frame_host.h" |
| 22 #include "content/public/browser/web_contents.h" | 23 #include "content/public/browser/web_contents.h" |
| 23 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h" | 24 #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h" |
| 24 | 25 |
| 25 namespace content { | 26 namespace content { |
| 26 | 27 |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 30 blink::mojom::WebBluetoothError TranslateConnectErrorAndRecord( |
| 31 device::BluetoothDevice::ConnectErrorCode error_code) { |
| 32 switch (error_code) { |
| 33 case device::BluetoothDevice::ERROR_UNKNOWN: |
| 34 RecordConnectGATTOutcome(UMAConnectGATTOutcome::UNKNOWN); |
| 35 return blink::mojom::WebBluetoothError::CONNECT_UNKNOWN_ERROR; |
| 36 case device::BluetoothDevice::ERROR_INPROGRESS: |
| 37 RecordConnectGATTOutcome(UMAConnectGATTOutcome::IN_PROGRESS); |
| 38 return blink::mojom::WebBluetoothError::CONNECT_ALREADY_IN_PROGRESS; |
| 39 case device::BluetoothDevice::ERROR_FAILED: |
| 40 RecordConnectGATTOutcome(UMAConnectGATTOutcome::FAILED); |
| 41 return blink::mojom::WebBluetoothError::CONNECT_UNKNOWN_FAILURE; |
| 42 case device::BluetoothDevice::ERROR_AUTH_FAILED: |
| 43 RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_FAILED); |
| 44 return blink::mojom::WebBluetoothError::CONNECT_AUTH_FAILED; |
| 45 case device::BluetoothDevice::ERROR_AUTH_CANCELED: |
| 46 RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_CANCELED); |
| 47 return blink::mojom::WebBluetoothError::CONNECT_AUTH_CANCELED; |
| 48 case device::BluetoothDevice::ERROR_AUTH_REJECTED: |
| 49 RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_REJECTED); |
| 50 return blink::mojom::WebBluetoothError::CONNECT_AUTH_REJECTED; |
| 51 case device::BluetoothDevice::ERROR_AUTH_TIMEOUT: |
| 52 RecordConnectGATTOutcome(UMAConnectGATTOutcome::AUTH_TIMEOUT); |
| 53 return blink::mojom::WebBluetoothError::CONNECT_AUTH_TIMEOUT; |
| 54 case device::BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: |
| 55 RecordConnectGATTOutcome(UMAConnectGATTOutcome::UNSUPPORTED_DEVICE); |
| 56 return blink::mojom::WebBluetoothError::CONNECT_UNSUPPORTED_DEVICE; |
| 57 case device::BluetoothDevice::ERROR_ATTRIBUTE_LENGTH_INVALID: |
| 58 RecordConnectGATTOutcome(UMAConnectGATTOutcome::ATTRIBUTE_LENGTH_INVALID); |
| 59 return blink::mojom::WebBluetoothError::CONNECT_ATTRIBUTE_LENGTH_INVALID; |
| 60 case device::BluetoothDevice::ERROR_CONNECTION_CONGESTED: |
| 61 RecordConnectGATTOutcome(UMAConnectGATTOutcome::CONNECTION_CONGESTED); |
| 62 return blink::mojom::WebBluetoothError::CONNECT_CONNECTION_CONGESTED; |
| 63 case device::BluetoothDevice::ERROR_INSUFFICIENT_ENCRYPTION: |
| 64 RecordConnectGATTOutcome(UMAConnectGATTOutcome::INSUFFICIENT_ENCRYPTION); |
| 65 return blink::mojom::WebBluetoothError::CONNECT_INSUFFICIENT_ENCRYPTION; |
| 66 case device::BluetoothDevice::ERROR_OFFSET_INVALID: |
| 67 RecordConnectGATTOutcome(UMAConnectGATTOutcome::OFFSET_INVALID); |
| 68 return blink::mojom::WebBluetoothError::CONNECT_OFFSET_INVALID; |
| 69 case device::BluetoothDevice::ERROR_READ_NOT_PERMITTED: |
| 70 RecordConnectGATTOutcome(UMAConnectGATTOutcome::READ_NOT_PERMITTED); |
| 71 return blink::mojom::WebBluetoothError::CONNECT_READ_NOT_PERMITTED; |
| 72 case device::BluetoothDevice::ERROR_REQUEST_NOT_SUPPORTED: |
| 73 RecordConnectGATTOutcome(UMAConnectGATTOutcome::REQUEST_NOT_SUPPORTED); |
| 74 return blink::mojom::WebBluetoothError::CONNECT_REQUEST_NOT_SUPPORTED; |
| 75 case device::BluetoothDevice::ERROR_WRITE_NOT_PERMITTED: |
| 76 RecordConnectGATTOutcome(UMAConnectGATTOutcome::WRITE_NOT_PERMITTED); |
| 77 return blink::mojom::WebBluetoothError::CONNECT_WRITE_NOT_PERMITTED; |
| 78 case device::BluetoothDevice::NUM_CONNECT_ERROR_CODES: |
| 79 NOTREACHED(); |
| 80 return blink::mojom::WebBluetoothError::UNTRANSLATED_CONNECT_ERROR_CODE; |
| 81 } |
| 82 NOTREACHED(); |
| 83 return blink::mojom::WebBluetoothError::UNTRANSLATED_CONNECT_ERROR_CODE; |
| 84 } |
| 85 |
| 29 blink::mojom::WebBluetoothError TranslateGATTErrorAndRecord( | 86 blink::mojom::WebBluetoothError TranslateGATTErrorAndRecord( |
| 30 device::BluetoothRemoteGattService::GattErrorCode error_code, | 87 device::BluetoothRemoteGattService::GattErrorCode error_code, |
| 31 UMAGATTOperation operation) { | 88 UMAGATTOperation operation) { |
| 32 switch (error_code) { | 89 switch (error_code) { |
| 33 case device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN: | 90 case device::BluetoothRemoteGattService::GATT_ERROR_UNKNOWN: |
| 34 RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::UNKNOWN); | 91 RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::UNKNOWN); |
| 35 return blink::mojom::WebBluetoothError::GATT_UNKNOWN_ERROR; | 92 return blink::mojom::WebBluetoothError::GATT_UNKNOWN_ERROR; |
| 36 case device::BluetoothRemoteGattService::GATT_ERROR_FAILED: | 93 case device::BluetoothRemoteGattService::GATT_ERROR_FAILED: |
| 37 RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::FAILED); | 94 RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::FAILED); |
| 38 return blink::mojom::WebBluetoothError::GATT_UNKNOWN_FAILURE; | 95 return blink::mojom::WebBluetoothError::GATT_UNKNOWN_FAILURE; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 } | 157 } |
| 101 return services; | 158 return services; |
| 102 } | 159 } |
| 103 | 160 |
| 104 } // namespace | 161 } // namespace |
| 105 | 162 |
| 106 WebBluetoothServiceImpl::WebBluetoothServiceImpl( | 163 WebBluetoothServiceImpl::WebBluetoothServiceImpl( |
| 107 RenderFrameHost* render_frame_host, | 164 RenderFrameHost* render_frame_host, |
| 108 blink::mojom::WebBluetoothServiceRequest request) | 165 blink::mojom::WebBluetoothServiceRequest request) |
| 109 : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)), | 166 : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)), |
| 167 connected_devices_(new FrameConnectedBluetoothDevices(render_frame_host)), |
| 110 render_frame_host_(render_frame_host), | 168 render_frame_host_(render_frame_host), |
| 111 binding_(this, std::move(request)), | 169 binding_(this, std::move(request)), |
| 112 weak_ptr_factory_(this) { | 170 weak_ptr_factory_(this) { |
| 113 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 171 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 114 CHECK(web_contents()); | 172 CHECK(web_contents()); |
| 115 | 173 |
| 116 GetBluetoothDispatcherHost()->AddAdapterObserver(this); | 174 GetBluetoothDispatcherHost()->AddAdapterObserver(this); |
| 117 } | 175 } |
| 118 | 176 |
| 119 WebBluetoothServiceImpl::~WebBluetoothServiceImpl() { | 177 WebBluetoothServiceImpl::~WebBluetoothServiceImpl() { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 136 } | 194 } |
| 137 | 195 |
| 138 void WebBluetoothServiceImpl::AdapterPresentChanged( | 196 void WebBluetoothServiceImpl::AdapterPresentChanged( |
| 139 device::BluetoothAdapter* adapter, | 197 device::BluetoothAdapter* adapter, |
| 140 bool present) { | 198 bool present) { |
| 141 if (!present) { | 199 if (!present) { |
| 142 ClearState(); | 200 ClearState(); |
| 143 } | 201 } |
| 144 } | 202 } |
| 145 | 203 |
| 204 void WebBluetoothServiceImpl::DeviceChanged(device::BluetoothAdapter* adapter, |
| 205 device::BluetoothDevice* device) { |
| 206 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 207 if (!device->IsGattConnected() || !device->IsConnected()) { |
| 208 std::string device_id = |
| 209 connected_devices_->CloseConnectionToDeviceWithAddress( |
| 210 device->GetAddress()); |
| 211 if (!device_id.empty()) { |
| 212 // TODO(ortuno): Send event to client. |
| 213 // http://crbug.com/581855 |
| 214 } |
| 215 } |
| 216 } |
| 217 |
| 146 void WebBluetoothServiceImpl::GattServicesDiscovered( | 218 void WebBluetoothServiceImpl::GattServicesDiscovered( |
| 147 device::BluetoothAdapter* adapter, | 219 device::BluetoothAdapter* adapter, |
| 148 device::BluetoothDevice* device) { | 220 device::BluetoothDevice* device) { |
| 149 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 221 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 150 const std::string& device_address = device->GetAddress(); | 222 const std::string& device_address = device->GetAddress(); |
| 151 VLOG(1) << "Services discovered for device: " << device_address; | 223 VLOG(1) << "Services discovered for device: " << device_address; |
| 152 | 224 |
| 153 auto iter = pending_primary_services_requests_.find(device_address); | 225 auto iter = pending_primary_services_requests_.find(device_address); |
| 154 if (iter == pending_primary_services_requests_.end()) { | 226 if (iter == pending_primary_services_requests_.end()) { |
| 155 return; | 227 return; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 characteristic_instance_id, mojo::Array<uint8_t>(std::move(value))); | 268 characteristic_instance_id, mojo::Array<uint8_t>(std::move(value))); |
| 197 } | 269 } |
| 198 } | 270 } |
| 199 | 271 |
| 200 void WebBluetoothServiceImpl::SetClient( | 272 void WebBluetoothServiceImpl::SetClient( |
| 201 blink::mojom::WebBluetoothServiceClientAssociatedPtrInfo client) { | 273 blink::mojom::WebBluetoothServiceClientAssociatedPtrInfo client) { |
| 202 DCHECK(!client_.get()); | 274 DCHECK(!client_.get()); |
| 203 client_.Bind(std::move(client)); | 275 client_.Bind(std::move(client)); |
| 204 } | 276 } |
| 205 | 277 |
| 278 void WebBluetoothServiceImpl::RemoteServerConnect( |
| 279 const mojo::String& device_id, |
| 280 const RemoteServerConnectCallback& callback) { |
| 281 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 282 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT); |
| 283 |
| 284 const CacheQueryResult query_result = |
| 285 GetBluetoothDispatcherHost()->QueryCacheForDevice(GetOrigin(), device_id); |
| 286 |
| 287 if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| 288 RecordConnectGATTOutcome(query_result.outcome); |
| 289 callback.Run(query_result.GetWebError()); |
| 290 return; |
| 291 } |
| 292 |
| 293 if (connected_devices_->IsConnectedToDeviceWithId(device_id)) { |
| 294 VLOG(1) << "Already connected."; |
| 295 callback.Run(blink::mojom::WebBluetoothError::SUCCESS); |
| 296 return; |
| 297 } |
| 298 |
| 299 // It's possible for WebBluetoothServiceImpl to issue two successive |
| 300 // connection requests for which it would get two successive responses |
| 301 // and consequently try to insert two BluetoothGattConnections for the |
| 302 // same device. WebBluetoothServiceImpl should reject or queue connection |
| 303 // requests if there is a pending connection already, but the platform |
| 304 // abstraction doesn't currently support checking for pending connections. |
| 305 // TODO(ortuno): CHECK that this never happens once the platform |
| 306 // abstraction allows to check for pending connections. |
| 307 // http://crbug.com/583544 |
| 308 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 309 query_result.device->CreateGattConnection( |
| 310 base::Bind(&WebBluetoothServiceImpl::OnCreateGATTConnectionSuccess, |
| 311 weak_ptr_factory_.GetWeakPtr(), device_id, start_time, |
| 312 callback), |
| 313 base::Bind(&WebBluetoothServiceImpl::OnCreateGATTConnectionFailed, |
| 314 weak_ptr_factory_.GetWeakPtr(), device_id, start_time, |
| 315 callback)); |
| 316 } |
| 317 |
| 318 void WebBluetoothServiceImpl::RemoteServerDisconnect( |
| 319 const mojo::String& device_id) { |
| 320 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 321 RecordWebBluetoothFunctionCall( |
| 322 UMAWebBluetoothFunction::REMOTE_GATT_SERVER_DISCONNECT); |
| 323 |
| 324 if (connected_devices_->IsConnectedToDeviceWithId(device_id)) { |
| 325 VLOG(1) << "Disconnecting device: " << device_id; |
| 326 connected_devices_->CloseConnectionToDeviceWithId(device_id); |
| 327 } |
| 328 } |
| 329 |
| 206 void WebBluetoothServiceImpl::RemoteServerGetPrimaryService( | 330 void WebBluetoothServiceImpl::RemoteServerGetPrimaryService( |
| 207 const mojo::String& device_id, | 331 const mojo::String& device_id, |
| 208 const mojo::String& service_uuid, | 332 const mojo::String& service_uuid, |
| 209 const RemoteServerGetPrimaryServiceCallback& callback) { | 333 const RemoteServerGetPrimaryServiceCallback& callback) { |
| 210 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 334 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 211 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_PRIMARY_SERVICE); | 335 RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_PRIMARY_SERVICE); |
| 212 RecordGetPrimaryServiceService(device::BluetoothUUID(service_uuid)); | 336 RecordGetPrimaryServiceService(device::BluetoothUUID(service_uuid)); |
| 213 | 337 |
| 214 if (!GetBluetoothDispatcherHost() | 338 if (!GetBluetoothDispatcherHost() |
| 215 ->allowed_devices_map_.IsOriginAllowedToAccessService( | 339 ->allowed_devices_map_.IsOriginAllowedToAccessService( |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 | 643 |
| 520 RecordGetPrimaryServiceOutcome(UMAGetPrimaryServiceOutcome::SUCCESS); | 644 RecordGetPrimaryServiceOutcome(UMAGetPrimaryServiceOutcome::SUCCESS); |
| 521 blink::mojom::WebBluetoothRemoteGATTServicePtr service_ptr = | 645 blink::mojom::WebBluetoothRemoteGATTServicePtr service_ptr = |
| 522 blink::mojom::WebBluetoothRemoteGATTService::New(); | 646 blink::mojom::WebBluetoothRemoteGATTService::New(); |
| 523 service_ptr->instance_id = services[0]->GetIdentifier(); | 647 service_ptr->instance_id = services[0]->GetIdentifier(); |
| 524 service_ptr->uuid = services[0]->GetUUID().canonical_value(); | 648 service_ptr->uuid = services[0]->GetUUID().canonical_value(); |
| 525 callback.Run(blink::mojom::WebBluetoothError::SUCCESS, | 649 callback.Run(blink::mojom::WebBluetoothError::SUCCESS, |
| 526 std::move(service_ptr)); | 650 std::move(service_ptr)); |
| 527 } | 651 } |
| 528 | 652 |
| 653 void WebBluetoothServiceImpl::OnCreateGATTConnectionSuccess( |
| 654 const std::string& device_id, |
| 655 base::TimeTicks start_time, |
| 656 const RemoteServerConnectCallback& callback, |
| 657 std::unique_ptr<device::BluetoothGattConnection> connection) { |
| 658 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 659 RecordConnectGATTTimeSuccess(base::TimeTicks::Now() - start_time); |
| 660 RecordConnectGATTOutcome(UMAConnectGATTOutcome::SUCCESS); |
| 661 |
| 662 connected_devices_->Insert(device_id, std::move(connection)); |
| 663 callback.Run(blink::mojom::WebBluetoothError::SUCCESS); |
| 664 } |
| 665 |
| 666 void WebBluetoothServiceImpl::OnCreateGATTConnectionFailed( |
| 667 const std::string& device_id, |
| 668 base::TimeTicks start_time, |
| 669 const RemoteServerConnectCallback& callback, |
| 670 device::BluetoothDevice::ConnectErrorCode error_code) { |
| 671 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 672 RecordConnectGATTTimeFailed(base::TimeTicks::Now() - start_time); |
| 673 callback.Run(TranslateConnectErrorAndRecord(error_code)); |
| 674 } |
| 675 |
| 529 void WebBluetoothServiceImpl::OnReadValueSuccess( | 676 void WebBluetoothServiceImpl::OnReadValueSuccess( |
| 530 const RemoteCharacteristicReadValueCallback& callback, | 677 const RemoteCharacteristicReadValueCallback& callback, |
| 531 const std::vector<uint8_t>& value) { | 678 const std::vector<uint8_t>& value) { |
| 532 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 679 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 533 RecordCharacteristicReadValueOutcome(UMAGATTOperationOutcome::SUCCESS); | 680 RecordCharacteristicReadValueOutcome(UMAGATTOperationOutcome::SUCCESS); |
| 534 callback.Run(blink::mojom::WebBluetoothError::SUCCESS, | 681 callback.Run(blink::mojom::WebBluetoothError::SUCCESS, |
| 535 mojo::Array<uint8_t>::From(value)); | 682 mojo::Array<uint8_t>::From(value)); |
| 536 } | 683 } |
| 537 | 684 |
| 538 void WebBluetoothServiceImpl::OnReadValueFailed( | 685 void WebBluetoothServiceImpl::OnReadValueFailed( |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 | 825 |
| 679 url::Origin WebBluetoothServiceImpl::GetOrigin() { | 826 url::Origin WebBluetoothServiceImpl::GetOrigin() { |
| 680 return render_frame_host_->GetLastCommittedOrigin(); | 827 return render_frame_host_->GetLastCommittedOrigin(); |
| 681 } | 828 } |
| 682 | 829 |
| 683 void WebBluetoothServiceImpl::ClearState() { | 830 void WebBluetoothServiceImpl::ClearState() { |
| 684 characteristic_id_to_notify_session_.clear(); | 831 characteristic_id_to_notify_session_.clear(); |
| 685 pending_primary_services_requests_.clear(); | 832 pending_primary_services_requests_.clear(); |
| 686 characteristic_id_to_service_id_.clear(); | 833 characteristic_id_to_service_id_.clear(); |
| 687 service_id_to_device_address_.clear(); | 834 service_id_to_device_address_.clear(); |
| 835 connected_devices_.reset( |
| 836 new FrameConnectedBluetoothDevices(render_frame_host_)); |
| 688 } | 837 } |
| 689 | 838 |
| 690 } // namespace content | 839 } // namespace content |
| OLD | NEW |