diff options
author | ortuno <ortuno@chromium.org> | 2015-07-08 14:35:20 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-08 21:35:50 +0000 |
commit | af85f60db9f8a89b2b4446e47c73f7cc44dcf4c6 (patch) | |
tree | aeca3b55398142b642b1772e2eb17a736e24b2f2 | |
parent | b0caed2bedfc19825ba34024c4678adf351d561c (diff) | |
download | chromium_src-af85f60db9f8a89b2b4446e47c73f7cc44dcf4c6.zip chromium_src-af85f60db9f8a89b2b4446e47c73f7cc44dcf4c6.tar.gz chromium_src-af85f60db9f8a89b2b4446e47c73f7cc44dcf4c6.tar.bz2 |
bluetooth: browser-side implementation of writeValue.
Chrome spec repo update: https://github.com/WebBluetoothChrome/web-bluetooth/pull/12
This is the second of three patches to implement writeValue():
[1] http://crrev.com/1212943006 (Blink-side interface)
[2] This patch.
[3] http://crrev.com/1218803008 (Blink-side implementation)
BUG=507415
Review URL: https://codereview.chromium.org/1217983004
Cr-Commit-Position: refs/heads/master@{#337912}
11 files changed, 181 insertions, 2 deletions
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index 30d33d4..796f66a 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h @@ -113,6 +113,7 @@ enum BadMessageReason { SWDH_UPDATE_BAD_REGISTRATION_ID = 87, SWDH_UPDATE_CANNOT = 88, SWDH_UNREGISTER_BAD_REGISTRATION_ID = 89, + BDH_INVALID_WRITE_VALUE_LENGTH = 90, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc index 6ccc37b..987a067 100644 --- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc +++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc @@ -189,6 +189,7 @@ bool BluetoothDispatcherHost::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetPrimaryService, OnGetPrimaryService) IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic) IPC_MESSAGE_HANDLER(BluetoothHostMsg_ReadValue, OnReadValue) + IPC_MESSAGE_HANDLER(BluetoothHostMsg_WriteValue, OnWriteValue) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -432,6 +433,72 @@ void BluetoothDispatcherHost::OnReadValue( weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); } +void BluetoothDispatcherHost::OnWriteValue( + int thread_id, + int request_id, + const std::string& characteristic_instance_id, + const std::vector<uint8_t>& value) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // Length check per step 3 of writeValue algorithm: + // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattcharacteristic-writevalue + // 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) { + bad_message::ReceivedBadMessage( + this, bad_message::BDH_INVALID_WRITE_VALUE_LENGTH); + return; + } + + 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. + 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. + Send(new BluetoothMsg_WriteCharacteristicValueError( + thread_id, request_id, BluetoothError::NETWORK, + kDeviceNoLongerInRange)); + return; + } + + BluetoothGattService* service = device->GetGattService(service_instance_id); + if (service == nullptr) { + Send(new BluetoothMsg_WriteCharacteristicValueError( + thread_id, request_id, BluetoothError::INVALID_STATE, + kServiceNoLongerExists)); + return; + } + + BluetoothGattCharacteristic* characteristic = + service->GetCharacteristic(characteristic_instance_id); + if (characteristic == nullptr) { + Send(new BluetoothMsg_WriteCharacteristicValueError( + thread_id, request_id, BluetoothError::INVALID_STATE, + kCharacteristicNoLongerExits)); + return; + } + characteristic->WriteRemoteCharacteristic( + value, base::Bind(&BluetoothDispatcherHost::OnWriteValueSuccess, + weak_ptr_factory_.GetWeakPtr(), thread_id, request_id), + base::Bind(&BluetoothDispatcherHost::OnWriteValueFailed, + weak_ptr_factory_.GetWeakPtr(), thread_id, request_id)); +} + void BluetoothDispatcherHost::OnDiscoverySessionStarted( int thread_id, int request_id, @@ -582,4 +649,19 @@ void BluetoothDispatcherHost::OnCharacteristicReadValueError( thread_id, request_id, error.first, error.second)); } +void BluetoothDispatcherHost::OnWriteValueSuccess(int thread_id, + int request_id) { + Send(new BluetoothMsg_WriteCharacteristicValueSuccess(thread_id, request_id)); +} + +void BluetoothDispatcherHost::OnWriteValueFailed( + int thread_id, + int request_id, + device::BluetoothGattService::GattErrorCode error_code) { + std::pair<BluetoothError, std::string> error = TranslateGATTError(error_code); + + Send(new BluetoothMsg_WriteCharacteristicValueError( + thread_id, request_id, error.first, error.second)); +} + } // namespace content diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.h b/content/browser/bluetooth/bluetooth_dispatcher_host.h index 0e02382..f448468 100644 --- a/content/browser/bluetooth/bluetooth_dispatcher_host.h +++ b/content/browser/bluetooth/bluetooth_dispatcher_host.h @@ -77,6 +77,10 @@ class CONTENT_EXPORT BluetoothDispatcherHost final void OnReadValue(int thread_id, int request_id, const std::string& characteristic_instance_id); + void OnWriteValue(int thread_id, + int request_id, + const std::string& characteristic_instance_id, + const std::vector<uint8_t>& value); // Callbacks for BluetoothAdapter::StartDiscoverySession. void OnDiscoverySessionStarted( @@ -128,6 +132,12 @@ class CONTENT_EXPORT BluetoothDispatcherHost final int request_id, device::BluetoothGattService::GattErrorCode); + // Callbacks for BluetoothGattCharacteristic::WriteRemoteCharacteristic. + void OnWriteValueSuccess(int thread_id, int request_id); + void OnWriteValueFailed(int thread_id, + int request_id, + device::BluetoothGattService::GattErrorCode); + // Maps to get the object's parent based on it's instanceID // Map of service_instance_id to device_instance_id. std::map<std::string, std::string> service_to_device_; diff --git a/content/child/bluetooth/bluetooth_dispatcher.cc b/content/child/bluetooth/bluetooth_dispatcher.cc index 2643752..82530d9 100644 --- a/content/child/bluetooth/bluetooth_dispatcher.cc +++ b/content/child/bluetooth/bluetooth_dispatcher.cc @@ -163,6 +163,10 @@ void BluetoothDispatcher::OnMessageReceived(const IPC::Message& msg) { OnReadValueSuccess); IPC_MESSAGE_HANDLER(BluetoothMsg_ReadCharacteristicValueError, OnReadValueError); + IPC_MESSAGE_HANDLER(BluetoothMsg_WriteCharacteristicValueSuccess, + OnWriteValueSuccess); + IPC_MESSAGE_HANDLER(BluetoothMsg_WriteCharacteristicValueError, + OnWriteValueError); IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() DCHECK(handled) << "Unhandled message:" << msg.type(); @@ -233,6 +237,16 @@ void BluetoothDispatcher::readValue( characteristic_instance_id.utf8())); } +void BluetoothDispatcher::writeValue( + const blink::WebString& characteristic_instance_id, + const std::vector<uint8_t>& value, + blink::WebBluetoothWriteValueCallbacks* callbacks) { + int request_id = pending_write_value_requests_.Add(callbacks); + + Send(new BluetoothHostMsg_WriteValue( + CurrentWorkerId(), request_id, characteristic_instance_id.utf8(), value)); +} + void BluetoothDispatcher::OnWorkerRunLoopStopped() { delete this; } @@ -404,4 +418,26 @@ void BluetoothDispatcher::OnReadValueError(int thread_id, pending_read_value_requests_.Remove(request_id); } +void BluetoothDispatcher::OnWriteValueSuccess(int thread_id, int request_id) { + DCHECK(pending_write_value_requests_.Lookup(request_id)) << request_id; + + pending_write_value_requests_.Lookup(request_id)->onSuccess(); + + pending_write_value_requests_.Remove(request_id); +} + +void BluetoothDispatcher::OnWriteValueError(int thread_id, + int request_id, + BluetoothError error_type, + const std::string& error_message) { + DCHECK(pending_write_value_requests_.Lookup(request_id)) << request_id; + + pending_write_value_requests_.Lookup(request_id) + ->onError( + new WebBluetoothError(WebBluetoothErrorFromBluetoothError(error_type), + WebString::fromUTF8(error_message))); + + pending_write_value_requests_.Remove(request_id); +} + } // namespace content diff --git a/content/child/bluetooth/bluetooth_dispatcher.h b/content/child/bluetooth/bluetooth_dispatcher.h index 254c732a..2b2a1357 100644 --- a/content/child/bluetooth/bluetooth_dispatcher.h +++ b/content/child/bluetooth/bluetooth_dispatcher.h @@ -65,6 +65,9 @@ class BluetoothDispatcher : public WorkerTaskRunner::Observer { blink::WebBluetoothGetCharacteristicCallbacks* callbacks); void readValue(const blink::WebString& characteristic_instance_id, blink::WebBluetoothReadValueCallbacks* callbacks); + void writeValue(const blink::WebString& characteristic_instance_id, + const std::vector<uint8_t>& value, + blink::WebBluetoothWriteValueCallbacks*); // WorkerTaskRunner::Observer implementation. void OnWorkerRunLoopStopped() override; @@ -109,6 +112,11 @@ class BluetoothDispatcher : public WorkerTaskRunner::Observer { int request_id, BluetoothError error_type, const std::string& error_message); + void OnWriteValueSuccess(int thread_id, int request_id); + void OnWriteValueError(int thread_id, + int request_id, + BluetoothError error_type, + const std::string& error_message); scoped_refptr<ThreadSafeSender> thread_safe_sender_; @@ -130,6 +138,8 @@ class BluetoothDispatcher : public WorkerTaskRunner::Observer { // Tracks requests to read from a characteristics. IDMap<blink::WebBluetoothReadValueCallbacks, IDMapOwnPointer> pending_read_value_requests_; + IDMap<blink::WebBluetoothWriteValueCallbacks, IDMapOwnPointer> + pending_write_value_requests_; DISALLOW_COPY_AND_ASSIGN(BluetoothDispatcher); }; diff --git a/content/child/bluetooth/web_bluetooth_impl.cc b/content/child/bluetooth/web_bluetooth_impl.cc index fd85a7d..c307461 100644 --- a/content/child/bluetooth/web_bluetooth_impl.cc +++ b/content/child/bluetooth/web_bluetooth_impl.cc @@ -49,6 +49,13 @@ void WebBluetoothImpl::readValue( GetDispatcher()->readValue(characteristic_instance_id, callbacks); } +void WebBluetoothImpl::writeValue( + const blink::WebString& characteristic_instance_id, + const std::vector<uint8_t>& value, + blink::WebBluetoothWriteValueCallbacks* callbacks) { + GetDispatcher()->writeValue(characteristic_instance_id, value, callbacks); +} + BluetoothDispatcher* WebBluetoothImpl::GetDispatcher() { return BluetoothDispatcher::GetOrCreateThreadSpecificInstance( thread_safe_sender_.get()); diff --git a/content/child/bluetooth/web_bluetooth_impl.h b/content/child/bluetooth/web_bluetooth_impl.h index 0a78df2..5eede0e 100644 --- a/content/child/bluetooth/web_bluetooth_impl.h +++ b/content/child/bluetooth/web_bluetooth_impl.h @@ -41,6 +41,9 @@ class CONTENT_EXPORT WebBluetoothImpl blink::WebBluetoothGetCharacteristicCallbacks* callbacks) override; void readValue(const blink::WebString& characteristic_instance_id, blink::WebBluetoothReadValueCallbacks* callbacks) override; + void writeValue(const blink::WebString& characteristic_instance_id, + const std::vector<uint8_t>& value, + blink::WebBluetoothWriteValueCallbacks*) override; private: BluetoothDispatcher* GetDispatcher(); diff --git a/content/common/bluetooth/bluetooth_messages.h b/content/common/bluetooth/bluetooth_messages.h index 4686131..378925e 100644 --- a/content/common/bluetooth/bluetooth_messages.h +++ b/content/common/bluetooth/bluetooth_messages.h @@ -175,6 +175,20 @@ IPC_MESSAGE_CONTROL4(BluetoothMsg_ReadCharacteristicValueError, content::BluetoothError /* result */, std::string /* error_message */) +// Informs the renderer that the value has been successfully written to +// the characteristic. +IPC_MESSAGE_CONTROL2(BluetoothMsg_WriteCharacteristicValueSuccess, + int /* thread_id */, + int /* request_id */) + +// Informs the renderer that an error occurred while writing a value to a +// characteristic. +IPC_MESSAGE_CONTROL4(BluetoothMsg_WriteCharacteristicValueError, + int /* thread_id */, + int /* request_id */, + content::BluetoothError /* result */, + std::string /* error_message */) + // Messages sent from the renderer to the browser. // Requests a bluetooth device from the browser. @@ -215,3 +229,10 @@ IPC_MESSAGE_CONTROL3(BluetoothHostMsg_ReadValue, int /* thread_id */, int /* request_id */, std::string /* characteristic_instance_id */) + +// Writes a value to a bluetooth device's characteristic. +IPC_MESSAGE_CONTROL4(BluetoothHostMsg_WriteValue, + int /* thread_id */, + int /* request_id */, + std::string /* characteristic_instance_id */, + std::vector<uint8_t> /* value */) diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc index 4c0635a..aad6fe5 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc @@ -272,6 +272,10 @@ LayoutTestBluetoothAdapterProvider::GetEmptyDevice( ON_CALL(*device_name_characteristic, ReadRemoteCharacteristic(_, _)) .WillByDefault(RunCallback<0>(device_name_value)); + ON_CALL(*device_name_characteristic, WriteRemoteCharacteristic(_, _, _)) + .WillByDefault(RunCallback<2 /* error callback */>( + BluetoothGattService::GATT_ERROR_NOT_PERMITTED)); + generic_access->AddMockCharacteristic(device_name_characteristic.Pass()); scoped_ptr<NiceMock<MockBluetoothGattCharacteristic>> reconnection_address( @@ -282,6 +286,9 @@ LayoutTestBluetoothAdapterProvider::GetEmptyDevice( .WillByDefault( RunCallback<1>(BluetoothGattService::GATT_ERROR_NOT_PERMITTED)); + ON_CALL(*reconnection_address, WriteRemoteCharacteristic(_, _, _)) + .WillByDefault(RunCallback<1 /* success callback */>()); + generic_access->AddMockCharacteristic(reconnection_address.Pass()); empty_device->AddMockService(generic_access.Pass()); diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h index da91254..40aa323 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h @@ -101,8 +101,9 @@ class LayoutTestBluetoothAdapterProvider { // - |GetUUIDs| returns a list with two UUIDs: "1800" and "1801". // - |GetGattServices| returns a list with one service "Generic Access". // "Generic Access" has a "Device Name" characteristic, with a value of - // "Empty Mock Device Name", and a "Reconnection Address" characteristic - // which can't be read. + // "Empty Mock Device Name" that can be read but not written, and a + // "Reconnection Address" characteristic which can't be read, but can be + // written. static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>> GetEmptyDevice(device::MockBluetoothAdapter* adapter, const std::string& device_name = "Empty Mock Device"); diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 31c9f25..038ec9c 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -50648,6 +50648,7 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries. <int value="87" label="SWDH_UPDATE_BAD_REGISTRATION_ID"/> <int value="88" label="SWDH_UPDATE_CANNOT"/> <int value="89" label="SWDH_UNREGISTER_BAD_REGISTRATION_ID"/> + <int value="90" label="BDH_INVALID_WRITE_VALUE_LENGTH"/> </enum> <enum name="BadMessageReasonExtensions" type="int"> |