Chromium Code Reviews| Index: components/arc/bluetooth/arc_bluetooth_bridge.cc |
| diff --git a/components/arc/bluetooth/arc_bluetooth_bridge.cc b/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| index 7eaf57aa1dd55e8300096956b7fc9de23c9553f3..d9a373b1388e17da362347d78e7328d4325ab956 100644 |
| --- a/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| +++ b/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| @@ -60,6 +60,83 @@ constexpr uint32_t kGattWritePermission = |
| BluetoothGattCharacteristic::Permission::PERMISSION_WRITE_ENCRYPTED | |
| BluetoothGattCharacteristic::Permission:: |
| PERMISSION_WRITE_ENCRYPTED_AUTHENTICATED; |
| +constexpr int32_t kInvalidGattAttributeHandle = -1; |
| + |
| +using GattStatusCallback = |
| + base::Callback<void(arc::mojom::BluetoothGattStatus)>; |
| +using GattReadCallback = |
| + base::Callback<void(arc::mojom::BluetoothGattValuePtr)>; |
| + |
| +// Example of identifier: /org/bluez/hci0/dev_E0_CF_65_8C_86_1A/service001a |
| +// We want to convert last digit of the identifier to int in base 16 |
| +int ConvertGattIdentifierToId(const std::string identifier) { |
| + return std::stoi(identifier.substr(identifier.size() - 4), nullptr, 16); |
| +} |
| + |
| +// Create GattDBElement and fill in common data for |
| +// Gatt Service/Characteristic/Descriptor. |
| +template <class RemoteGattAttribute> |
| +arc::mojom::BluetoothGattDBElementPtr CreateGattDBElement( |
| + const arc::mojom::BluetoothGattDBAttributeType type, |
| + const RemoteGattAttribute* gatt_attr) { |
| + arc::mojom::BluetoothGattDBElementPtr element = |
| + arc::mojom::BluetoothGattDBElement::New(); |
| + element->type = type; |
| + element->uuid = arc::mojom::BluetoothUUID::From(gatt_attr->GetUUID()); |
| + element->id = element->attribute_handle = element->start_handle = |
| + element->end_handle = |
| + ConvertGattIdentifierToId(gatt_attr->GetIdentifier()); |
| + element->properties = 0; |
| + return element; |
| +} |
| + |
| +// Find Gatt Service/Characteristic/Descriptor from std::vector using UUID. |
| +template <class RemoteGattAttribute> |
| +RemoteGattAttribute* FindGattAttributeFromUuid( |
| + const std::vector<RemoteGattAttribute*> gatt_attrs, |
|
Luis Héctor Chávez
2016/07/20 23:11:04
should this be a const-reference?
puthik_chromium
2016/07/21 00:05:04
Done.
|
| + const device::BluetoothUUID uuid) { |
| + auto it = std::find_if( |
| + gatt_attrs.begin(), gatt_attrs.end(), |
| + [uuid](RemoteGattAttribute* attr) { return attr->GetUUID() == uuid; }); |
| + if (it == gatt_attrs.end()) |
| + return nullptr; |
| + return *it; |
| +} |
| + |
| +// Common success callback for GATT operations that only need to report |
| +// GattStatus back to Android. |
| +void OnGattOperationDone(const GattStatusCallback& callback) { |
| + callback.Run(arc::mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +// Common error callback for GATT operations that only need to report |
| +// GattStatus back to Android. |
| +void OnGattOperationError(const GattStatusCallback& callback, |
| + BluetoothGattService::GattErrorCode error_code) { |
| + callback.Run(mojo::ConvertTo<arc::mojom::BluetoothGattStatus>(error_code)); |
| +} |
| + |
| +// Common success callback for ReadGattCharacteristic and ReadGattDescriptor |
| +void OnGattReadDone(const GattReadCallback& callback, |
| + const std::vector<uint8_t>& result) { |
| + arc::mojom::BluetoothGattValuePtr gattValue = |
| + arc::mojom::BluetoothGattValue::New(); |
| + gattValue->status = arc::mojom::BluetoothGattStatus::GATT_SUCCESS; |
| + gattValue->value = mojo::Array<uint8_t>::From(result); |
| + callback.Run(std::move(gattValue)); |
| +} |
| + |
| +// Common error callback for ReadGattCharacteristic and ReadGattDescriptor |
| +void OnGattReadError(const GattReadCallback& callback, |
| + BluetoothGattService::GattErrorCode error_code) { |
| + arc::mojom::BluetoothGattValuePtr gattValue = |
| + arc::mojom::BluetoothGattValue::New(); |
| + gattValue->status = |
| + mojo::ConvertTo<arc::mojom::BluetoothGattStatus>(error_code); |
| + gattValue->value = nullptr; |
| + callback.Run(std::move(gattValue)); |
| +} |
| + |
| } // namespace |
| namespace arc { |
| @@ -78,6 +155,8 @@ ArcBluetoothBridge::ArcBluetoothBridge(ArcBridgeService* bridge_service) |
| } |
| ArcBluetoothBridge::~ArcBluetoothBridge() { |
| + DCHECK(CalledOnValidThread()); |
| + |
| arc_bridge_service()->bluetooth()->RemoveObserver(this); |
| if (bluetooth_adapter_) |
| @@ -86,6 +165,8 @@ ArcBluetoothBridge::~ArcBluetoothBridge() { |
| void ArcBluetoothBridge::OnAdapterInitialized( |
| scoped_refptr<BluetoothAdapter> adapter) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| // We can downcast here because we are always running on Chrome OS, and |
| // so our adapter uses BlueZ. |
| bluetooth_adapter_ = |
| @@ -106,6 +187,8 @@ void ArcBluetoothBridge::OnInstanceReady() { |
| void ArcBluetoothBridge::AdapterPresentChanged(BluetoothAdapter* adapter, |
| bool present) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| // If the adapter goes away, remove ourselves as an observer. |
| if (!present && adapter == bluetooth_adapter_) { |
| adapter->RemoveObserver(this); |
| @@ -743,30 +826,6 @@ void ArcBluetoothBridge::StopLEListen(const StopLEListenCallback& callback) { |
| weak_factory_.GetWeakPtr(), callback)); |
| } |
| -// Example of identifier: /org/bluez/hci0/dev_E0_CF_65_8C_86_1A/service001a |
| -// We want to convert last digit of the identifier to int in base 16 |
| -int ArcBluetoothBridge::ConvertGattIdentifierToId( |
| - const std::string identifier) const { |
| - return std::stoi(identifier.substr(identifier.size() - 4), nullptr, 16); |
| -} |
| - |
| -// Create GattDBElement and fill in common data for |
| -// Gatt Service/Characteristic/Descriptor. |
| -template <class T> |
| -mojom::BluetoothGattDBElementPtr ArcBluetoothBridge::CreateGattDBElement( |
| - const mojom::BluetoothGattDBAttributeType type, |
| - const T* gattObject) const { |
| - mojom::BluetoothGattDBElementPtr element = |
| - mojom::BluetoothGattDBElement::New(); |
| - element->type = type; |
| - element->uuid = mojom::BluetoothUUID::From(gattObject->GetUUID()); |
| - element->id = element->attribute_handle = element->start_handle = |
| - element->end_handle = |
| - ConvertGattIdentifierToId(gattObject->GetIdentifier()); |
| - element->properties = 0; |
| - return element; |
| -} |
| - |
| void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) { |
| if (!HasBluetoothInstance()) |
| return; |
| @@ -813,18 +872,6 @@ void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) { |
| std::move(remote_addr), std::move(db)); |
| } |
| -// Find Gatt Service/Characteristic/Descriptor from std::vector from UUID. |
| -template <class T> |
| -T* ArcBluetoothBridge::FindGattObjectFromUuid( |
| - const std::vector<T*> gatt_objs, |
| - const device::BluetoothUUID uuid) const { |
| - auto it = std::find_if(gatt_objs.begin(), gatt_objs.end(), |
| - [&](T* obj) { return obj->GetUUID() == uuid; }); |
| - if (it == gatt_objs.end()) |
| - return nullptr; |
| - return *it; |
| -} |
| - |
| BluetoothRemoteGattCharacteristic* ArcBluetoothBridge::FindGattCharacteristic( |
| mojom::BluetoothAddressPtr remote_addr, |
| mojom::BluetoothGattServiceIDPtr service_id, |
| @@ -839,12 +886,12 @@ BluetoothRemoteGattCharacteristic* ArcBluetoothBridge::FindGattCharacteristic( |
| return nullptr; |
| BluetoothRemoteGattService* service = |
| - FindGattObjectFromUuid<BluetoothRemoteGattService>( |
| + FindGattAttributeFromUuid<BluetoothRemoteGattService>( |
|
Luis Héctor Chávez
2016/07/20 23:11:04
nit: C++ might be able to autodeduce the template
puthik_chromium
2016/07/21 00:05:03
Done.
|
| device->GetGattServices(), service_id->id->uuid.To<BluetoothUUID>()); |
| if (!service) |
| return nullptr; |
| - return FindGattObjectFromUuid<BluetoothRemoteGattCharacteristic>( |
| + return FindGattAttributeFromUuid<BluetoothRemoteGattCharacteristic>( |
| service->GetCharacteristics(), char_id->uuid.To<BluetoothUUID>()); |
| } |
| @@ -858,42 +905,10 @@ BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor( |
| if (!characteristic) |
| return nullptr; |
| - return FindGattObjectFromUuid<BluetoothRemoteGattDescriptor>( |
| + return FindGattAttributeFromUuid<BluetoothRemoteGattDescriptor>( |
| characteristic->GetDescriptors(), desc_id->uuid.To<BluetoothUUID>()); |
| } |
| -// Same callback for both ReadGattCharacteristic and ReadGattDescriptor |
| -void ArcBluetoothBridge::OnGattReadDone( |
| - const GattReadCallback& callback, |
| - const std::vector<uint8_t>& result) const { |
| - mojom::BluetoothGattValuePtr gattValue = mojom::BluetoothGattValue::New(); |
| - gattValue->status = mojom::BluetoothGattStatus::GATT_SUCCESS; |
| - gattValue->value = mojo::Array<uint8_t>::From(result); |
| - callback.Run(std::move(gattValue)); |
| -} |
| - |
| -void ArcBluetoothBridge::OnGattReadError( |
| - const GattReadCallback& callback, |
| - BluetoothGattService::GattErrorCode error_code) const { |
| - mojom::BluetoothGattValuePtr gattValue = mojom::BluetoothGattValue::New(); |
| - gattValue->status = mojo::ConvertTo<mojom::BluetoothGattStatus>(error_code); |
| - gattValue->value = nullptr; |
| - |
| - callback.Run(std::move(gattValue)); |
| -} |
| - |
| -// Same callback for both WriteGattCharacteristic and WriteGattDescriptor |
| -void ArcBluetoothBridge::OnGattWriteDone( |
| - const GattWriteCallback& callback) const { |
| - callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| -} |
| - |
| -void ArcBluetoothBridge::OnGattWriteError( |
| - const GattWriteCallback& callback, |
| - BluetoothGattService::GattErrorCode error_code) const { |
| - callback.Run(mojo::ConvertTo<mojom::BluetoothGattStatus>(error_code)); |
| -} |
| - |
| void ArcBluetoothBridge::ReadGattCharacteristic( |
| mojom::BluetoothAddressPtr remote_addr, |
| mojom::BluetoothGattServiceIDPtr service_id, |
| @@ -905,10 +920,8 @@ void ArcBluetoothBridge::ReadGattCharacteristic( |
| DCHECK(characteristic->GetPermissions() & kGattReadPermission); |
| characteristic->ReadRemoteCharacteristic( |
| - base::Bind(&ArcBluetoothBridge::OnGattReadDone, |
| - weak_factory_.GetWeakPtr(), callback), |
| - base::Bind(&ArcBluetoothBridge::OnGattReadError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + base::Bind(&OnGattReadDone, callback), |
| + base::Bind(&OnGattReadError, callback)); |
| } |
| void ArcBluetoothBridge::WriteGattCharacteristic( |
| @@ -924,10 +937,8 @@ void ArcBluetoothBridge::WriteGattCharacteristic( |
| characteristic->WriteRemoteCharacteristic( |
| value->value.To<std::vector<uint8_t>>(), |
| - base::Bind(&ArcBluetoothBridge::OnGattWriteDone, |
| - weak_factory_.GetWeakPtr(), callback), |
| - base::Bind(&ArcBluetoothBridge::OnGattWriteError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| } |
| void ArcBluetoothBridge::ReadGattDescriptor( |
| @@ -942,11 +953,8 @@ void ArcBluetoothBridge::ReadGattDescriptor( |
| DCHECK(descriptor); |
| DCHECK(descriptor->GetPermissions() & kGattReadPermission); |
| - descriptor->ReadRemoteDescriptor( |
| - base::Bind(&ArcBluetoothBridge::OnGattReadDone, |
| - weak_factory_.GetWeakPtr(), callback), |
| - base::Bind(&ArcBluetoothBridge::OnGattReadError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + descriptor->ReadRemoteDescriptor(base::Bind(&OnGattReadDone, callback), |
| + base::Bind(&OnGattReadError, callback)); |
| } |
| void ArcBluetoothBridge::WriteGattDescriptor( |
| @@ -971,16 +979,14 @@ void ArcBluetoothBridge::WriteGattDescriptor( |
| // TODO(http://crbug.com/622832) |
| if (descriptor->GetUUID() == |
| BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid()) { |
| - OnGattWriteDone(callback); |
| + OnGattOperationDone(callback); |
| return; |
| } |
| descriptor->WriteRemoteDescriptor( |
| value->value.To<std::vector<uint8_t>>(), |
| - base::Bind(&ArcBluetoothBridge::OnGattWriteDone, |
| - weak_factory_.GetWeakPtr(), callback), |
| - base::Bind(&ArcBluetoothBridge::OnGattWriteError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| } |
| void ArcBluetoothBridge::OnGattNotifyStartDone( |
| @@ -991,17 +997,6 @@ void ArcBluetoothBridge::OnGattNotifyStartDone( |
| callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| } |
| -void ArcBluetoothBridge::OnGattNotifyStartError( |
| - const RegisterForGattNotificationCallback& callback, |
| - BluetoothGattService::GattErrorCode error_code) const { |
| - callback.Run(mojo::ConvertTo<mojom::BluetoothGattStatus>(error_code)); |
| -} |
| - |
| -void ArcBluetoothBridge::OnGattNotifyStopDone( |
| - const DeregisterForGattNotificationCallback& callback) const { |
| - callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| -} |
| - |
| void ArcBluetoothBridge::RegisterForGattNotification( |
| mojom::BluetoothAddressPtr remote_addr, |
| mojom::BluetoothGattServiceIDPtr service_id, |
| @@ -1024,8 +1019,7 @@ void ArcBluetoothBridge::RegisterForGattNotification( |
| base::Bind(&ArcBluetoothBridge::OnGattNotifyStartDone, |
| weak_factory_.GetWeakPtr(), callback, |
| characteristic->GetIdentifier()), |
| - base::Bind(&ArcBluetoothBridge::OnGattNotifyStartError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + base::Bind(&OnGattOperationError, callback)); |
| } |
| void ArcBluetoothBridge::DeregisterForGattNotification( |
| @@ -1050,8 +1044,7 @@ void ArcBluetoothBridge::DeregisterForGattNotification( |
| std::unique_ptr<BluetoothGattNotifySession> notify = |
| std::move(notification_session_[char_id_str]); |
| notification_session_.erase(char_id_str); |
| - notify->Stop(base::Bind(&ArcBluetoothBridge::OnGattNotifyStopDone, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + notify->Stop(base::Bind(&OnGattOperationDone, callback)); |
| } |
| void ArcBluetoothBridge::ReadRemoteRssi( |
| @@ -1063,30 +1056,118 @@ void ArcBluetoothBridge::ReadRemoteRssi( |
| callback.Run(rssi); |
| } |
| +template <class LocalGattAttribute> |
| +int32_t ArcBluetoothBridge::CreateGattAttributeHandle( |
| + LocalGattAttribute* gatt_attr) { |
| + DCHECK(CalledOnValidThread()); |
| + if (!gatt_attr) |
| + return kInvalidGattAttributeHandle; |
| + int32_t handle = next_gatt_server_attribute_handle(); |
| + const std::string& identifier = gatt_attr->GetIdentifier(); |
| + gatt_identifier_[handle] = identifier; |
| + return handle; |
| +} |
| + |
| void ArcBluetoothBridge::AddService(mojom::BluetoothGattServiceIDPtr service_id, |
| int32_t num_handles, |
| - const AddServiceCallback& callback) {} |
| + const AddServiceCallback& callback) { |
| + base::WeakPtr<BluetoothLocalGattService> service = |
| + BluetoothLocalGattService::Create( |
| + bluetooth_adapter_.get(), service_id->id->uuid.To<BluetoothUUID>(), |
| + service_id->is_primary, nullptr /*included_service */, |
|
Luis Héctor Chávez
2016/07/20 23:11:04
nit: /* included service */
puthik_chromium
2016/07/21 00:05:04
Done.
|
| + this /* delegate*/); |
| + callback.Run( |
| + CreateGattAttributeHandle<BluetoothLocalGattService>(service.get())); |
|
Luis Héctor Chávez
2016/07/20 23:11:04
This (and all other uses of CreateGattAttributeHan
puthik_chromium
2016/07/21 00:05:04
Done.
|
| +} |
| void ArcBluetoothBridge::AddCharacteristic( |
| int32_t service_handle, |
| mojom::BluetoothUUIDPtr uuid, |
| int32_t properties, |
| int32_t permissions, |
| - const AddCharacteristicCallback& callback) {} |
| + const AddCharacteristicCallback& callback) { |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + base::WeakPtr<BluetoothLocalGattCharacteristic> characteristic = |
| + BluetoothLocalGattCharacteristic::Create( |
| + uuid.To<BluetoothUUID>(), properties, permissions, |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle])); |
| + int32_t characteristic_handle = |
| + CreateGattAttributeHandle<BluetoothLocalGattCharacteristic>( |
| + characteristic.get()); |
| + last_characteristic_[service_handle] = characteristic_handle; |
| + callback.Run(characteristic_handle); |
| +} |
| void ArcBluetoothBridge::AddDescriptor(int32_t service_handle, |
| mojom::BluetoothUUIDPtr uuid, |
| int32_t permissions, |
| - const AddDescriptorCallback& callback) {} |
| + const AddDescriptorCallback& callback) { |
| + // Chrome automatically adds a CCC Descriptor to a characteristic when needed. |
| + // We will generate a bogus handle for Android. |
| + if (uuid.To<BluetoothUUID>() == |
| + BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid()) { |
| + int32_t handle = next_gatt_server_attribute_handle(); |
| + callback.Run(handle); |
| + return; |
| + } |
| + |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + // Since the Android API does not give information about which characteristic |
| + // is the parent of the new descriptor, we assume that it would be the last |
| + // characteristic that was added to the given service. This matches the |
| + // Android framework code at android/bluetooth/BluetoothGattServer.java#594. |
| + // Link: https://goo.gl/cJZl1u |
| + DCHECK(last_characteristic_.find(service_handle) != |
| + last_characteristic_.end()); |
| + int32_t last_characteristic_handle = last_characteristic_[service_handle]; |
| + |
| + DCHECK(gatt_identifier_.find(last_characteristic_handle) != |
| + gatt_identifier_.end()); |
| + BluetoothLocalGattCharacteristic* characteristic = |
| + service->GetCharacteristic(gatt_identifier_[last_characteristic_handle]); |
| + DCHECK(characteristic); |
| + |
| + base::WeakPtr<BluetoothLocalGattDescriptor> descriptor = |
| + BluetoothLocalGattDescriptor::Create(uuid.To<BluetoothUUID>(), |
| + permissions, characteristic); |
| + callback.Run(CreateGattAttributeHandle<BluetoothLocalGattDescriptor>( |
| + descriptor.get())); |
| +} |
| void ArcBluetoothBridge::StartService(int32_t service_handle, |
| - const StartServiceCallback& callback) {} |
| + const StartServiceCallback& callback) { |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + service->Register(base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| +} |
| void ArcBluetoothBridge::StopService(int32_t service_handle, |
| - const StopServiceCallback& callback) {} |
| + const StopServiceCallback& callback) { |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + service->Unregister(base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| +} |
| void ArcBluetoothBridge::DeleteService(int32_t service_handle, |
| - const DeleteServiceCallback& callback) {} |
| + const DeleteServiceCallback& callback) { |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
|
Luis Héctor Chávez
2016/07/20 23:11:04
Just for my peace of mind, can you add thread-chec
puthik_chromium
2016/07/21 00:05:04
Done.
|
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + |
| + service->Delete(); |
| + gatt_identifier_.erase(service_handle); |
| + OnGattOperationDone(callback); |
| +} |
| void ArcBluetoothBridge::SendIndication( |
| int32_t attribute_handle, |
| @@ -1432,4 +1513,8 @@ bool ArcBluetoothBridge::CheckBluetoothInstanceVersion( |
| return false; |
| } |
| +bool ArcBluetoothBridge::CalledOnValidThread() { |
| + return thread_checker_.CalledOnValidThread(); |
| +} |
| + |
| } // namespace arc |