| 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 |
| 21 // TODO(jingxuy): find out the right UUID |
| 22 const char kWeaveServiceUUID[] = "00000100-0004-1000-8000-001A11000100"; |
| 23 |
| 24 // The UUID of the BLE service that host the RX and TX characteristics. |
| 25 const char kRXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000101"; |
| 26 const char kTXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000102"; |
| 27 |
| 28 // TODO(jingxuy): verify these properties, currently just a draft version. |
| 29 const uint32_t kRXCharacteristicProperties = |
| 30 Property::PROPERTY_NOTIFY | Property::PROPERTY_READ; |
| 31 |
| 32 const uint32_t kTXCharacteristicProperties = Property::PROPERTY_WRITE; |
| 33 |
| 34 const uint32_t kCharacteristicPermissions = |
| 35 BluetoothLocalGattCharacteristic::Permission::PERMISSION_NONE; |
| 36 |
| 37 } // namespace |
| 38 |
| 39 // static. |
| 40 BluetoothLowEnergyWeaveServer::Factory* |
| 41 BluetoothLowEnergyWeaveServer::Factory::factory_instance_ = nullptr; |
| 42 |
| 43 // static. |
| 44 std::unique_ptr<BluetoothLowEnergyWeaveServer> |
| 45 BluetoothLowEnergyWeaveServer::Factory::NewInstance() { |
| 46 if (factory_instance_ == nullptr) { |
| 47 factory_instance_ = new Factory(); |
| 48 } |
| 49 return factory_instance_->BuildInstance(); |
| 50 } |
| 51 |
| 52 // static. |
| 53 void BluetoothLowEnergyWeaveServer::Factory::SetInstanceForTesting( |
| 54 Factory* factory) { |
| 55 factory_instance_ = factory; |
| 56 } |
| 57 |
| 58 std::unique_ptr<BluetoothLowEnergyWeaveServer> |
| 59 BluetoothLowEnergyWeaveServer::Factory::BuildInstance() { |
| 60 return std::unique_ptr<BluetoothLowEnergyWeaveServer>( |
| 61 new BluetoothLowEnergyWeaveServer()); |
| 62 } |
| 63 |
| 64 BluetoothLowEnergyWeaveServer::BluetoothLowEnergyWeaveServer() |
| 65 : task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 66 ad_rotator_(BluetoothLowEnergyAdvertisementRotator::Factory::NewInstance( |
| 67 kWeaveServiceUUID)), |
| 68 weak_ptr_factory_(this) { |
| 69 adapter_ = |
| 70 BluetoothAdapter::CreateAdapter( |
| 71 base::Bind(&BluetoothLowEnergyWeaveServer::CreateAdapterCallback, |
| 72 weak_ptr_factory_.GetWeakPtr())) |
| 73 .get(); |
| 74 service_ = BluetoothLocalGattService::Create( |
| 75 adapter_.get(), BluetoothUUID(kWeaveServiceUUID), true, nullptr, this); |
| 76 rx_characteristic_ = BluetoothLocalGattCharacteristic::Create( |
| 77 BluetoothUUID(kRXCharacteristicUUID), kRXCharacteristicProperties, |
| 78 kCharacteristicPermissions, service_.get()); |
| 79 tx_characteristic_ = BluetoothLocalGattCharacteristic::Create( |
| 80 BluetoothUUID(kTXCharacteristicUUID), kTXCharacteristicProperties, |
| 81 kCharacteristicPermissions, service_.get()); |
| 82 } |
| 83 |
| 84 void BluetoothLowEnergyWeaveServer::OnCharacteristicReadRequest( |
| 85 const BluetoothDevice* bluetooth_device, |
| 86 const BluetoothLocalGattCharacteristic* characteristic, |
| 87 int offset, |
| 88 const ValueCallback& callback, |
| 89 const ErrorCallback& error_callback) { |
| 90 // Only care about the read on the rx_characteristic from registered devices. |
| 91 // TODO(jingxuy): Do we even need to support this function? |
| 92 // I thought the client only gets informed of rx_characteristics changes and |
| 93 // wont't starting actively reading the value. |
| 94 } |
| 95 |
| 96 void BluetoothLowEnergyWeaveServer::OnCharacteristicWriteRequest( |
| 97 const BluetoothDevice* bluetooth_device, |
| 98 const BluetoothLocalGattCharacteristic* characteristic, |
| 99 const Packet& value, |
| 100 int offset, |
| 101 const base::Closure& callback, |
| 102 const ErrorCallback& error_callback) { |
| 103 // Only care about the writes on the tx_characteristic from registered |
| 104 // devices. |
| 105 if (characteristic != tx_characteristic_.get() || |
| 106 !HasChannel(bluetooth_device)) { |
| 107 return; |
| 108 } |
| 109 |
| 110 map_to_channel_[bluetooth_device]->ReceivePacket(value); |
| 111 |
| 112 // TODO(jingxuy): do I need to care about offset? |
| 113 // TODO(jingxuy): what do I do with the error_callback? |
| 114 callback.Run(); |
| 115 } |
| 116 |
| 117 void BluetoothLowEnergyWeaveServer::OnNotificationsStart( |
| 118 const BluetoothDevice* bluetooth_device, |
| 119 const BluetoothLocalGattCharacteristic* characteristic) { |
| 120 if (characteristic != rx_characteristic_.get() || |
| 121 HasChannel(bluetooth_device)) { |
| 122 return; |
| 123 } |
| 124 |
| 125 std::unique_ptr<BluetoothLowEnergyWeaveChannel> channel( |
| 126 new BluetoothLowEnergyWeaveChannel(bluetooth_device, rx_characteristic_)); |
| 127 |
| 128 map_to_channel_.insert(std::make_pair(bluetooth_device, std::move(channel))); |
| 129 } |
| 130 |
| 131 void BluetoothLowEnergyWeaveServer::OnNotificationsStop( |
| 132 const BluetoothDevice* bluetooth_device, |
| 133 const BluetoothLocalGattCharacteristic* characteristic) { |
| 134 if (characteristic != rx_characteristic_.get() || |
| 135 !HasChannel(bluetooth_device)) { |
| 136 return; |
| 137 } |
| 138 |
| 139 map_to_channel_[bluetooth_device]->GetServerConnection()->Disconnect(); |
| 140 |
| 141 map_to_channel_.erase(bluetooth_device); |
| 142 } |
| 143 |
| 144 void BluetoothLowEnergyWeaveServer::OnChannelAuthenticated( |
| 145 std::string device_id, |
| 146 const BluetoothDevice* bluetooth_device) { |
| 147 DCHECK(HasDevice(device_id)); |
| 148 DCHECK(HasChannel(bluetooth_device)); |
| 149 |
| 150 DisableAdvertising(device_id); |
| 151 |
| 152 for (const auto& observer : observers_) { |
| 153 observer->OnConnectionEstablished( |
| 154 map_to_channel_[bluetooth_device]->GetServerConnection()); |
| 155 } |
| 156 } |
| 157 |
| 158 void BluetoothLowEnergyWeaveServer::OnChannelDisconnected( |
| 159 std::string device_id, |
| 160 const BluetoothDevice* bluetooth_device) { |
| 161 DCHECK(HasDevice(device_id)); |
| 162 DCHECK(HasChannel(bluetooth_device)); |
| 163 |
| 164 EnableAdvertising(device_id); |
| 165 |
| 166 for (const auto& observer : observers_) { |
| 167 observer->OnConnectionClosed(); |
| 168 } |
| 169 |
| 170 map_to_channel_.erase(bluetooth_device); |
| 171 } |
| 172 |
| 173 void BluetoothLowEnergyWeaveServer::RegisterDevice( |
| 174 const RemoteDevice& remote_device) { |
| 175 DCHECK(!HasDevice(remote_device.user_id)); |
| 176 |
| 177 map_to_remote_device_[remote_device.user_id] = remote_device; |
| 178 ad_rotator_->AddDevice(remote_device); |
| 179 } |
| 180 |
| 181 void BluetoothLowEnergyWeaveServer::UnregisterDevice( |
| 182 const RemoteDevice& remote_device) { |
| 183 std::string device_id = remote_device.user_id; |
| 184 DCHECK(HasDevice(device_id)); |
| 185 |
| 186 if (IsAdvertising(device_id)) { |
| 187 UnregisterAdvertisement(device_id); |
| 188 } |
| 189 |
| 190 // TODO(jingxuy): remove current connected channels. |
| 191 |
| 192 ad_rotator_->RemoveDevice(remote_device); |
| 193 map_to_remote_device_.erase(remote_device.user_id); |
| 194 } |
| 195 |
| 196 bool BluetoothLowEnergyWeaveServer::HasDevice(std::string device_address) { |
| 197 return map_to_remote_device_.find(device_address) != |
| 198 map_to_remote_device_.end(); |
| 199 } |
| 200 |
| 201 void BluetoothLowEnergyWeaveServer::EnableAdvertising(std::string device_id) { |
| 202 DCHECK(HasDevice(device_id) || !ad_rotator_->HasDeviceWithId(device_id)); |
| 203 |
| 204 ad_rotator_->AddDevice(map_to_remote_device_[device_id]); |
| 205 } |
| 206 |
| 207 void BluetoothLowEnergyWeaveServer::DisableAdvertising(std::string device_id) { |
| 208 DCHECK(HasDevice(device_id) || ad_rotator_->HasDeviceWithId(device_id)); |
| 209 |
| 210 const RemoteDevice& remote_device = map_to_remote_device_[device_id]; |
| 211 |
| 212 ad_rotator_->RemoveDevice(remote_device); |
| 213 |
| 214 if (map_to_advertisement_.find(device_id) != map_to_advertisement_.end()) { |
| 215 UnregisterAdvertisement(device_id); |
| 216 } |
| 217 } |
| 218 |
| 219 void BluetoothLowEnergyWeaveServer::SetTaskRunnerForTesting( |
| 220 scoped_refptr<base::TaskRunner> task_runner) { |
| 221 task_runner_ = task_runner; |
| 222 } |
| 223 |
| 224 bool BluetoothLowEnergyWeaveServer::IsAdvertising( |
| 225 std::string bluetooth_address) { |
| 226 return map_to_advertisement_.find(bluetooth_address) != |
| 227 map_to_advertisement_.end(); |
| 228 } |
| 229 |
| 230 bool BluetoothLowEnergyWeaveServer::HasChannel( |
| 231 const BluetoothDevice* bluetooth_device) { |
| 232 return map_to_channel_.find(bluetooth_device) != map_to_channel_.end(); |
| 233 } |
| 234 |
| 235 void BluetoothLowEnergyWeaveServer::RotateAdvertisement() { |
| 236 for (auto const& it : map_to_advertisement_) { |
| 237 UnregisterAdvertisement(it.first); |
| 238 } |
| 239 |
| 240 Advertise(); |
| 241 base::TimeDelta wait_time = |
| 242 base::TimeDelta::FromSeconds(kAdvertisementRotationPeriodInSecs); |
| 243 |
| 244 task_runner_->PostDelayedTask( |
| 245 FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::RotateAdvertisement, |
| 246 weak_ptr_factory_.GetWeakPtr()), |
| 247 wait_time); |
| 248 } |
| 249 |
| 250 void BluetoothLowEnergyWeaveServer::Advertise() { |
| 251 std::pair<std::string, std::unique_ptr<Advertisement>> ad = |
| 252 ad_rotator_->GetNextAdvertisement(); |
| 253 adapter_->RegisterAdvertisement( |
| 254 std::move(ad.second), |
| 255 base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess, |
| 256 weak_ptr_factory_.GetWeakPtr(), ad.first), |
| 257 base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementError, |
| 258 weak_ptr_factory_.GetWeakPtr())); |
| 259 } |
| 260 |
| 261 void BluetoothLowEnergyWeaveServer::UnregisterAdvertisement( |
| 262 std::string bluetooth_address) { |
| 263 DCHECK(IsAdvertising(bluetooth_address)); |
| 264 map_to_advertisement_[bluetooth_address]->Unregister( |
| 265 base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess, |
| 266 weak_ptr_factory_.GetWeakPtr(), bluetooth_address), |
| 267 base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError, |
| 268 weak_ptr_factory_.GetWeakPtr(), bluetooth_address)); |
| 269 } |
| 270 |
| 271 void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess( |
| 272 std::string bluetooth_address) { |
| 273 map_to_advertisement_.erase(bluetooth_address); |
| 274 } |
| 275 |
| 276 void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError( |
| 277 std::string bluetooth_address, |
| 278 BluetoothAdvertisement::ErrorCode error) { |
| 279 DCHECK(error == |
| 280 BluetoothAdvertisement::ErrorCode::ERROR_ADVERTISEMENT_DOES_NOT_EXIST); |
| 281 // The only way the unregister could fail is if the advertisement is not |
| 282 // registered to begin with. Which means in our use case it should never fail. |
| 283 // Hence remove the advertisement from the map. |
| 284 map_to_advertisement_.erase(bluetooth_address); |
| 285 } |
| 286 |
| 287 void BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess( |
| 288 std::string bluetooth_address, |
| 289 scoped_refptr<BluetoothAdvertisement> advertisement) { |
| 290 map_to_advertisement_[bluetooth_address] = advertisement; |
| 291 ad_rotator_->RotateAdvertisement(); |
| 292 // Keep trying to advertise until failures. |
| 293 Advertise(); |
| 294 } |
| 295 |
| 296 } // namespace weave |
| 297 |
| 298 } // namespace |
| OLD | NEW |