Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |