Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Unified Diff: components/arc/bluetooth/arc_bluetooth_bridge.cc

Issue 2104043002: arc: bluetooth: Implement Gatt Server add/delete/start/stop service (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gs1
Patch Set: rebase Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/arc/bluetooth/arc_bluetooth_bridge.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « components/arc/bluetooth/arc_bluetooth_bridge.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698