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

Side by Side Diff: components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc

Issue 2183523006: Chrome OS uWeave Characteristics Server (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@migration
Patch Set: fixed bugs in server connection Created 4 years, 4 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 unified diff | Download patch
OLDNEW
(Empty)
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 "base/bind.h"
6 #include "base/threading/thread_task_runner_handle.h"
7 #include "base/time/time.h"
8 #include "components/proximity_auth/ble/bluetooth_low_energy_weave_server.h"
9 #include "device/bluetooth/bluetooth_adapter_factory.h"
10 #include "device/bluetooth/bluetooth_uuid.h"
11
12 namespace proximity_auth {
13 namespace weave {
14 namespace {
15
16 using Property = BluetoothLocalGattCharacteristic::Property;
17 using BluetoothUUID = device::BluetoothUUID;
18
19 const uint32_t kAdvertisementRotationPeriodInSecs = 5;
20 const uint32_t kEidRotationPeriodInHours = 8;
21 const uint32_t kEidSeedRotationPeriodInDays = 14;
22
23 // TODO(jingxuy): find out the right UUID
24 const char kWeaveServiceUUID[] = "00000100-0004-1000-8000-001A11000100";
25
26 // The UUID of the BLE service that host the RX and TX characteristics.
27 const char kRXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000101";
28 const char kTXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000102";
29
30 // TODO(jingxuy): verify these properties, currently just a draft version.
31 const uint32_t kRXCharacteristicProperties =
32 Property::PROPERTY_NOTIFY | Property::PROPERTY_READ;
33
34 const uint32_t kTXCharacteristicProperties = Property::PROPERTY_WRITE;
35
36 const uint32_t kCharacteristicPermissions =
37 BluetoothLocalGattCharacteristic::Permission::PERMISSION_NONE;
38
39 } // namespace
40
41 // static.
42 BluetoothLowEnergyWeaveServer::Factory*
43 BluetoothLowEnergyWeaveServer::Factory::factory_instance_ = nullptr;
44
45 // static.
46 std::unique_ptr<BluetoothLowEnergyWeaveServer>
47 BluetoothLowEnergyWeaveServer::Factory::NewInstance() {
48 if (factory_instance_ == nullptr) {
49 factory_instance_ = new Factory();
50 }
51 return factory_instance_->BuildInstance();
52 }
53
54 // static.
55 void BluetoothLowEnergyWeaveServer::Factory::SetInstanceForTesting(
56 Factory* factory) {
57 factory_instance_ = factory;
58 }
59
60 std::unique_ptr<BluetoothLowEnergyWeaveServer>
61 BluetoothLowEnergyWeaveServer::Factory::BuildInstance() {
62 return std::unique_ptr<BluetoothLowEnergyWeaveServer>(
63 new BluetoothLowEnergyWeaveServer());
64 }
65
66 BluetoothLowEnergyWeaveServer::BluetoothLowEnergyWeaveServer()
67 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
68 ad_rotator_(BluetoothLowEnergyAdvertisementRotator::Factory::NewInstance(
69 kWeaveServiceUUID)),
70 weak_ptr_factory_(this) {
71 adapter_ =
72 BluetoothAdapter::CreateAdapter(
73 base::Bind(&BluetoothLowEnergyWeaveServer::CreateAdapterCallback,
74 weak_ptr_factory_.GetWeakPtr()))
75 .get();
76 service_ = BluetoothLocalGattService::Create(
77 adapter_.get(), BluetoothUUID(kWeaveServiceUUID), true, nullptr, this);
78 rx_characteristic_ = BluetoothLocalGattCharacteristic::Create(
79 BluetoothUUID(kRXCharacteristicUUID), kRXCharacteristicProperties,
80 kCharacteristicPermissions, service_.get());
81 tx_characteristic_ = BluetoothLocalGattCharacteristic::Create(
82 BluetoothUUID(kTXCharacteristicUUID), kTXCharacteristicProperties,
83 kCharacteristicPermissions, service_.get());
84 }
85
86 void BluetoothLowEnergyWeaveServer::OnCharacteristicReadRequest(
87 const BluetoothDevice* bluetooth_device,
88 const BluetoothLocalGattCharacteristic* characteristic,
89 int offset,
90 const ValueCallback& callback,
91 const ErrorCallback& error_callback) {
92 // Only care about the read on the rx_characteristic from registered devices.
93 if (characteristic != rx_characteristic_.get() ||
94 !HasDevice(bluetooth_device->GetAddress())) {
95 return;
96 }
97
98 // TODO(jingxuy): Do we even need to support this function?
99 // I thought the client only gets informed of rx_characteristics changes and
100 // wont't starting actively reading the value.
101 }
102
103 void BluetoothLowEnergyWeaveServer::OnCharacteristicWriteRequest(
104 const BluetoothDevice* bluetooth_device,
105 const BluetoothLocalGattCharacteristic* characteristic,
106 const Packet& value,
107 int offset,
108 const base::Closure& callback,
109 const ErrorCallback& error_callback) {
110 // Only care about the writes on the tx_characteristic from registered
111 // devices.
112 if (characteristic != tx_characteristic_.get() ||
113 !HasDevice(bluetooth_device->GetAddress())) {
114 return;
115 }
116
117 auto it = map_to_server_connection_.find(bluetooth_device->GetAddress());
118
119 // Device is registered but it's not connected.
120 if (it == map_to_server_connection_.end())
121 return;
122
123 // TODO(jingxuy): do I need to care about offset?
124 // TODO(jingxuy): what do I do with the error_callback?
125 it->second->ReceivePacket(value);
126 callback.Run();
127 }
128
129 void BluetoothLowEnergyWeaveServer::OnNotificationsStart(
130 const BluetoothDevice* bluetooth_device,
131 const BluetoothLocalGattCharacteristic* characteristic) {
132 const std::string bluetooth_address = bluetooth_device->GetAddress();
133
134 if (characteristic != rx_characteristic_.get() ||
135 !HasDevice(bluetooth_address) || IsConnected(bluetooth_address)) {
136 return;
137 }
138
139 std::unique_ptr<BluetoothLowEnergyWeaveServerConnection> connection(
140 new BluetoothLowEnergyWeaveServerConnection(
141 bluetooth_device, weak_ptr_factory_.GetWeakPtr(),
142 rx_characteristic_));
143
144 connection->Connect();
145
146 map_to_server_connection_.insert(
147 std::make_pair(bluetooth_address, std::move(connection)));
148 }
149
150 void BluetoothLowEnergyWeaveServer::OnNotificationsStop(
151 const BluetoothDevice* bluetooth_device,
152 const BluetoothLocalGattCharacteristic* characteristic) {
153 const std::string bluetooth_address = bluetooth_device->GetAddress();
154
155 if (characteristic != rx_characteristic_.get() ||
156 !HasDevice(bluetooth_address) || !IsConnected(bluetooth_address)) {
157 return;
158 }
159
160 auto it = map_to_server_connection_.find(bluetooth_address);
161
162 if (it->second->status() != ConnectionStatus::DISCONNECTED) {
163 it->second->Disconnect();
164 }
165 map_to_server_connection_.erase(bluetooth_address);
166 }
167
168 void BluetoothLowEnergyWeaveServer::RegisterDevice(
169 const RemoteDevice& remote_device) {
170 DCHECK(!HasDevice(remote_device.bluetooth_address));
171
172 map_to_remote_device_[remote_device.bluetooth_address] = remote_device;
173 ad_rotator_->AddDevice(remote_device);
174 }
175
176 void BluetoothLowEnergyWeaveServer::UnregisterDevice(
177 const RemoteDevice& remote_device) {
178 std::string bluetooth_address = remote_device.bluetooth_address;
179 DCHECK(HasDevice(bluetooth_address));
180
181 if (IsAdvertising(bluetooth_address)) {
182 UnregisterAdvertisement(bluetooth_address);
183 }
184
185 if (IsConnected(bluetooth_address)) {
186 map_to_server_connection_[bluetooth_address]->Disconnect();
187 map_to_server_connection_.erase(bluetooth_address);
188 }
189
190 ad_rotator_->RemoveDevice(remote_device);
191 map_to_remote_device_.erase(bluetooth_address);
192 }
193
194 bool BluetoothLowEnergyWeaveServer::HasDevice(std::string device_address) {
195 return map_to_remote_device_.find(device_address) !=
196 map_to_remote_device_.end();
197 }
198
199 const RemoteDevice& BluetoothLowEnergyWeaveServer::GetRemoteDevice(
200 const BluetoothDevice* bluetooth_device) {
201 DCHECK(HasDevice(bluetooth_device->GetAddress()));
202 return map_to_remote_device_[bluetooth_device->GetAddress()];
203 }
204
205 void BluetoothLowEnergyWeaveServer::EnableAdvertising(
206 const RemoteDevice& remote_device) {
207 DCHECK(HasDevice(remote_device.bluetooth_address) ||
208 !ad_rotator_->HasDeviceWithAddress(remote_device.bluetooth_address));
209
210 ad_rotator_->AddDevice(remote_device);
211 }
212
213 void BluetoothLowEnergyWeaveServer::DisableAdvertising(
214 const RemoteDevice& remote_device) {
215 DCHECK(HasDevice(remote_device.bluetooth_address) ||
216 ad_rotator_->HasDeviceWithAddress(remote_device.bluetooth_address));
217
218 ad_rotator_->RemoveDevice(remote_device);
219
220 if (map_to_advertisement_.find(remote_device.bluetooth_address) !=
221 map_to_advertisement_.end()) {
222 UnregisterAdvertisement(remote_device.bluetooth_address);
223 }
224 }
225
226 void BluetoothLowEnergyWeaveServer::SetTaskRunnerForTesting(
227 scoped_refptr<base::TaskRunner> task_runner) {
228 task_runner_ = task_runner;
229 }
230
231 bool BluetoothLowEnergyWeaveServer::IsAdvertising(
232 std::string bluetooth_address) {
233 return map_to_advertisement_.find(bluetooth_address) !=
234 map_to_advertisement_.end();
235 }
236
237 bool BluetoothLowEnergyWeaveServer::IsConnected(std::string device_address) {
238 return map_to_server_connection_.find(device_address) !=
239 map_to_server_connection_.end();
240 }
241
242 void BluetoothLowEnergyWeaveServer::UpdateEidSeeds() {
243 RefreshAdvertisement();
244 // TODO (jingxuy): make this follow 14 day boundaries.
245 base::TimeDelta wait_time =
246 base::TimeDelta::FromDays(kEidSeedRotationPeriodInDays);
247 task_runner_->PostDelayedTask(
248 FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::UpdateEidSeeds,
249 weak_ptr_factory_.GetWeakPtr()),
250 wait_time);
251 }
252
253 void BluetoothLowEnergyWeaveServer::UpdateEids() {
254 RefreshAdvertisement();
255 // TODO(jingxuy): make this follow 8 hour boundaries.
256 base::TimeDelta wait_time =
257 base::TimeDelta::FromHours(kEidRotationPeriodInHours);
258 task_runner_->PostDelayedTask(
259 FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::UpdateEids,
260 weak_ptr_factory_.GetWeakPtr()),
261 wait_time);
262 }
263
264 void BluetoothLowEnergyWeaveServer::RefreshAdvertisement() {
265 // Can't change content of current advertisement.
266 // Hence unregister all current advertisement and put them on the top of the
267 // advertising queue and retry advertising them again.
268 // Unless some other application come in between the process and steal the
269 // advertisement quota, we can still advertise everything that's unregistered.
270 for (auto const& it : map_to_advertisement_) {
271 UnregisterAdvertisement(it.first);
272 ad_rotator_->CutAdvertisementLine(it.first);
273 }
274 Advertise();
275 }
276
277 void BluetoothLowEnergyWeaveServer::RotateAdvertisement() {
278 for (auto const& it : map_to_advertisement_) {
279 UnregisterAdvertisement(it.first);
280 }
281
282 Advertise();
283 base::TimeDelta wait_time =
284 base::TimeDelta::FromSeconds(kAdvertisementRotationPeriodInSecs);
285
286 task_runner_->PostDelayedTask(
287 FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::RotateAdvertisement,
288 weak_ptr_factory_.GetWeakPtr()),
289 wait_time);
290 }
291
292 void BluetoothLowEnergyWeaveServer::Advertise() {
293 std::pair<std::string, std::unique_ptr<Advertisement>> ad =
294 ad_rotator_->GetNextAdvertisement();
295 adapter_->RegisterAdvertisement(
rkc 2016/08/02 01:09:21 This won't work. You can only advertise one advert
rkc 2016/08/02 22:14:24 Just to clarify, after some digging around in the
296 std::move(ad.second),
297 base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess,
298 weak_ptr_factory_.GetWeakPtr(), ad.first),
299 base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementError,
300 weak_ptr_factory_.GetWeakPtr()));
301 }
302
303 void BluetoothLowEnergyWeaveServer::UnregisterAdvertisement(
304 std::string bluetooth_address) {
305 DCHECK(IsAdvertising(bluetooth_address));
306 map_to_advertisement_[bluetooth_address]->Unregister(
307 base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess,
308 weak_ptr_factory_.GetWeakPtr(), bluetooth_address),
309 base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError,
310 weak_ptr_factory_.GetWeakPtr(), bluetooth_address));
311 }
312
313 void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess(
314 std::string bluetooth_address) {
315 map_to_advertisement_.erase(bluetooth_address);
316 }
317
318 void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError(
319 std::string bluetooth_address,
320 BluetoothAdvertisement::ErrorCode error) {
321 DCHECK(error ==
322 BluetoothAdvertisement::ErrorCode::ERROR_ADVERTISEMENT_DOES_NOT_EXIST);
323 // The only way the unregister could fail is if the advertisement is not
324 // registered to begin with. Which means in our use case it should never fail.
325 // Hence remove the advertisement from the map.
326 map_to_advertisement_.erase(bluetooth_address);
327 }
328
329 void BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess(
330 std::string bluetooth_address,
331 scoped_refptr<BluetoothAdvertisement> advertisement) {
332 map_to_advertisement_[bluetooth_address] = advertisement;
333 ad_rotator_->RotateAdvertisement();
334 // Keep trying to advertise until failures.
335 Advertise();
336 }
337
338 } // namespace weave
339
340 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698