CHECK(!pending_decl_);
CHECK(!pending_end_decl_cb_);
- // Calculate the instance ID for this service by searching through the handle
- // map to see how many occurrences of the same service UUID we find.
- int inst_id = 0;
- for (const auto& iter : handle_map_) {
- const GattIdentifier* gatt_id = &iter.first;
-
- if (!gatt_id->IsService())
- continue;
-
- if (gatt_id->service_uuid() == uuid)
- ++inst_id;
- }
-
- // Pass empty string for the address as this is a local service.
- auto service_id = GattIdentifier::CreateServiceId(
- "", inst_id, uuid, is_primary);
+ auto service_id = GetIdForService(uuid, is_primary);
+ CHECK(service_id);
// Pass 0 for permissions and properties as this is a service decl.
AttributeEntry entry(
return nullptr;
}
- // Calculate the instance ID for this characteristic by searching through the
- // pending entries.
- int inst_id = 0;
- for (const auto& entry : pending_decl_->attributes) {
- const GattIdentifier* gatt_id = &entry.id;
-
- if (!gatt_id->IsCharacteristic())
- continue;
-
- if (gatt_id->characteristic_uuid() == uuid)
- ++inst_id;
+ if (pending_end_decl_cb_) {
+ LOG(ERROR) << "EndServiceDeclaration in progress, cannot modify service";
+ return nullptr;
}
- CHECK(pending_decl_->service_id.IsService());
-
- auto char_id = GattIdentifier::CreateCharacteristicId(
- inst_id, uuid, pending_decl_->service_id);
-
+ auto char_id = GetIdForCharacteristic(uuid);
+ CHECK(char_id);
AttributeEntry entry(*char_id, properties, permissions);
// 2 handles for the characteristic declaration and the value attributes.
return char_id;
}
+std::unique_ptr<GattIdentifier> GattServer::AddDescriptor(
+ const UUID& uuid, int permissions) {
+ VLOG(1) << __func__ << " server_if: " << server_if_
+ << " - UUID: " << uuid.ToString()
+ << ", permissions: " << permissions;
+ lock_guard<mutex> lock(mutex_);
+
+ if (!pending_decl_) {
+ LOG(ERROR) << "Service declaration not begun";
+ return nullptr;
+ }
+
+ if (pending_end_decl_cb_) {
+ LOG(ERROR) << "EndServiceDeclaration in progress, cannot modify service";
+ return nullptr;
+ }
+
+ auto desc_id = GetIdForDescriptor(uuid);
+ if (!desc_id)
+ return nullptr;
+
+ AttributeEntry entry(*desc_id, kCharacteristicPropertyNone, permissions);
+
+ // 1 handle for the descriptor attribute.
+ pending_decl_->num_handles += 1;
+ pending_decl_->attributes.push_back(entry);
+
+ return desc_id;
+}
+
bool GattServer::EndServiceDeclaration(const ResultCallback& callback) {
VLOG(1) << __func__ << " server_if: " << server_if_;
lock_guard<mutex> lock(mutex_);
return true;
}
+std::unique_ptr<GattIdentifier> GattServer::GetIdForService(
+ const UUID& uuid, bool is_primary) {
+ // Calculate the instance ID for this service by searching through the handle
+ // map to see how many occurrences of the same service UUID we find.
+ int inst_id = 0;
+ for (const auto& iter : handle_map_) {
+ const GattIdentifier* gatt_id = &iter.first;
+
+ if (!gatt_id->IsService())
+ continue;
+
+ if (gatt_id->service_uuid() == uuid)
+ ++inst_id;
+ }
+
+ // Pass empty string for the address as this is a local service.
+ return GattIdentifier::CreateServiceId("", inst_id, uuid, is_primary);
+}
+
+std::unique_ptr<GattIdentifier> GattServer::GetIdForCharacteristic(
+ const UUID& uuid) {
+ CHECK(pending_decl_);
+
+ // Calculate the instance ID for this characteristic by searching through the
+ // pending entries.
+ int inst_id = 0;
+ for (const auto& entry : pending_decl_->attributes) {
+ const GattIdentifier& gatt_id = entry.id;
+
+ if (!gatt_id.IsCharacteristic())
+ continue;
+
+ if (gatt_id.characteristic_uuid() == uuid)
+ ++inst_id;
+ }
+
+ CHECK(pending_decl_->service_id.IsService());
+
+ return GattIdentifier::CreateCharacteristicId(
+ inst_id, uuid, pending_decl_->service_id);
+}
+
+std::unique_ptr<GattIdentifier> GattServer::GetIdForDescriptor(
+ const UUID& uuid) {
+ CHECK(pending_decl_);
+
+ // Calculate the instance ID for this descriptor by searching through the
+ // pending entries. We iterate in reverse until we find a characteristic
+ // entry.
+ CHECK(!pending_decl_->attributes.empty());
+ int inst_id = 0;
+ bool char_found = false;
+ GattIdentifier char_id;
+ for (auto iter = pending_decl_->attributes.end() - 1;
+ iter != pending_decl_->attributes.begin(); // Begin is always a service
+ --iter) {
+ const GattIdentifier& gatt_id = iter->id;
+
+ if (gatt_id.IsCharacteristic()) {
+ // Found the owning characteristic.
+ char_found = true;
+ char_id = gatt_id;
+ break;
+ }
+
+ if (!gatt_id.IsDescriptor()) {
+ // A descriptor must be preceded by a descriptor or a characteristic.
+ LOG(ERROR) << "Descriptors must come directly after a characteristic or "
+ << "another descriptor.";
+ return nullptr;
+ }
+
+ if (gatt_id.descriptor_uuid() == uuid)
+ ++inst_id;
+ }
+
+ if (!char_found) {
+ LOG(ERROR) << "No characteristic found to add the descriptor to.";
+ return nullptr;
+ }
+
+ return GattIdentifier::CreateDescriptorId(inst_id, uuid, char_id);
+}
+
void GattServer::ServiceAddedCallback(
hal::BluetoothGattInterface* gatt_iface,
int status, int server_if,
HandleNextEntry(gatt_iface);
}
+void GattServer::DescriptorAddedCallback(
+ hal::BluetoothGattInterface* gatt_iface,
+ int status, int server_if,
+ const bt_uuid_t& uuid,
+ int service_handle,
+ int desc_handle) {
+ lock_guard<mutex> lock(mutex_);
+
+ if (server_if != server_if_)
+ return;
+
+ CHECK(pending_decl_);
+ CHECK(pending_decl_->service_handle == service_handle);
+ CHECK(pending_id_);
+ CHECK(pending_id_->IsDescriptor());
+ CHECK(pending_id_->descriptor_uuid() == UUID(uuid));
+
+ VLOG(1) << __func__ << " - status: " << status
+ << " server_if: " << server_if
+ << " service_handle: " << service_handle
+ << " desc_handle: " << desc_handle;
+
+ if (status != BT_STATUS_SUCCESS) {
+ NotifyEndCallbackAndClearData(static_cast<BLEStatus>(status),
+ pending_decl_->service_id);
+ return;
+ }
+
+ // Add this to the handle map and contiue.
+ pending_handle_map_[*pending_id_] = desc_handle;
+ HandleNextEntry(gatt_iface);
+}
+
void GattServer::ServiceStartedCallback(
hal::BluetoothGattInterface* gatt_iface,
int status, int server_if,
}
pending_id_.reset(new GattIdentifier(next_entry->id));
+ return;
+ }
+
+ if (next_entry->id.IsDescriptor()) {
+ bt_uuid_t desc_uuid = next_entry->id.descriptor_uuid().GetBlueDroid();
+ bt_status_t status = gatt_iface->GetServerHALInterface()->
+ add_descriptor(
+ server_if_,
+ pending_decl_->service_handle,
+ &desc_uuid,
+ next_entry->permissions);
+ // Terminate the procedure in the case of an error.
+ if (status != BT_STATUS_SUCCESS) {
+ NotifyEndCallbackAndClearData(static_cast<BLEStatus>(status),
+ pending_decl_->service_id);
+ return;
+ }
+
+ pending_id_.reset(new GattIdentifier(next_entry->id));
return;
}
// Inserts a new characteristic definition into a previously begun service
// declaration. Returns the assigned identifier for the characteristic, or
- // nullptr in the case of an error.
+ // nullptr if a service declaration wasn't begun or a call to
+ // EndServiceDeclaration is still in progress.
std::unique_ptr<GattIdentifier> AddCharacteristic(
const UUID& uuid, int properties, int permissions);
+ // Inserts a new descriptor definition into a previous begun service
+ // declaration. Returns the assigned identifier for the descriptor, or
+ // nullptr if a service declaration wasn't begun, a call to
+ // EndServiceDeclaration is still in progress, or a characteristic definition
+ // doesn't properly precede this definition.
+ std::unique_ptr<GattIdentifier> AddDescriptor(
+ const UUID& uuid, int permissions);
+
// Ends a previously started service declaration. This method immediately
// returns false if a service declaration hasn't been started. Otherwise,
// |callback| will be called asynchronously with the result of the operation.
// obtained from the factory.
GattServer(const UUID& uuid, int server_if);
+ // Returns a GattIdentifier for the attribute with the given UUID within the
+ // current pending service declaration.
+ std::unique_ptr<GattIdentifier> GetIdForService(const UUID& uuid,
+ bool is_primary);
+ std::unique_ptr<GattIdentifier> GetIdForCharacteristic(const UUID& uuid);
+ std::unique_ptr<GattIdentifier> GetIdForDescriptor(const UUID& uuid);
+
// hal::BluetoothGattInterface::ServerObserver overrides:
void ServiceAddedCallback(
hal::BluetoothGattInterface* gatt_iface,
const bt_uuid_t& uuid,
int service_handle,
int char_handle) override;
+ void DescriptorAddedCallback(
+ hal::BluetoothGattInterface* gatt_iface,
+ int status, int server_if,
+ const bt_uuid_t& uuid,
+ int service_handle,
+ int desc_handle) override;
void ServiceStartedCallback(
hal::BluetoothGattInterface* gatt_iface,
int status, int server_if,
g_interface, status, server_if, *uuid, srvc_handle, char_handle));
}
+void DescriptorAddedCallback(
+ int status, int server_if,
+ bt_uuid_t* uuid,
+ int srvc_handle,
+ int desc_handle) {
+ lock_guard<mutex> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
+ << " srvc_handle: " << srvc_handle << " desc_handle: " << desc_handle;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ if (!uuid) {
+ LOG(WARNING) << "|uuid| is NULL; ignoring DescriptorAddedCallback";
+ return;
+ }
+
+ FOR_EACH_SERVER_OBSERVER(DescriptorAddedCallback(
+ g_interface, status, server_if, *uuid, srvc_handle, desc_handle));
+}
+
void ServiceStartedCallback(int status, int server_if, int srvc_handle) {
lock_guard<mutex> lock(g_instance_lock);
VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
ServiceAddedCallback,
nullptr, // included_service_added_cb,
CharacteristicAddedCallback,
- nullptr, // descriptor_added_cb,
+ DescriptorAddedCallback,
ServiceStartedCallback,
ServiceStoppedCallback,
nullptr, // service_deleted_cb,
// Do nothing.
}
+void BluetoothGattInterface::ServerObserver::DescriptorAddedCallback(
+ BluetoothGattInterface* /* gatt_iface */,
+ int /* status */,
+ int /* server_if */,
+ const bt_uuid_t& /* uuid */,
+ int /* srvc_handle */,
+ int /* desc_handle */) {
+ // Do nothing.
+}
+
void BluetoothGattInterface::ServerObserver::ServiceStartedCallback(
BluetoothGattInterface* /* gatt_iface */,
int /* status */,
int srvc_handle,
int char_handle);
+ virtual void DescriptorAddedCallback(
+ BluetoothGattInterface* gatt_iface,
+ int status, int server_if,
+ const bt_uuid_t& uuid,
+ int srvc_handle,
+ int desc_handle);
+
virtual void ServiceStartedCallback(
BluetoothGattInterface* gatt_iface,
int status, int server_if,
return BT_STATUS_FAIL;
}
+bt_status_t FakeAddDescriptor(int server_if, int srvc_handle,
+ bt_uuid_t* uuid,
+ int permissions) {
+ if (g_server_handler)
+ return g_server_handler->AddDescriptor(
+ server_if, srvc_handle, uuid, permissions);
+
+ return BT_STATUS_FAIL;
+}
+
bt_status_t FakeStartService(
int server_if, int srvc_handle, int transport) {
if (g_server_handler)
FakeAddService,
nullptr, // add_included_service
FakeAddCharacteristic,
- nullptr, // add_descriptor
+ FakeAddDescriptor,
FakeStartService,
nullptr, // stop_service
FakeDeleteService,
this, status, server_if, uuid, srvc_handle, char_handle));
}
+void FakeBluetoothGattInterface::NotifyDescriptorAddedCallback(
+ int status, int server_if,
+ const bt_uuid_t& uuid,
+ int srvc_handle, int desc_handle) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ DescriptorAddedCallback(
+ this, status, server_if, uuid, srvc_handle, desc_handle));
+}
+
void FakeBluetoothGattInterface::NotifyServiceStartedCallback(
int status, int server_if, int srvc_handle) {
FOR_EACH_OBSERVER(
virtual bt_status_t AddCharacteristic(int server_if, int srvc_handle,
bt_uuid_t *uuid,
int properties, int permissions) = 0;
+ virtual bt_status_t AddDescriptor(int server_if, int srvc_handle,
+ bt_uuid_t* uuid,
+ int permissions) = 0;
virtual bt_status_t StartService(
int server_if, int srvc_handle, int transport) = 0;
virtual bt_status_t DeleteService(int server_if, int srvc_handle) = 0;
void NotifyCharacteristicAddedCallback(int status, int server_if,
const bt_uuid_t& uuid,
int srvc_handle, int char_handle);
+ void NotifyDescriptorAddedCallback(int status, int server_if,
+ const bt_uuid_t& uuid,
+ int srvc_handle, int desc_handle);
void NotifyServiceStartedCallback(int status, int server_if, int srvc_handle);
// BluetoothGattInterface overrides:
return android::NO_ERROR;
}
+ case ADD_DESCRIPTOR_TRANSACTION: {
+ int server_if = data.readInt32();
+ auto uuid = CreateUUIDFromParcel(data);
+ CHECK(uuid);
+ int permissions = data.readInt32();
+
+ std::unique_ptr<bluetooth::GattIdentifier> out_id;
+ bool result = AddDescriptor(server_if, *uuid, permissions, &out_id);
+
+ reply->writeInt32(result);
+
+ if (result) {
+ CHECK(out_id);
+ WriteGattIdentifierToParcel(*out_id, reply);
+ }
+
+ return android::NO_ERROR;
+ }
case END_SERVICE_DECLARATION_TRANSACTION: {
int server_if = data.readInt32();
bool result = EndServiceDeclaration(server_if);
return result;
}
+bool BpBluetoothGattServer::AddDescriptor(
+ int server_if, const bluetooth::UUID& uuid, int permissions,
+ std::unique_ptr<bluetooth::GattIdentifier>* out_id) {
+ CHECK(out_id);
+ Parcel data, reply;
+
+ data.writeInterfaceToken(IBluetoothGattServer::getInterfaceDescriptor());
+ data.writeInt32(server_if);
+ WriteUUIDToParcel(uuid, &data);
+ data.writeInt32(permissions);
+
+ remote()->transact(IBluetoothGattServer::ADD_DESCRIPTOR_TRANSACTION,
+ data, &reply);
+
+ bool result = reply.readInt32();
+ if (result)
+ *out_id = CreateGattIdentifierFromParcel(reply);
+
+ return result;
+}
+
bool BpBluetoothGattServer::EndServiceDeclaration(int server_if) {
Parcel data, reply;
int server_if, const bluetooth::UUID& uuid,
int properties, int permissions,
std::unique_ptr<bluetooth::GattIdentifier>* out_id) = 0;
+ virtual bool AddDescriptor(
+ int server_if, const bluetooth::UUID& uuid, int permissions,
+ std::unique_ptr<bluetooth::GattIdentifier>* out_id) = 0;
virtual bool EndServiceDeclaration(int server_if) = 0;
// TODO(armansito): Complete the API definition.
int server_if, const bluetooth::UUID& uuid,
int properties, int permissions,
std::unique_ptr<bluetooth::GattIdentifier>* out_id) override;
+ bool AddDescriptor(
+ int server_if, const bluetooth::UUID& uuid, int permissions,
+ std::unique_ptr<bluetooth::GattIdentifier>* out_id) override;
bool EndServiceDeclaration(int server_if) override;
private:
return true;
}
+bool BluetoothGattServerBinderServer::AddDescriptor(
+ int server_if, const bluetooth::UUID& uuid, int permissions,
+ std::unique_ptr<bluetooth::GattIdentifier>* out_id) {
+ VLOG(2) << __func__;
+ CHECK(out_id);
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_server = GetGattServer(server_if);
+ if (!gatt_server) {
+ LOG(ERROR) << "Unknown server_if: " << server_if;
+ return false;
+ }
+
+ auto desc_id = gatt_server->AddDescriptor(uuid, permissions);
+ if (!desc_id) {
+ LOG(ERROR) << "Failed to add descriptor - server_if: "
+ << server_if << " UUID: " << uuid.ToString();
+ return false;
+ }
+
+ out_id->swap(desc_id);
+
+ return true;
+}
+
bool BluetoothGattServerBinderServer::EndServiceDeclaration(int server_if) {
VLOG(2) << __func__;
std::lock_guard<std::mutex> lock(*maps_lock());
int server_if, const bluetooth::UUID& uuid,
int properties, int permissions,
std::unique_ptr<bluetooth::GattIdentifier>* out_id) override;
+ bool AddDescriptor(
+ int server_if, const bluetooth::UUID& uuid, int permissions,
+ std::unique_ptr<bluetooth::GattIdentifier>* out_id) override;
bool EndServiceDeclaration(int server_if) override;
private:
MOCK_METHOD1(UnregisterServer, bt_status_t(int));
MOCK_METHOD3(AddService, bt_status_t(int, btgatt_srvc_id_t*, int));
MOCK_METHOD5(AddCharacteristic, bt_status_t(int, int, bt_uuid_t*, int, int));
+ MOCK_METHOD4(AddDescriptor, bt_status_t(int, int, bt_uuid_t*, int));
MOCK_METHOD3(StartService, bt_status_t(int, int, int));
MOCK_METHOD2(DeleteService, bt_status_t(int, int));
int char_handle1 = 0x0004;
EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback));
+ // Cannot add any more characteristics while EndServiceDeclaration is in
+ // progress.
+ EXPECT_EQ(nullptr, gatt_server_->AddCharacteristic(char_uuid, props, perms));
+
EXPECT_CALL(*mock_handler_, AddCharacteristic(_, _, _, _, _))
.Times(8)
.WillOnce(Return(BT_STATUS_FAIL)) // char_id0 - try 1
EXPECT_EQ(4, cb_count);
}
+TEST_F(GattServerPostRegisterTest, AddDescriptor) {
+ // Set up some values for UUIDs, permissions, and properties.
+ const UUID service_uuid = UUID::GetRandom();
+ const UUID char_uuid0 = UUID::GetRandom();
+ const UUID char_uuid1 = UUID::GetRandom();
+ const UUID desc_uuid = UUID::GetRandom();
+ bt_uuid_t hal_char_uuid0 = char_uuid0.GetBlueDroid();
+ bt_uuid_t hal_char_uuid1 = char_uuid1.GetBlueDroid();
+ bt_uuid_t hal_desc_uuid = desc_uuid.GetBlueDroid();
+ const int props = bluetooth::kCharacteristicPropertyRead |
+ bluetooth::kCharacteristicPropertyNotify;
+ const int perms = kAttributePermissionReadEncrypted;
+
+ // Service declaration not started.
+ EXPECT_EQ(nullptr, gatt_server_->AddDescriptor(desc_uuid, perms));
+
+ // Start a service declaration.
+ auto service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true);
+ btgatt_srvc_id_t hal_id;
+ hal::GetHALServiceId(*service_id, &hal_id);
+
+ // No characteristic was inserted.
+ EXPECT_EQ(nullptr, gatt_server_->AddDescriptor(desc_uuid, perms));
+
+ // Add two characeristics.
+ auto char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms);
+ auto char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms);
+
+ // Add a descriptor.
+ auto desc_id = gatt_server_->AddDescriptor(desc_uuid, perms);
+ EXPECT_NE(nullptr, desc_id);
+ EXPECT_TRUE(desc_id->IsDescriptor());
+ EXPECT_TRUE(*desc_id->GetOwningCharacteristicId() == *char_id1);
+ EXPECT_TRUE(*desc_id->GetOwningServiceId() == *service_id);
+
+ // Add a second descriptor with the same UUID.
+ auto desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms);
+ EXPECT_NE(nullptr, desc_id1);
+ EXPECT_TRUE(*desc_id1 != *desc_id);
+ EXPECT_TRUE(desc_id1->IsDescriptor());
+ EXPECT_TRUE(*desc_id1->GetOwningCharacteristicId() == *char_id1);
+ EXPECT_TRUE(*desc_id1->GetOwningServiceId() == *service_id);
+
+ // Expect calls for 7 handles.
+ EXPECT_CALL(*mock_handler_, AddService(kDefaultServerId, _, 7))
+ .WillRepeatedly(Return(BT_STATUS_SUCCESS));
+ EXPECT_CALL(*mock_handler_, AddCharacteristic(_, _, _, _, _))
+ .WillRepeatedly(Return(BT_STATUS_SUCCESS));
+
+ GattIdentifier cb_id;
+ BLEStatus cb_status;
+ int cb_count = 0;
+ auto callback = [&](BLEStatus in_status, const GattIdentifier& in_id) {
+ cb_id = in_id;
+ cb_status = in_status;
+ cb_count++;
+ };
+
+ int srvc_handle = 0x0001;
+ int char_handle0 = 0x0002;
+ int char_handle1 = 0x0004;
+ int desc_handle0 = 0x0005;
+ int desc_handle1 = 0x0006;
+
+ EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback));
+
+ // Cannot add any more descriptors while EndServiceDeclaration is in progress.
+ EXPECT_EQ(nullptr, gatt_server_->AddDescriptor(desc_uuid, perms));
+
+ fake_hal_gatt_iface_->NotifyServiceAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle);
+ EXPECT_EQ(0, cb_count);
+
+ EXPECT_CALL(*mock_handler_, AddDescriptor(_, _, _, _))
+ .Times(8)
+ .WillOnce(Return(BT_STATUS_FAIL)) // desc_id0 - try 1
+ .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 2
+ .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 3
+ .WillOnce(Return(BT_STATUS_FAIL)) // desc_id1 - try 3
+ .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 4
+ .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id1 - try 4
+ .WillOnce(Return(BT_STATUS_SUCCESS)) // desc_id0 - try 5
+ .WillOnce(Return(BT_STATUS_SUCCESS)); // desc_id1 - try 5
+
+ // Notify success for both characteristics. First descriptor call will fail.
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0,
+ srvc_handle, char_handle0);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1,
+ srvc_handle, char_handle1);
+ EXPECT_EQ(1, cb_count);
+ EXPECT_NE(BLE_STATUS_SUCCESS, cb_status);
+ EXPECT_TRUE(cb_id == *service_id);
+
+ // Restart (try 2)
+ cb_count = 0;
+ service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true);
+ hal::GetHALServiceId(*service_id, &hal_id);
+ char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms);
+ char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms);
+ desc_id = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id);
+ desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id1);
+ EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback));
+
+ fake_hal_gatt_iface_->NotifyServiceAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0,
+ srvc_handle, char_handle0);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1,
+ srvc_handle, char_handle1);
+ EXPECT_EQ(0, cb_count);
+
+ // Notify failure for first descriptor.
+ fake_hal_gatt_iface_->NotifyDescriptorAddedCallback(
+ BT_STATUS_FAIL, kDefaultServerId, hal_desc_uuid,
+ srvc_handle, desc_handle0);
+ EXPECT_EQ(1, cb_count);
+ EXPECT_NE(BLE_STATUS_SUCCESS, cb_status);
+ EXPECT_TRUE(cb_id == *service_id);
+
+ // Restart (try 3)
+ cb_count = 0;
+ service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true);
+ hal::GetHALServiceId(*service_id, &hal_id);
+ char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms);
+ char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms);
+ desc_id = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id);
+ desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id1);
+ EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback));
+
+ fake_hal_gatt_iface_->NotifyServiceAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0,
+ srvc_handle, char_handle0);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1,
+ srvc_handle, char_handle1);
+ EXPECT_EQ(0, cb_count);
+
+ // Notify success for first descriptor; the second descriptor will fail
+ // immediately.
+ fake_hal_gatt_iface_->NotifyDescriptorAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid,
+ srvc_handle, desc_handle0);
+ EXPECT_EQ(1, cb_count);
+ EXPECT_NE(BLE_STATUS_SUCCESS, cb_status);
+ EXPECT_TRUE(cb_id == *service_id);
+
+ // Restart (try 4)
+ cb_count = 0;
+ service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true);
+ hal::GetHALServiceId(*service_id, &hal_id);
+ char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms);
+ char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms);
+ desc_id = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id);
+ desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id1);
+ EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback));
+
+ fake_hal_gatt_iface_->NotifyServiceAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0,
+ srvc_handle, char_handle0);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1,
+ srvc_handle, char_handle1);
+ EXPECT_EQ(0, cb_count);
+
+ // Notify success for first first descriptor and failure for second
+ // descriptor.
+ fake_hal_gatt_iface_->NotifyDescriptorAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid,
+ srvc_handle, desc_handle0);
+ EXPECT_EQ(0, cb_count);
+
+ fake_hal_gatt_iface_->NotifyDescriptorAddedCallback(
+ BT_STATUS_FAIL, kDefaultServerId, hal_desc_uuid,
+ srvc_handle, desc_handle1);
+ EXPECT_EQ(1, cb_count);
+ EXPECT_NE(BLE_STATUS_SUCCESS, cb_status);
+ EXPECT_TRUE(cb_id == *service_id);
+
+ // Restart (try 5)
+ cb_count = 0;
+ service_id = gatt_server_->BeginServiceDeclaration(service_uuid, true);
+ hal::GetHALServiceId(*service_id, &hal_id);
+ char_id0 = gatt_server_->AddCharacteristic(char_uuid0, props, perms);
+ char_id1 = gatt_server_->AddCharacteristic(char_uuid1, props, perms);
+ desc_id = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id);
+ desc_id1 = gatt_server_->AddDescriptor(desc_uuid, perms);
+ ASSERT_NE(nullptr, desc_id1);
+ EXPECT_TRUE(gatt_server_->EndServiceDeclaration(callback));
+
+ fake_hal_gatt_iface_->NotifyServiceAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_id, srvc_handle);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid0,
+ srvc_handle, char_handle0);
+ EXPECT_EQ(0, cb_count);
+ fake_hal_gatt_iface_->NotifyCharacteristicAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_char_uuid1,
+ srvc_handle, char_handle1);
+ EXPECT_EQ(0, cb_count);
+
+ // Notify success for both descriptors.
+ fake_hal_gatt_iface_->NotifyDescriptorAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid,
+ srvc_handle, desc_handle0);
+ EXPECT_EQ(0, cb_count);
+
+ // The second descriptor callback should trigger the end routine.
+ EXPECT_CALL(*mock_handler_, StartService(kDefaultServerId, srvc_handle, _))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ fake_hal_gatt_iface_->NotifyDescriptorAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_desc_uuid,
+ srvc_handle, desc_handle1);
+ EXPECT_EQ(0, cb_count);
+}
+
} // namespace
} // namespace bluetooth