Index: device/bluetooth/dbus/bluetooth_device_client.cc |
diff --git a/device/bluetooth/dbus/bluetooth_device_client.cc b/device/bluetooth/dbus/bluetooth_device_client.cc |
index 920fb3c9c82ab13a2357bad9c9bad3892a9e3a7f..a081b658363f744f355f0a8111fe2bfe7491e966 100644 |
--- a/device/bluetooth/dbus/bluetooth_device_client.cc |
+++ b/device/bluetooth/dbus/bluetooth_device_client.cc |
@@ -7,11 +7,13 @@ |
#include "base/bind.h" |
#include "base/logging.h" |
#include "base/macros.h" |
+#include "base/memory/ptr_util.h" |
#include "base/stl_util.h" |
#include "dbus/bus.h" |
#include "dbus/message.h" |
#include "dbus/object_manager.h" |
#include "dbus/object_proxy.h" |
+#include "device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h" |
#include "third_party/cros_system_api/dbus/service_constants.h" |
namespace bluez { |
@@ -21,6 +23,150 @@ namespace { |
// Value returned for the the RSSI or TX power if it cannot be read. |
const int kUnknownPower = 127; |
+std::unique_ptr<BluetoothServiceAttributeValueBlueZ> ReadAttributeValue( |
+ dbus::MessageReader* struct_reader) { |
+ uint8_t type_val; |
+ if (!struct_reader->PopByte(&type_val)) |
+ return nullptr; |
+ BluetoothServiceAttributeValueBlueZ::Type type = |
+ static_cast<BluetoothServiceAttributeValueBlueZ::Type>(type_val); |
+ |
+ uint32_t size; |
+ if (!struct_reader->PopUint32(&size)) |
+ return nullptr; |
+ |
+ std::unique_ptr<base::Value> value = nullptr; |
+ switch (type) { |
+ case bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE: { |
+ break; |
+ } |
+ case bluez::BluetoothServiceAttributeValueBlueZ::UINT: |
+ // Fall through. |
+ case bluez::BluetoothServiceAttributeValueBlueZ::INT: { |
+ switch (size) { |
+ // It doesn't matter what 'sign' the number is, only size. |
+ // Whenever we unpack this value, we will take the raw bits and |
+ // cast it back to the correct sign anyway. |
+ case 1: |
+ uint8_t byte; |
+ if (!struct_reader->PopVariantOfByte(&byte)) |
+ return nullptr; |
+ value = base::MakeUnique<base::FundamentalValue>(byte); |
+ break; |
+ case 2: |
+ uint16_t short_val; |
+ if (!struct_reader->PopVariantOfUint16(&short_val)) |
+ return nullptr; |
+ value = base::MakeUnique<base::FundamentalValue>(short_val); |
+ break; |
+ case 4: |
+ uint32_t val; |
+ if (!struct_reader->PopVariantOfUint32(&val)) |
+ return nullptr; |
+ value = base::MakeUnique<base::FundamentalValue>( |
+ static_cast<int32_t>(val)); |
+ break; |
+ case 8: |
+ // Fall through. |
+ // BlueZ should never be sending us this size at the moment since |
+ // the Android SDP records we will create from these raw records |
+ // don't have any fields which use this size. If we ever decide to |
+ // change this, this needs to get fixed. |
+ default: |
+ NOTREACHED(); |
+ } |
+ break; |
+ } |
+ case bluez::BluetoothServiceAttributeValueBlueZ::UUID: |
+ // Fall through. |
+ case bluez::BluetoothServiceAttributeValueBlueZ::STRING: |
+ // Fall through. |
+ case bluez::BluetoothServiceAttributeValueBlueZ::URL: { |
+ std::string str; |
+ if (!struct_reader->PopVariantOfString(&str)) |
+ return nullptr; |
+ value = base::MakeUnique<base::StringValue>(str); |
+ break; |
+ } |
+ case bluez::BluetoothServiceAttributeValueBlueZ::BOOL: { |
+ bool b; |
+ if (!struct_reader->PopVariantOfBool(&b)) |
+ return nullptr; |
+ value = base::MakeUnique<base::FundamentalValue>(b); |
+ break; |
+ } |
+ case bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE: { |
+ dbus::MessageReader variant_reader(nullptr); |
+ if (!struct_reader->PopVariant(&variant_reader)) |
+ return nullptr; |
+ dbus::MessageReader array_reader(nullptr); |
+ if (!variant_reader.PopArray(&array_reader)) |
+ return nullptr; |
+ std::unique_ptr<BluetoothServiceAttributeValueBlueZ::Sequence> sequence = |
+ base::MakeUnique<BluetoothServiceAttributeValueBlueZ::Sequence>(); |
+ while (array_reader.HasMoreData()) { |
+ dbus::MessageReader sequence_element_struct_reader(nullptr); |
+ if (!array_reader.PopStruct(&sequence_element_struct_reader)) |
+ return nullptr; |
+ std::unique_ptr<BluetoothServiceAttributeValueBlueZ> attribute_value = |
+ ReadAttributeValue(&sequence_element_struct_reader); |
+ if (!attribute_value) |
+ return nullptr; |
+ sequence->emplace_back(*attribute_value); |
+ } |
+ return base::MakeUnique<BluetoothServiceAttributeValueBlueZ>( |
+ std::move(sequence)); |
+ break; |
xiyuan
2016/06/29 22:43:08
nit: no "break" since we "return" ?
rkc
2016/06/30 20:02:24
Done.
|
+ } |
+ } |
+ return base::MakeUnique<BluetoothServiceAttributeValueBlueZ>( |
+ type, size, std::move(value)); |
+} |
+ |
+std::unique_ptr<BluetoothServiceRecordBlueZ> ReadRecord( |
+ dbus::MessageReader* array_reader) { |
+ std::unique_ptr<BluetoothServiceRecordBlueZ> record = |
+ base::MakeUnique<BluetoothServiceRecordBlueZ>(); |
+ while (array_reader->HasMoreData()) { |
+ dbus::MessageReader dict_entry_reader(nullptr); |
+ if (!array_reader->PopDictEntry(&dict_entry_reader)) |
+ return nullptr; |
+ uint16_t id; |
+ if (!dict_entry_reader.PopUint16(&id)) |
+ return nullptr; |
+ dbus::MessageReader struct_reader(nullptr); |
+ if (!dict_entry_reader.PopStruct(&struct_reader)) |
+ return nullptr; |
+ std::unique_ptr<BluetoothServiceAttributeValueBlueZ> attribute_value = |
+ ReadAttributeValue(&struct_reader); |
+ if (!attribute_value) |
+ return nullptr; |
+ record->AddRecordEntry(id, *attribute_value); |
+ } |
+ // return std::move(record); |
+ return record; |
+} |
+ |
+bool ReadRecordsFromMessage(dbus::MessageReader* reader, |
+ BluetoothDeviceClient::ServiceRecordList* records) { |
+ dbus::MessageReader array_reader(nullptr); |
+ if (!reader->PopArray(&array_reader)) { |
+ return false; |
+ LOG(ERROR) << "Arguments for GetConnInfo invalid."; |
+ } |
+ while (array_reader.HasMoreData()) { |
+ dbus::MessageReader nested_array_reader(nullptr); |
+ if (!array_reader.PopArray(&nested_array_reader)) |
+ return false; |
+ std::unique_ptr<BluetoothServiceRecordBlueZ> record = |
+ ReadRecord(&nested_array_reader); |
+ if (!record) |
+ return false; |
+ records->emplace_back(*record); |
+ } |
+ return true; |
+} |
+ |
} // namespace |
const char BluetoothDeviceClient::kNoResponseError[] = |
@@ -281,6 +427,26 @@ class BluetoothDeviceClientImpl : public BluetoothDeviceClient, |
weak_ptr_factory_.GetWeakPtr(), error_callback)); |
} |
+ void GetServiceRecords(const dbus::ObjectPath& object_path, |
+ const ServiceRecordsCallback& callback, |
+ const ErrorCallback& error_callback) override { |
+ dbus::MethodCall method_call(bluetooth_device::kBluetoothDeviceInterface, |
+ bluetooth_device::kGetServiceRecords); |
+ |
+ dbus::ObjectProxy* object_proxy = |
+ object_manager_->GetObjectProxy(object_path); |
+ if (!object_proxy) { |
+ error_callback.Run(kUnknownDeviceError, ""); |
+ return; |
+ } |
+ object_proxy->CallMethodWithErrorCallback( |
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
+ base::Bind(&BluetoothDeviceClientImpl::OnGetServiceRecordsSuccess, |
+ weak_ptr_factory_.GetWeakPtr(), callback), |
+ base::Bind(&BluetoothDeviceClientImpl::OnError, |
+ weak_ptr_factory_.GetWeakPtr(), error_callback)); |
+ } |
+ |
protected: |
void Init(dbus::Bus* bus) override { |
object_manager_ = bus->GetObjectManager( |
@@ -344,6 +510,23 @@ class BluetoothDeviceClientImpl : public BluetoothDeviceClient, |
callback.Run(rssi, transmit_power, max_transmit_power); |
} |
+ void OnGetServiceRecordsSuccess(const ServiceRecordsCallback& callback, |
+ dbus::Response* response) { |
+ ServiceRecordList records; |
+ if (!response) { |
+ LOG(ERROR) << "GetServiceRecords succeeded, but no response received."; |
+ callback.Run(records); |
+ return; |
+ } |
+ |
+ dbus::MessageReader reader(response); |
+ if (!ReadRecordsFromMessage(&reader, &records)) { |
+ callback.Run(ServiceRecordList()); |
+ } |
+ |
+ callback.Run(records); |
+ } |
+ |
// Called when a response for a failed method call is received. |
void OnError(const ErrorCallback& error_callback, |
dbus::ErrorResponse* response) { |