Index: content/browser/bluetooth/bluetooth_dispatcher_host.cc |
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc |
index 30d468b300e1ca6ef5e6691e9e62699cd2452547..b2e7ee3162b670a3c8a413bfdfc60f6324e0cdb8 100644 |
--- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc |
+++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc |
@@ -8,6 +8,13 @@ |
// case. |
// https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothdevice-connectgatt |
+// ID Not In Map Note: |
+// A service, characteristic, or descriptor ID not in the corresponding |
+// BluetoothDispatcherHost map [service_to_device_, characteristic_to_service_, |
+// 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. |
+ |
#include "content/browser/bluetooth/bluetooth_dispatcher_host.h" |
#include "base/bind.h" |
@@ -204,6 +211,8 @@ bool BluetoothDispatcherHost::OnMessageReceived(const IPC::Message& message) { |
IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic) |
IPC_MESSAGE_HANDLER(BluetoothHostMsg_ReadValue, OnReadValue) |
IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue) |
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_StartNotifications, OnStartNotifications) |
+ IPC_MESSAGE_HANDLER(BluetoothHostMsg_StopNotifications, OnStopNotifications) |
IPC_MESSAGE_UNHANDLED(handled = false) |
IPC_END_MESSAGE_MAP() |
return handled; |
@@ -358,6 +367,15 @@ void BluetoothDispatcherHost::DeviceRemoved(device::BluetoothAdapter* adapter, |
} |
} |
+void BluetoothDispatcherHost::GattCharacteristicValueChanged( |
+ device::BluetoothAdapter* adapter, |
+ device::BluetoothGattCharacteristic* characteristic, |
+ const std::vector<uint8>& value) { |
+ // TODO(ortuno): Notify renderer the characteristic changed. |
+ // http://crbug.com/529560 |
+ VLOG(1) << "Characteristic updated."; |
+} |
+ |
void BluetoothDispatcherHost::OnRequestDevice( |
int thread_id, |
int request_id, |
@@ -517,11 +535,8 @@ void BluetoothDispatcherHost::OnGetCharacteristic( |
RecordGetCharacteristicCharacteristic(characteristic_uuid); |
auto device_iter = service_to_device_.find(service_instance_id); |
- // A service_instance_id not in the map implies a hostile renderer |
- // because a renderer obtains the service id from this class and |
- // it will be added to the map at that time. |
+ // Kill the renderer, see "ID Not In Map Note" above. |
if (device_iter == service_to_device_.end()) { |
- // Kill the renderer |
bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_SERVICE_ID); |
return; |
} |
@@ -585,11 +600,9 @@ void BluetoothDispatcherHost::OnReadValue( |
auto characteristic_iter = |
characteristic_to_service_.find(characteristic_instance_id); |
- // A characteristic_instance_id not in the map implies a hostile renderer |
- // because a renderer obtains the characteristic id from this class and |
- // it will be added to the map at that time. |
+ |
+ // Kill the renderer, see "ID Not In Map Note" above. |
if (characteristic_iter == characteristic_to_service_.end()) { |
- // Kill the renderer |
bad_message::ReceivedBadMessage(this, |
bad_message::BDH_INVALID_CHARACTERISTIC_ID); |
return; |
@@ -657,9 +670,8 @@ void BluetoothDispatcherHost::OnWriteValue( |
auto characteristic_iter = |
characteristic_to_service_.find(characteristic_instance_id); |
- // A characteristic_instance_id not in the map implies a hostile renderer |
- // because a renderer obtains the characteristic id from this class and |
- // it will be added to the map at that time. |
+ |
+ // Kill the renderer, see "ID Not In Map Note" above. |
if (characteristic_iter == characteristic_to_service_.end()) { |
bad_message::ReceivedBadMessage(this, |
bad_message::BDH_INVALID_CHARACTERISTIC_ID); |
@@ -705,6 +717,94 @@ void BluetoothDispatcherHost::OnWriteValue( |
weak_ptr_on_ui_thread_, thread_id, request_id)); |
} |
+void BluetoothDispatcherHost::OnStartNotifications( |
+ int thread_id, |
+ int request_id, |
+ const std::string& characteristic_instance_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ RecordWebBluetoothFunctionCall( |
+ UMAWebBluetoothFunction::CHARACTERISTIC_START_NOTIFICATIONS); |
+ |
+ // BluetoothDispatcher will never send a request for a characteristic |
+ // already subscribed to notifications. |
+ if (characteristic_id_to_notify_session_.find(characteristic_instance_id) != |
+ characteristic_id_to_notify_session_.end()) { |
+ bad_message::ReceivedBadMessage( |
+ this, bad_message::BDH_CHARACTERISTIC_ALREADY_SUBSCRIBED); |
+ return; |
+ } |
+ |
+ // TODO(ortuno): Check if notify/indicate bit is set. |
+ // http://crbug.com/538869 |
+ |
+ auto characteristic_iter = |
+ characteristic_to_service_.find(characteristic_instance_id); |
+ |
+ // Kill the renderer, see "ID Not In Map Note" above. |
+ if (characteristic_iter == characteristic_to_service_.end()) { |
+ bad_message::ReceivedBadMessage(this, |
+ bad_message::BDH_INVALID_CHARACTERISTIC_ID); |
+ return; |
+ } |
+ |
+ const std::string& service_instance_id = characteristic_iter->second; |
+ auto device_iter = service_to_device_.find(service_instance_id); |
+ CHECK(device_iter != service_to_device_.end()); |
+ |
+ device::BluetoothDevice* device = |
+ adapter_->GetDevice(device_iter->second /* device_instance_id */); |
+ if (device == nullptr) { // See "NETWORK_ERROR Note" above. |
+ RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_DEVICE); |
+ Send(new BluetoothMsg_StartNotificationsError( |
+ thread_id, request_id, WebBluetoothError::DeviceNoLongerInRange)); |
+ return; |
+ } |
+ |
+ BluetoothGattService* service = device->GetGattService(service_instance_id); |
+ if (service == nullptr) { |
+ RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_SERVICE); |
+ Send(new BluetoothMsg_StartNotificationsError( |
+ thread_id, request_id, WebBluetoothError::ServiceNoLongerExists)); |
+ return; |
+ } |
+ |
+ BluetoothGattCharacteristic* characteristic = |
+ service->GetCharacteristic(characteristic_instance_id); |
+ if (characteristic == nullptr) { |
+ RecordStartNotificationsOutcome(UMAGATTOperationOutcome::NO_CHARACTERISTIC); |
+ Send(new BluetoothMsg_StartNotificationsError( |
+ thread_id, request_id, |
+ WebBluetoothError::CharacteristicNoLongerExists)); |
+ return; |
+ } |
+ |
+ characteristic->StartNotifySession( |
+ base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionSuccess, |
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), |
+ base::Bind(&BluetoothDispatcherHost::OnStartNotifySessionFailed, |
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); |
+} |
+ |
+void BluetoothDispatcherHost::OnStopNotifications( |
+ int thread_id, |
+ int request_id, |
+ const std::string& characteristic_instance_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ RecordWebBluetoothFunctionCall( |
+ UMAWebBluetoothFunction::CHARACTERISTIC_STOP_NOTIFICATIONS); |
+ |
+ auto notify_session_iter = |
+ characteristic_id_to_notify_session_.find(characteristic_instance_id); |
+ if (notify_session_iter == characteristic_id_to_notify_session_.end()) { |
+ Send(new BluetoothMsg_StopNotificationsSuccess(thread_id, request_id)); |
+ return; |
+ } |
+ notify_session_iter->second->Stop( |
+ base::Bind(&BluetoothDispatcherHost::OnStopNotifySession, |
+ weak_ptr_factory_.GetWeakPtr(), thread_id, request_id, |
+ characteristic_instance_id)); |
+} |
+ |
void BluetoothDispatcherHost::OnDiscoverySessionStarted( |
int chooser_id, |
scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { |
@@ -946,6 +1046,35 @@ void BluetoothDispatcherHost::OnWriteValueFailed( |
TranslateGATTError(error_code, UMAGATTOperation::CHARACTERISTIC_WRITE))); |
} |
+void BluetoothDispatcherHost::OnStartNotifySessionSuccess( |
+ int thread_id, |
+ int request_id, |
+ scoped_ptr<device::BluetoothGattNotifySession> notify_session) { |
+ RecordStartNotificationsOutcome(UMAGATTOperationOutcome::SUCCESS); |
+ |
+ characteristic_id_to_notify_session_.insert( |
+ notify_session->GetCharacteristicIdentifier(), notify_session.Pass()); |
+ Send(new BluetoothMsg_StartNotificationsSuccess(thread_id, request_id)); |
+} |
+ |
+void BluetoothDispatcherHost::OnStartNotifySessionFailed( |
+ int thread_id, |
+ int request_id, |
+ device::BluetoothGattService::GattErrorCode error_code) { |
+ // TranslateGATTError calls RecordGATTOperationOutcome. |
+ Send(new BluetoothMsg_StartNotificationsError( |
+ thread_id, request_id, |
+ TranslateGATTError(error_code, UMAGATTOperation::START_NOTIFICATIONS))); |
+} |
+ |
+void BluetoothDispatcherHost::OnStopNotifySession( |
+ int thread_id, |
+ int request_id, |
+ const std::string& characteristic_instance_id) { |
+ characteristic_id_to_notify_session_.erase(characteristic_instance_id); |
+ Send(new BluetoothMsg_StopNotificationsSuccess(thread_id, request_id)); |
+} |
+ |
void BluetoothDispatcherHost::ShowBluetoothOverviewLink() { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
NOTIMPLEMENTED(); |