Chromium Code Reviews| Index: content/browser/bluetooth/web_bluetooth_service_impl.cc |
| diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc |
| index f4ab0195f291d1ce6d3eaa9fcd1d93c8e04bd9ea..9a1f51d726b0ea479754c94f823ed0ab03c77a0e 100644 |
| --- a/content/browser/bluetooth/web_bluetooth_service_impl.cc |
| +++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc |
| @@ -4,7 +4,7 @@ |
| // ID Not In Map Note: |
| // A service, characteristic, or descriptor ID not in the corresponding |
| -// BluetoothDispatcherHost map [service_id_to_device_address_, |
| +// WebBluetoothServiceImpl map [service_id_to_device_address_, |
| // characteristic_id_to_service_id_, descriptor_to_characteristic_] implies a |
| // hostile renderer because a renderer obtains the corresponding ID from this |
| // class and it will be added to the map at that time. |
| @@ -13,11 +13,15 @@ |
| #include <algorithm> |
| +#include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| +#include "content/browser/bluetooth/bluetooth_adapter_factory_wrapper.h" |
| #include "content/browser/bluetooth/bluetooth_blacklist.h" |
| -#include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
| +#include "content/browser/bluetooth/bluetooth_device_chooser_controller.h" |
| +#include "content/browser/bluetooth/bluetooth_metrics.h" |
| #include "content/browser/bluetooth/frame_connected_bluetooth_devices.h" |
| #include "content/browser/renderer_host/render_process_host_impl.h" |
| +#include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_handle.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/web_contents.h" |
| @@ -170,13 +174,11 @@ WebBluetoothServiceImpl::WebBluetoothServiceImpl( |
| weak_ptr_factory_(this) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| CHECK(web_contents()); |
| - |
| - GetBluetoothDispatcherHost()->AddAdapterObserver(this); |
| } |
| WebBluetoothServiceImpl::~WebBluetoothServiceImpl() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - GetBluetoothDispatcherHost()->RemoveAdapterObserver(this); |
| + ClearState(); |
| } |
| void WebBluetoothServiceImpl::SetClientConnectionErrorHandler( |
| @@ -193,11 +195,22 @@ void WebBluetoothServiceImpl::DidFinishNavigation( |
| } |
| } |
| -void WebBluetoothServiceImpl::AdapterPresentChanged( |
| +void WebBluetoothServiceImpl::AdapterPoweredChanged( |
| device::BluetoothAdapter* adapter, |
| - bool present) { |
| - if (!present) { |
| - ClearState(); |
| + bool powered) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + if (device_chooser_controller_.get()) { |
| + device_chooser_controller_->AdapterPoweredChanged(powered); |
| + } |
| +} |
| + |
| +void WebBluetoothServiceImpl::DeviceAdded(device::BluetoothAdapter* adapter, |
| + device::BluetoothDevice* device) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + if (device_chooser_controller_.get()) { |
| + VLOG(1) << "Adding device to device chooser controller: " |
| + << device->GetAddress(); |
| + device_chooser_controller_->AddFilteredDevice(*device); |
| } |
| } |
| @@ -275,14 +288,35 @@ void WebBluetoothServiceImpl::SetClient( |
| client_.Bind(std::move(client)); |
| } |
| +void WebBluetoothServiceImpl::RequestDevice( |
| + blink::mojom::WebBluetoothRequestDeviceOptionsPtr options, |
| + const RequestDeviceCallback& callback) { |
| + RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::REQUEST_DEVICE); |
| + RecordRequestDeviceOptions(options); |
| + |
| + if (!GetAdapter()) { |
| + if (GetBluetoothAdapterFactoryWrapper().IsBluetoothAdapterAvailable()) { |
| + GetBluetoothAdapterFactoryWrapper().AcquireAdapter( |
| + this, base::Bind(&WebBluetoothServiceImpl::RequestDeviceImpl, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + base::Passed(std::move(options)), callback)); |
| + return; |
| + } |
| + RecordRequestDeviceOutcome(UMARequestDeviceOutcome::NO_BLUETOOTH_ADAPTER); |
| + callback.Run(blink::mojom::WebBluetoothError::NO_BLUETOOTH_ADAPTER, |
| + nullptr /* device */); |
| + return; |
| + } |
| + RequestDeviceImpl(std::move(options), callback, GetAdapter()); |
| +} |
| + |
| void WebBluetoothServiceImpl::RemoteServerConnect( |
| const mojo::String& device_id, |
| const RemoteServerConnectCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT); |
| - const CacheQueryResult query_result = |
| - GetBluetoothDispatcherHost()->QueryCacheForDevice(GetOrigin(), device_id); |
| + const CacheQueryResult query_result = QueryCacheForDevice(device_id); |
| if (query_result.outcome != CacheQueryOutcome::SUCCESS) { |
| RecordConnectGATTOutcome(query_result.outcome); |
| @@ -335,16 +369,14 @@ void WebBluetoothServiceImpl::RemoteServerGetPrimaryService( |
| RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_PRIMARY_SERVICE); |
| RecordGetPrimaryServiceService(device::BluetoothUUID(service_uuid)); |
| - if (!GetBluetoothDispatcherHost() |
| - ->allowed_devices_map_.IsOriginAllowedToAccessService( |
| - GetOrigin(), device_id, service_uuid)) { |
| + if (!allowed_devices_map_.IsOriginAllowedToAccessService( |
| + GetOrigin(), device_id, service_uuid)) { |
| callback.Run(blink::mojom::WebBluetoothError::NOT_ALLOWED_TO_ACCESS_SERVICE, |
| nullptr /* service */); |
| return; |
| } |
| - const CacheQueryResult query_result = |
| - GetBluetoothDispatcherHost()->QueryCacheForDevice(GetOrigin(), device_id); |
| + const CacheQueryResult query_result = QueryCacheForDevice(device_id); |
| if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
| binding_.Close(); |
| @@ -613,6 +645,27 @@ void WebBluetoothServiceImpl::RemoteCharacteristicStopNotifications( |
| weak_ptr_factory_.GetWeakPtr(), characteristic_instance_id, callback)); |
| } |
| +void WebBluetoothServiceImpl::RequestDeviceImpl( |
| + blink::mojom::WebBluetoothRequestDeviceOptionsPtr options, |
| + const RequestDeviceCallback& callback, |
| + device::BluetoothAdapter* adapter) { |
| + // requestDevice() can only be called when processing a user-gesture and |
| + // any user gesture outside of a chooser should close the chooser so we should |
| + // never get a request with an open chooser. |
| + CHECK(!device_chooser_controller_.get()); |
| + |
| + device_chooser_controller_.reset(new BluetoothDeviceChooserController( |
| + this, render_frame_host_, adapter, |
| + GetBluetoothAdapterFactoryWrapper().GetScanDuration())); |
| + |
| + device_chooser_controller_->GetDevice( |
| + std::move(options), |
| + base::Bind(&WebBluetoothServiceImpl::OnGetDeviceSuccess, |
| + weak_ptr_factory_.GetWeakPtr(), callback), |
| + base::Bind(&WebBluetoothServiceImpl::OnGetDeviceFailed, |
| + weak_ptr_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| void WebBluetoothServiceImpl::RemoteServerGetPrimaryServiceImpl( |
| const std::string& service_uuid, |
| const RemoteServerGetPrimaryServiceCallback& callback, |
| @@ -648,6 +701,57 @@ void WebBluetoothServiceImpl::RemoteServerGetPrimaryServiceImpl( |
| std::move(service_ptr)); |
| } |
| +void WebBluetoothServiceImpl::OnGetDeviceSuccess( |
| + const RequestDeviceCallback& callback, |
| + blink::mojom::WebBluetoothRequestDeviceOptionsPtr options, |
| + const std::string& device_address) { |
| + device_chooser_controller_.reset(); |
| + |
| + const device::BluetoothDevice* const device = |
| + GetAdapter()->GetDevice(device_address); |
| + if (device == nullptr) { |
| + VLOG(1) << "Device " << device_address << " no longer in adapter"; |
| + RecordRequestDeviceOutcome(UMARequestDeviceOutcome::CHOSEN_DEVICE_VANISHED); |
| + callback.Run(blink::mojom::WebBluetoothError::CHOSEN_DEVICE_VANISHED, |
| + nullptr /* device */); |
| + return; |
| + } |
| + |
| + const std::string device_id_for_origin = |
| + allowed_devices_map_.AddDevice(GetOrigin(), device_address, options); |
| + |
| + VLOG(1) << "Device: " << device->GetName(); |
| + VLOG(1) << "UUIDs: "; |
| + |
| + mojo::Array<mojo::String> filtered_uuids; |
| + for (const device::BluetoothUUID& uuid : device->GetUUIDs()) { |
| + if (allowed_devices_map_.IsOriginAllowedToAccessService( |
| + GetOrigin(), device_id_for_origin, uuid.canonical_value())) { |
| + VLOG(1) << "\t Allowed: " << uuid.canonical_value(); |
| + filtered_uuids.push_back(uuid.canonical_value()); |
| + } else { |
| + VLOG(1) << "\t Not Allowed: " << uuid.canonical_value(); |
| + } |
| + } |
| + |
| + blink::mojom::WebBluetoothDevicePtr device_ptr = |
| + blink::mojom::WebBluetoothDevice::New(); |
| + device_ptr->id = device_id_for_origin; |
| + device_ptr->name = base::UTF16ToUTF8(device->GetName()); |
| + device_ptr->uuids = std::move(filtered_uuids); |
| + |
| + RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS); |
| + callback.Run(blink::mojom::WebBluetoothError::SUCCESS, std::move(device_ptr)); |
| +} |
| + |
| +void WebBluetoothServiceImpl::OnGetDeviceFailed( |
| + const RequestDeviceCallback& callback, |
| + blink::mojom::WebBluetoothError error) { |
| + // Errors are recorded the *device_chooser_controller_. |
|
Jeffrey Yasskin
2016/05/13 21:36:55
Nit: "recorded by the"
ortuno
2016/05/13 22:14:38
Done.
|
| + callback.Run(error, nullptr /* device */); |
| + device_chooser_controller_.reset(); |
| +} |
| + |
| void WebBluetoothServiceImpl::OnCreateGATTConnectionSuccess( |
| const std::string& device_id, |
| base::TimeTicks start_time, |
| @@ -733,6 +837,27 @@ void WebBluetoothServiceImpl::OnStopNotifySessionComplete( |
| callback.Run(); |
| } |
| +CacheQueryResult WebBluetoothServiceImpl::QueryCacheForDevice( |
| + const std::string& device_id) { |
| + const std::string& device_address = |
| + allowed_devices_map_.GetDeviceAddress(GetOrigin(), device_id); |
| + if (device_address.empty()) { |
| + CrashRendererAndClosePipe(bad_message::BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN); |
| + return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER); |
| + } |
| + |
| + CacheQueryResult result; |
| + result.device = GetAdapter()->GetDevice(device_address); |
| + |
| + // When a device can't be found in the BluetoothAdapter, that generally |
| + // indicates that it's gone out of range. We reject with a NetworkError in |
| + // that case. |
| + if (result.device == nullptr) { |
| + result.outcome = CacheQueryOutcome::NO_DEVICE; |
| + } |
| + return result; |
| +} |
| + |
| CacheQueryResult WebBluetoothServiceImpl::QueryCacheForService( |
| const std::string& service_instance_id) { |
| auto device_iter = service_id_to_device_address_.find(service_instance_id); |
| @@ -744,23 +869,14 @@ CacheQueryResult WebBluetoothServiceImpl::QueryCacheForService( |
| } |
| const std::string& device_id = |
| - GetBluetoothDispatcherHost()->allowed_devices_map_.GetDeviceId( |
| - GetOrigin(), device_iter->second); |
| + allowed_devices_map_.GetDeviceId(GetOrigin(), device_iter->second); |
| // Kill the renderer if origin is not allowed to access the device. |
| if (device_id.empty()) { |
| CrashRendererAndClosePipe(bad_message::BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN); |
| return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER); |
| } |
| - CacheQueryResult result = |
| - GetBluetoothDispatcherHost()->QueryCacheForDevice(GetOrigin(), device_id); |
| - |
| - // TODO(ortuno): Remove once QueryCacheForDevice closes binding_. |
| - // http://crbug.com/508771 |
| - if (result.outcome == CacheQueryOutcome::BAD_RENDERER) { |
| - binding_.Close(); |
| - } |
| - |
| + CacheQueryResult result = QueryCacheForDevice(device_id); |
| if (result.outcome != CacheQueryOutcome::SUCCESS) { |
| return result; |
| } |
| @@ -768,10 +884,9 @@ CacheQueryResult WebBluetoothServiceImpl::QueryCacheForService( |
| result.service = result.device->GetGattService(service_instance_id); |
| if (result.service == nullptr) { |
| result.outcome = CacheQueryOutcome::NO_SERVICE; |
| - } else if (!GetBluetoothDispatcherHost() |
| - ->allowed_devices_map_.IsOriginAllowedToAccessService( |
| - GetOrigin(), device_id, |
| - result.service->GetUUID().canonical_value())) { |
| + } else if (!allowed_devices_map_.IsOriginAllowedToAccessService( |
| + GetOrigin(), device_id, |
| + result.service->GetUUID().canonical_value())) { |
| CrashRendererAndClosePipe(bad_message::BDH_SERVICE_NOT_ALLOWED_FOR_ORIGIN); |
| return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER); |
| } |
| @@ -809,10 +924,15 @@ RenderProcessHost* WebBluetoothServiceImpl::GetRenderProcessHost() { |
| return render_frame_host_->GetProcess(); |
| } |
| -BluetoothDispatcherHost* WebBluetoothServiceImpl::GetBluetoothDispatcherHost() { |
| +BluetoothAdapterFactoryWrapper& |
| +WebBluetoothServiceImpl::GetBluetoothAdapterFactoryWrapper() { |
| RenderProcessHostImpl* render_process_host_impl = |
| static_cast<RenderProcessHostImpl*>(GetRenderProcessHost()); |
| - return render_process_host_impl->GetBluetoothDispatcherHost(); |
| + return *(render_process_host_impl->GetBluetoothAdapterFactoryWrapper()); |
| +} |
| + |
| +device::BluetoothAdapter* WebBluetoothServiceImpl::GetAdapter() { |
| + return GetBluetoothAdapterFactoryWrapper().GetAdapter(this); |
| } |
| void WebBluetoothServiceImpl::CrashRendererAndClosePipe( |
| @@ -832,6 +952,9 @@ void WebBluetoothServiceImpl::ClearState() { |
| service_id_to_device_address_.clear(); |
| connected_devices_.reset( |
| new FrameConnectedBluetoothDevices(render_frame_host_)); |
| + allowed_devices_map_ = BluetoothAllowedDevicesMap(); |
| + device_chooser_controller_.reset(); |
| + GetBluetoothAdapterFactoryWrapper().ReleaseAdapter(this); |
| } |
| } // namespace content |