1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "device/bluetooth/bluetooth_remote_gatt_service_win.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/stl_util.h"
13 #include "device/bluetooth/bluetooth_adapter_win.h"
14 #include "device/bluetooth/bluetooth_device_win.h"
15 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h"
16 #include "device/bluetooth/bluetooth_task_manager_win.h"
17
18 namespace device {
19
BluetoothRemoteGattServiceWin(BluetoothDeviceWin * device,base::FilePath service_path,BluetoothUUID service_uuid,uint16_t service_attribute_handle,bool is_primary,BluetoothRemoteGattServiceWin * parent_service,scoped_refptr<base::SequencedTaskRunner> ui_task_runner)20 BluetoothRemoteGattServiceWin::BluetoothRemoteGattServiceWin(
21 BluetoothDeviceWin* device,
22 base::FilePath service_path,
23 BluetoothUUID service_uuid,
24 uint16_t service_attribute_handle,
25 bool is_primary,
26 BluetoothRemoteGattServiceWin* parent_service,
27 scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
28 : device_(device),
29 service_path_(service_path),
30 service_uuid_(service_uuid),
31 service_attribute_handle_(service_attribute_handle),
32 is_primary_(is_primary),
33 parent_service_(parent_service),
34 ui_task_runner_(std::move(ui_task_runner)) {
35 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
36 DCHECK(!service_path_.empty());
37 DCHECK(service_uuid_.IsValid());
38 DCHECK(service_attribute_handle_);
39 DCHECK(device_);
40 if (!is_primary_)
41 DCHECK(parent_service_);
42
43 adapter_ = static_cast<BluetoothAdapterWin*>(device_->GetAdapter());
44 DCHECK(adapter_);
45 task_manager_ = adapter_->GetWinBluetoothTaskManager();
46 DCHECK(task_manager_);
47 service_identifier_ = device_->GetIdentifier() + "/" + service_uuid_.value() +
48 "_" + std::to_string(service_attribute_handle_);
49 Update();
50 }
51
~BluetoothRemoteGattServiceWin()52 BluetoothRemoteGattServiceWin::~BluetoothRemoteGattServiceWin() {
53 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
54
55 ClearIncludedCharacteristics();
56
57 adapter_->NotifyGattServiceRemoved(this);
58 }
59
GetIdentifier() const60 std::string BluetoothRemoteGattServiceWin::GetIdentifier() const {
61 return service_identifier_;
62 }
63
GetUUID() const64 BluetoothUUID BluetoothRemoteGattServiceWin::GetUUID() const {
65 return const_cast<BluetoothUUID&>(service_uuid_);
66 }
67
IsPrimary() const68 bool BluetoothRemoteGattServiceWin::IsPrimary() const {
69 return is_primary_;
70 }
71
GetDevice() const72 BluetoothDevice* BluetoothRemoteGattServiceWin::GetDevice() const {
73 return device_;
74 }
75
76 std::vector<BluetoothRemoteGattService*>
GetIncludedServices() const77 BluetoothRemoteGattServiceWin::GetIncludedServices() const {
78 NOTIMPLEMENTED();
79 // TODO(crbug.com/590008): Needs implementation.
80 return std::vector<BluetoothRemoteGattService*>();
81 }
82
GattCharacteristicDiscoveryComplete(BluetoothRemoteGattCharacteristicWin * characteristic)83 void BluetoothRemoteGattServiceWin::GattCharacteristicDiscoveryComplete(
84 BluetoothRemoteGattCharacteristicWin* characteristic) {
85 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
86 DCHECK(base::Contains(characteristics_, characteristic->GetIdentifier()));
87
88 discovery_completed_included_characteristics_.insert(
89 characteristic->GetIdentifier());
90 SetDiscoveryComplete(characteristics_.size() ==
91 discovery_completed_included_characteristics_.size());
92 adapter_->NotifyGattCharacteristicAdded(characteristic);
93 NotifyGattServiceDiscoveryCompleteIfNecessary();
94 }
95
Update()96 void BluetoothRemoteGattServiceWin::Update() {
97 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
98
99 ++discovery_pending_count_;
100 task_manager_->PostGetGattIncludedCharacteristics(
101 service_path_, service_uuid_, service_attribute_handle_,
102 base::Bind(&BluetoothRemoteGattServiceWin::OnGetIncludedCharacteristics,
103 weak_ptr_factory_.GetWeakPtr()));
104 }
105
OnGetIncludedCharacteristics(std::unique_ptr<BTH_LE_GATT_CHARACTERISTIC> characteristics,uint16_t num,HRESULT hr)106 void BluetoothRemoteGattServiceWin::OnGetIncludedCharacteristics(
107 std::unique_ptr<BTH_LE_GATT_CHARACTERISTIC> characteristics,
108 uint16_t num,
109 HRESULT hr) {
110 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
111
112 if (--discovery_pending_count_ != 0)
113 return;
114
115 UpdateIncludedCharacteristics(characteristics.get(), num);
116 SetDiscoveryComplete(characteristics_.size() ==
117 discovery_completed_included_characteristics_.size());
118
119 // In case there are new included characterisitics that haven't been
120 // discovered yet, observers should be notified once that the discovery of
121 // these characteristics is complete. Hence the discovery complete flag is
122 // reset.
123 if (!IsDiscoveryComplete()) {
124 discovery_complete_notified_ = false;
125 return;
126 }
127
128 adapter_->NotifyGattServiceChanged(this);
129 NotifyGattServiceDiscoveryCompleteIfNecessary();
130 }
131
UpdateIncludedCharacteristics(PBTH_LE_GATT_CHARACTERISTIC characteristics,uint16_t num)132 void BluetoothRemoteGattServiceWin::UpdateIncludedCharacteristics(
133 PBTH_LE_GATT_CHARACTERISTIC characteristics,
134 uint16_t num) {
135 if (num == 0) {
136 if (!characteristics_.empty()) {
137 ClearIncludedCharacteristics();
138 adapter_->NotifyGattServiceChanged(this);
139 }
140 return;
141 }
142
143 // First, remove characteristics that no longer exist.
144 std::vector<std::string> to_be_removed;
145 for (const auto& c : characteristics_) {
146 if (!DoesCharacteristicExist(
147 characteristics, num,
148 static_cast<BluetoothRemoteGattCharacteristicWin*>(
149 c.second.get()))) {
150 to_be_removed.push_back(c.second->GetIdentifier());
151 }
152 }
153 for (const auto& id : to_be_removed) {
154 RemoveIncludedCharacteristic(id);
155 }
156
157 // Update previously known characteristics.
158 for (auto& c : characteristics_) {
159 static_cast<BluetoothRemoteGattCharacteristicWin*>(c.second.get())
160 ->Update();
161 }
162
163 // Return if no new characteristics have been added.
164 if (characteristics_.size() == num)
165 return;
166
167 // Add new characteristics.
168 for (uint16_t i = 0; i < num; i++) {
169 if (!IsCharacteristicDiscovered(characteristics[i].CharacteristicUuid,
170 characteristics[i].AttributeHandle)) {
171 PBTH_LE_GATT_CHARACTERISTIC info = new BTH_LE_GATT_CHARACTERISTIC();
172 *info = characteristics[i];
173 AddCharacteristic(std::make_unique<BluetoothRemoteGattCharacteristicWin>(
174 this, info, ui_task_runner_));
175 }
176 }
177 }
178
179 void BluetoothRemoteGattServiceWin::
NotifyGattServiceDiscoveryCompleteIfNecessary()180 NotifyGattServiceDiscoveryCompleteIfNecessary() {
181 if (IsDiscoveryComplete() && !discovery_complete_notified_) {
182 discovery_complete_notified_ = true;
183 device_->GattServiceDiscoveryComplete(this);
184 }
185 }
186
IsCharacteristicDiscovered(const BTH_LE_UUID & uuid,uint16_t attribute_handle)187 bool BluetoothRemoteGattServiceWin::IsCharacteristicDiscovered(
188 const BTH_LE_UUID& uuid,
189 uint16_t attribute_handle) {
190 BluetoothUUID bt_uuid =
191 BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(uuid);
192 for (const auto& c : characteristics_) {
193 if (bt_uuid == c.second->GetUUID() &&
194 attribute_handle ==
195 static_cast<BluetoothRemoteGattCharacteristicWin*>(c.second.get())
196 ->GetAttributeHandle()) {
197 return true;
198 }
199 }
200 return false;
201 }
202
DoesCharacteristicExist(PBTH_LE_GATT_CHARACTERISTIC characteristics,uint16_t num,BluetoothRemoteGattCharacteristicWin * characteristic)203 bool BluetoothRemoteGattServiceWin::DoesCharacteristicExist(
204 PBTH_LE_GATT_CHARACTERISTIC characteristics,
205 uint16_t num,
206 BluetoothRemoteGattCharacteristicWin* characteristic) {
207 for (uint16_t i = 0; i < num; i++) {
208 BluetoothUUID uuid =
209 BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(
210 characteristics[i].CharacteristicUuid);
211 if (characteristic->GetUUID() == uuid &&
212 characteristic->GetAttributeHandle() ==
213 characteristics[i].AttributeHandle) {
214 return true;
215 }
216 }
217 return false;
218 }
219
RemoveIncludedCharacteristic(std::string identifier)220 void BluetoothRemoteGattServiceWin::RemoveIncludedCharacteristic(
221 std::string identifier) {
222 discovery_completed_included_characteristics_.erase(identifier);
223
224 // Explicitly moving the to be deleted characteristic into a local variable,
225 // so that we can erase the entry from |characteristics_| before calling the
226 // characteristic's destructor. This will ensure that any call to
227 // GetCharacteristics() won't contain an entry corresponding to |identifier|.
228 // Note: `characteristics_.erase(identifier);` would not guarantee this.
229 DCHECK(base::Contains(characteristics_, identifier));
230 auto iter = characteristics_.find(identifier);
231 auto pair = std::move(*iter);
232 characteristics_.erase(iter);
233 }
234
ClearIncludedCharacteristics()235 void BluetoothRemoteGattServiceWin::ClearIncludedCharacteristics() {
236 discovery_completed_included_characteristics_.clear();
237 // Explicitly reset to null to ensure that calling GetCharacteristics() in
238 // GattCharacteristicRemoved() will return an empty collection.
239 // Note: `characteristics_.clear();` would not guarantee this.
240 std::exchange(characteristics_, {});
241 }
242
243 } // namespace device.
244