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 |