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