Chromium Code Reviews| Index: content/browser/bluetooth/bluetooth_service_impl.cc |
| diff --git a/content/browser/bluetooth/bluetooth_service_impl.cc b/content/browser/bluetooth/bluetooth_service_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2b1a920be11a9c7016f3b9b05c80b51708a5e0f5 |
| --- /dev/null |
| +++ b/content/browser/bluetooth/bluetooth_service_impl.cc |
| @@ -0,0 +1,182 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/bluetooth/bluetooth_service_impl.h" |
| + |
| +#include "content/browser/bluetooth/bluetooth_blacklist.h" |
| +#include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
| +#include "content/browser/renderer_host/render_process_host_impl.h" |
| +#include "content/public/browser/render_frame_host.h" |
| +#include "device/bluetooth/bluetooth_adapter_factory.h" |
| +#include "device/bluetooth/bluetooth_device.h" |
| +#include "device/bluetooth/bluetooth_discovery_session.h" |
| +#include "device/bluetooth/bluetooth_gatt_characteristic.h" |
| + |
| +using device::BluetoothGattService; |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +blink::mojom::WebBluetoothError GetWebError(CacheQueryOutcome outcome) { |
| + switch (outcome) { |
| + case CacheQueryOutcome::BAD_RENDERER: |
| + NOTREACHED(); |
| + return blink::mojom::WebBluetoothError::DEVICE_NO_LONGER_IN_RANGE; |
| + case CacheQueryOutcome::SUCCESS: |
| + return blink::mojom::WebBluetoothError::SUCCESS; |
| + case CacheQueryOutcome::NO_DEVICE: |
| + return blink::mojom::WebBluetoothError::DEVICE_NO_LONGER_IN_RANGE; |
| + case CacheQueryOutcome::NO_SERVICE: |
| + return blink::mojom::WebBluetoothError::SERVICE_NO_LONGER_EXISTS; |
| + case CacheQueryOutcome::NO_CHARACTERISTIC: |
| + return blink::mojom::WebBluetoothError::CHARACTERISTIC_NO_LONGER_EXISTS; |
| + } |
| + NOTREACHED(); |
| + return blink::mojom::WebBluetoothError::DEVICE_NO_LONGER_IN_RANGE; |
| +} |
| + |
| +blink::mojom::WebBluetoothError TranslateGATTErrorAndRecord( |
| + BluetoothGattService::GattErrorCode error_code, |
| + UMAGATTOperation operation) { |
| + switch (error_code) { |
| + case BluetoothGattService::GATT_ERROR_UNKNOWN: |
| + RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::UNKNOWN); |
| + return blink::mojom::WebBluetoothError::GATT_UNKNOWN_ERROR; |
| + case BluetoothGattService::GATT_ERROR_FAILED: |
| + RecordGATTOperationOutcome(operation, UMAGATTOperationOutcome::FAILED); |
| + return blink::mojom::WebBluetoothError::GATT_UNKNOWN_FAILURE; |
| + case BluetoothGattService::GATT_ERROR_IN_PROGRESS: |
| + RecordGATTOperationOutcome(operation, |
| + UMAGATTOperationOutcome::IN_PROGRESS); |
| + return blink::mojom::WebBluetoothError::GATT_OPERATION_IN_PROGRESS; |
| + case BluetoothGattService::GATT_ERROR_INVALID_LENGTH: |
| + RecordGATTOperationOutcome(operation, |
| + UMAGATTOperationOutcome::INVALID_LENGTH); |
| + return blink::mojom::WebBluetoothError::GATT_INVALID_ATTRIBUTE_LENGTH; |
| + case BluetoothGattService::GATT_ERROR_NOT_PERMITTED: |
| + RecordGATTOperationOutcome(operation, |
| + UMAGATTOperationOutcome::NOT_PERMITTED); |
| + return blink::mojom::WebBluetoothError::GATT_NOT_PERMITTED; |
| + case BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED: |
| + RecordGATTOperationOutcome(operation, |
| + UMAGATTOperationOutcome::NOT_AUTHORIZED); |
| + return blink::mojom::WebBluetoothError::GATT_NOT_AUTHORIZED; |
| + case BluetoothGattService::GATT_ERROR_NOT_PAIRED: |
| + RecordGATTOperationOutcome(operation, |
| + UMAGATTOperationOutcome::NOT_PAIRED); |
| + return blink::mojom::WebBluetoothError::GATT_NOT_PAIRED; |
| + case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED: |
| + RecordGATTOperationOutcome(operation, |
| + UMAGATTOperationOutcome::NOT_SUPPORTED); |
| + return blink::mojom::WebBluetoothError::GATT_NOT_SUPPORTED; |
| + } |
| + NOTREACHED(); |
| + return blink::mojom::WebBluetoothError::GATT_UNTRANSLATED_ERROR_CODE; |
| +} |
| + |
| +} // namespace |
| + |
| +using CacheQueryResult = BluetoothDispatcherHost::CacheQueryResult; |
| + |
| +// static |
| +void BluetoothServiceImpl::Create( |
| + int render_process_id, |
| + mojo::InterfaceRequest<BluetoothService> request) { |
| + new BluetoothServiceImpl(std::move(request), render_process_id); |
| +} |
| + |
| +BluetoothServiceImpl::BluetoothServiceImpl( |
| + mojo::InterfaceRequest<BluetoothService> request, |
| + int render_process_id) |
| + : render_process_id_(render_process_id), |
| + binding_(this, std::move(request)), |
| + weak_ptr_factory_(this) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + // Bind all future weak pointers to the UI thread. |
| + weak_ptr_on_ui_thread_ = weak_ptr_factory_.GetWeakPtr(); |
| + weak_ptr_on_ui_thread_.get(); // Associates with UI thread. |
| +} |
| + |
| +BluetoothServiceImpl::~BluetoothServiceImpl() {} |
| + |
| +void BluetoothServiceImpl::RemoteCharacteristicWriteValue( |
| + int frame_routing_id, |
| + const mojo::String& characteristic_instance_id, |
| + mojo::Array<uint8_t> value, |
| + const RemoteCharacteristicWriteValueCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + RecordWebBluetoothFunctionCall( |
| + UMAWebBluetoothFunction::CHARACTERISTIC_WRITE_VALUE); |
| + |
| + // We perform the length check on the renderer side. So if we |
| + // get a value with length > 512, we can assume it's a hostile |
| + // renderer and kill it. |
| + if (value.size() > 512) { |
| + CrashRenderer(bad_message::BDH_INVALID_WRITE_VALUE_LENGTH); |
| + return; |
| + } |
| + |
| + CacheQueryResult query_result = |
| + GetBluetoothDispatcherHost()->QueryCacheForCharacteristic( |
| + GetOrigin(frame_routing_id), characteristic_instance_id); |
| + |
| + if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
| + return; |
| + } |
| + |
| + if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| + RecordCharacteristicWriteValueOutcome(query_result.outcome); |
| + callback.Run(GetWebError(query_result.outcome)); |
| + return; |
| + } |
| + |
| + if (BluetoothBlacklist::Get().IsExcludedFromWrites( |
| + query_result.characteristic->GetUUID())) { |
| + RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::BLACKLISTED); |
| + callback.Run(blink::mojom::WebBluetoothError::BLACKLISTED_WRITE); |
| + return; |
| + } |
| + query_result.characteristic->WriteRemoteCharacteristic( |
|
Ken Rockot(use gerrit already)
2016/03/09 19:31:26
persisting offline discussion: need to make sure t
ortuno
2016/03/16 16:29:45
As discussed offline: BluetoothServiceImpl lives o
|
| + value.To<std::vector<uint8_t>>(), |
| + base::Bind(&BluetoothServiceImpl::OnWriteValueSuccess, |
| + weak_ptr_on_ui_thread_, callback), |
| + base::Bind(&BluetoothServiceImpl::OnWriteValueFailed, |
| + weak_ptr_on_ui_thread_, callback)); |
| +} |
| + |
| +void BluetoothServiceImpl::OnWriteValueSuccess( |
| + const RemoteCharacteristicWriteValueCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + RecordCharacteristicWriteValueOutcome(UMAGATTOperationOutcome::SUCCESS); |
| + callback.Run(blink::mojom::WebBluetoothError::SUCCESS); |
| +} |
| + |
| +void BluetoothServiceImpl::OnWriteValueFailed( |
| + const RemoteCharacteristicWriteValueCallback& callback, |
| + device::BluetoothGattService::GattErrorCode error_code) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + callback.Run(TranslateGATTErrorAndRecord( |
| + error_code, UMAGATTOperation::CHARACTERISTIC_WRITE)); |
| +} |
| + |
| +BluetoothDispatcherHost* BluetoothServiceImpl::GetBluetoothDispatcherHost() { |
| + RenderProcessHostImpl* render_process_host = |
| + static_cast<RenderProcessHostImpl*>( |
| + RenderProcessHost::FromID(render_process_id_)); |
| + return render_process_host->GetBluetoothDispatcherHost(); |
| +} |
| + |
| +void BluetoothServiceImpl::CrashRenderer(bad_message::BadMessageReason reason) { |
| + bad_message::ReceivedBadMessage(RenderProcessHost::FromID(render_process_id_), |
| + reason); |
| +} |
| + |
| +url::Origin BluetoothServiceImpl::GetOrigin(int frame_routing_id) { |
| + return RenderFrameHost::FromID(render_process_id_, frame_routing_id) |
| + ->GetLastCommittedOrigin(); |
| +} |
| + |
| +} // namespace content |