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

Unified 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: Created 4 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc b/components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0fa52485fa79ebf011356cccbeba630a16c1393a
--- /dev/null
+++ b/components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc
@@ -0,0 +1,320 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/proximity_auth/ble/bluetooth_low_energy_weave_server.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+namespace proximity_auth {
+namespace weave {
+namespace {
+
+typedef BluetoothLocalGattCharacteristic::Property Property;
+typedef device::BluetoothUUID BluetoothUUID;
+
+const uint32_t kAdvertisementRotationPeriodInSecs = 5;
+const uint32_t kEidRotationPeriodInHours = 8;
+const uint32_t kEidSeedRotationPeriodInDays = 14;
+// TODO(jingxuy): find out the right UUID
+// The UUID of the BLE service that host the RX and TX characteristics.
+const char kWeaveServiceUUID[] = "00000100-0004-1000-8000-001A11000100";
+const char kRXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000101";
+const char kTXCharacteristicUUID[] = "00000100-0004-1000-8000-001A11000102";
+
+// TODO(jingxuy): verify these properties, currently just a draft version.
+const uint32_t kRXCharacteristicProperties =
+ Property::PROPERTY_NOTIFY | Property::PROPERTY_READ;
+
+const uint32_t kTXCharacteristicProperties = Property::PROPERTY_WRITE;
+
+const uint32_t kCharacteristicPermissions =
+ BluetoothLocalGattCharacteristic::Permission::PERMISSION_NONE;
+
+} // namespace
+
+// static.
+BluetoothLowEnergyWeaveServer::Factory*
+ BluetoothLowEnergyWeaveServer::Factory::factory_instance_ = nullptr;
+
+// static.
+std::unique_ptr<BluetoothLowEnergyWeaveServer>
+BluetoothLowEnergyWeaveServer::Factory::NewInstance() {
+ if (factory_instance_ == nullptr) {
+ factory_instance_ = new Factory();
+ }
+ return factory_instance_->BuildInstance();
+}
+
+// static.
+void BluetoothLowEnergyWeaveServer::Factory::SetInstanceForTesting(
+ Factory* factory) {
+ factory_instance_ = factory;
+}
+
+std::unique_ptr<BluetoothLowEnergyWeaveServer>
+BluetoothLowEnergyWeaveServer::Factory::BuildInstance() {
+ return std::unique_ptr<BluetoothLowEnergyWeaveServer>(
+ new BluetoothLowEnergyWeaveServer());
+}
+
+BluetoothLowEnergyWeaveServer::BluetoothLowEnergyWeaveServer()
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ ad_rotator_(BluetoothLowEnergyAdvertisementRotator::Factory::NewInstance(
+ kWeaveServiceUUID)),
+ weak_ptr_factory_(this) {
+ adapter_ =
+ BluetoothAdapter::CreateAdapter(
+ base::Bind(&BluetoothLowEnergyWeaveServer::CreateAdapterCallback,
+ weak_ptr_factory_.GetWeakPtr()))
+ .get();
+ service_ = BluetoothLocalGattService::Create(
+ adapter_.get(), BluetoothUUID(kWeaveServiceUUID), true, nullptr, this);
+ rx_characteristic_ = BluetoothLocalGattCharacteristic::Create(
+ BluetoothUUID(kRXCharacteristicUUID), kRXCharacteristicProperties,
+ kCharacteristicPermissions, service_.get());
+ tx_characteristic_ = BluetoothLocalGattCharacteristic::Create(
+ BluetoothUUID(kTXCharacteristicUUID), kTXCharacteristicProperties,
+ kCharacteristicPermissions, service_.get());
+}
+
+void BluetoothLowEnergyWeaveServer::CreateAdapterCallback() {}
+
+void BluetoothLowEnergyWeaveServer::OnCharacteristicReadRequest(
+ const BluetoothDevice* bluetooth_device,
+ const BluetoothLocalGattCharacteristic* characteristic,
+ int offset,
+ const ValueCallback& callback,
+ const ErrorCallback& error_callback) {
+ // Only care about the read on the rx_characteristic from registered devices.
+ if (characteristic != rx_characteristic_.get() ||
+ !HasDevice(bluetooth_device->GetAddress())) {
+ return;
+ }
+
+ // TODO(jingxuy): Do we even need to support this function?
+ // I thought the client only gets informed of rx_characteristics changes and
+ // wont't starting actively reading the value.
+}
+
+void BluetoothLowEnergyWeaveServer::OnCharacteristicWriteRequest(
+ const BluetoothDevice* bluetooth_device,
+ const BluetoothLocalGattCharacteristic* characteristic,
+ const Packet& value,
+ int offset,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ // Only care about the writes on the tx_characteristic from registered
+ // devices.
+ if (characteristic != tx_characteristic_.get() ||
+ !HasDevice(bluetooth_device->GetAddress())) {
+ return;
+ }
+
+ auto it = map_to_server_connection_.find(bluetooth_device->GetAddress());
+
+ // Device is registered but it's not connected.
+ if (it == map_to_server_connection_.end())
+ return;
+
+ // TODO(jingxuy): do I need to care about offset?
+ if (it->second->ReceivePacket(value)) {
+ callback.Run();
+ } else {
+ error_callback.Run();
+ }
+}
+
+void BluetoothLowEnergyWeaveServer::OnNotificationsStart(
+ const BluetoothDevice* bluetooth_device,
+ const BluetoothLocalGattCharacteristic* characteristic) {
+ if (characteristic != rx_characteristic_.get() ||
+ !HasDevice(bluetooth_device->GetAddress())) {
+ return;
+ }
+
+ auto it = map_to_server_connection_.find(bluetooth_device->GetAddress());
+
+ if (it == map_to_server_connection_.end()) {
+ std::unique_ptr<BluetoothLowEnergyWeaveServerConnection> connection(
+ new BluetoothLowEnergyWeaveServerConnection(
+ bluetooth_device, weak_ptr_factory_.GetWeakPtr(),
+ rx_characteristic_));
+
+ map_to_server_connection_.insert(
+ std::make_pair(bluetooth_device->GetAddress(), std::move(connection)));
+
+ } else if (it->second->status() == ConnectionStatus::DISCONNECTED) {
+ it->second->Connect();
+ }
+}
+
+void BluetoothLowEnergyWeaveServer::OnNotificationsStop(
+ const BluetoothDevice* bluetooth_device,
+ const BluetoothLocalGattCharacteristic* characteristic) {
+ if (characteristic != rx_characteristic_.get() ||
+ !HasDevice(bluetooth_device->GetAddress())) {
+ return;
+ }
+
+ auto it = map_to_server_connection_.find(bluetooth_device->GetAddress());
+
+ // Getting notification stop when it never started!
+ if (it == map_to_server_connection_.end()) {
+ return;
+ }
+
+ if (it->second->status() == ConnectionStatus::CONNECTED) {
+ it->second->Connect();
+ }
+}
+
+void BluetoothLowEnergyWeaveServer::RegisterDevice(
+ const RemoteDevice& remote_device) {
+ map_to_remote_device_[remote_device.bluetooth_address] = remote_device;
+ ad_rotator_->AddDevice(remote_device);
+}
+
+bool BluetoothLowEnergyWeaveServer::HasDevice(std::string device_address) {
+ return map_to_remote_device_.find(device_address) !=
+ map_to_remote_device_.end();
+}
+
+const RemoteDevice& BluetoothLowEnergyWeaveServer::GetRemoteDevice(
+ const BluetoothDevice* bluetooth_device) {
+ DCHECK(HasDevice(bluetooth_device->GetAddress()));
+ return map_to_remote_device_[bluetooth_device->GetAddress()];
+}
+
+void BluetoothLowEnergyWeaveServer::StartAdvertising(
+ const RemoteDevice& remote_device) {
+ DCHECK(HasDevice(remote_device.bluetooth_address) ||
+ !ad_rotator_->HasDeviceWithAddress(remote_device.bluetooth_address));
+
+ ad_rotator_->AddDevice(remote_device);
+}
+
+void BluetoothLowEnergyWeaveServer::StopAdvertising(
+ const RemoteDevice& remote_device) {
+ DCHECK(HasDevice(remote_device.bluetooth_address) ||
+ ad_rotator_->HasDeviceWithAddress(remote_device.bluetooth_address));
+
+ ad_rotator_->RemoveDevice(remote_device);
+
+ if (map_to_advertisement_.find(remote_device.bluetooth_address) !=
+ map_to_advertisement_.end()) {
+ UnregisterAdvertisement(remote_device.bluetooth_address);
+ }
+}
+
+void BluetoothLowEnergyWeaveServer::SetTaskRunnerForTesting(
+ scoped_refptr<base::TaskRunner> task_runner) {
+ task_runner_ = task_runner;
+}
+
+void BluetoothLowEnergyWeaveServer::UpdateEidSeeds() {
+ RefreshAdvertisement();
+ // TODO (jingxuy): make this follow 14 day boundaries.
+ base::TimeDelta wait_time =
+ base::TimeDelta::FromDays(kEidSeedRotationPeriodInDays);
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::UpdateEidSeeds,
+ weak_ptr_factory_.GetWeakPtr()),
+ wait_time);
+}
+
+void BluetoothLowEnergyWeaveServer::UpdateEids() {
+ RefreshAdvertisement();
+ // TODO(jingxuy): make this follow 8 hour boundaries.
+ base::TimeDelta wait_time =
+ base::TimeDelta::FromHours(kEidRotationPeriodInHours);
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::UpdateEids,
+ weak_ptr_factory_.GetWeakPtr()),
+ wait_time);
+}
+
+void BluetoothLowEnergyWeaveServer::RefreshAdvertisement() {
+ // Can't change content of current advertisement.
+ // Hence unregister all current advertisement and put them on the top of the
+ // advertising queue and retry advertising them again.
+ // Unless some other application come in between the process and steal the
+ // advertisement quota, we can still advertise everything that's unregistered.
+ for (auto const& it : map_to_advertisement_) {
+ UnregisterAdvertisement(it.first);
+ ad_rotator_->CutAdvertisementLine(it.first);
+ }
+ Advertise();
+}
+
+void BluetoothLowEnergyWeaveServer::RotateAdvertisement() {
+ for (auto const& it : map_to_advertisement_) {
+ UnregisterAdvertisement(it.first);
+ }
+
+ Advertise();
+ base::TimeDelta wait_time =
+ base::TimeDelta::FromSeconds(kAdvertisementRotationPeriodInSecs);
+
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&BluetoothLowEnergyWeaveServer::RotateAdvertisement,
+ weak_ptr_factory_.GetWeakPtr()),
+ wait_time);
+}
+
+void BluetoothLowEnergyWeaveServer::Advertise() {
+ std::pair<std::string, std::unique_ptr<Advertisement>> ad =
+ ad_rotator_->GetNextAdvertisement();
+ adapter_->RegisterAdvertisement(
+ std::move(ad.second),
+ base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess,
+ weak_ptr_factory_.GetWeakPtr(), ad.first),
+ base::Bind(&BluetoothLowEnergyWeaveServer::RegisterAdvertisementError,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BluetoothLowEnergyWeaveServer::UnregisterAdvertisement(
+ std::string bluetooth_address) {
+ DCHECK(map_to_advertisement_.find(bluetooth_address) !=
+ map_to_advertisement_.end());
+ map_to_advertisement_[bluetooth_address]->Unregister(
+ base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess,
+ weak_ptr_factory_.GetWeakPtr(), bluetooth_address),
+ base::Bind(&BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError,
+ weak_ptr_factory_.GetWeakPtr(), bluetooth_address));
+}
+
+void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementSuccess(
+ std::string bluetooth_address) {
+ map_to_advertisement_.erase(bluetooth_address);
+}
+
+void BluetoothLowEnergyWeaveServer::UnregisterAdvertisementError(
+ std::string bluetooth_address,
+ BluetoothAdvertisement::ErrorCode error) {
+ DCHECK(error ==
+ BluetoothAdvertisement::ErrorCode::ERROR_ADVERTISEMENT_DOES_NOT_EXIST);
+ // The only way the unregister could fail is if the advertisement is not
+ // registered to begin with. Which means in our use case it should never fail.
+ // Hence remove the advertisement from the map.
+ map_to_advertisement_.erase(bluetooth_address);
+}
+
+void BluetoothLowEnergyWeaveServer::RegisterAdvertisementSuccess(
+ std::string bluetooth_address,
+ scoped_refptr<BluetoothAdvertisement> advertisement) {
+ map_to_advertisement_[bluetooth_address] = advertisement;
+ ad_rotator_->RotateAdvertisement();
+ // Keep trying to advertise until failures.
+ Advertise();
+}
+
+void BluetoothLowEnergyWeaveServer::RegisterAdvertisementError(
+ BluetoothAdvertisement::ErrorCode error) {}
+
+} // namespace weave
+
+} // namespace

Powered by Google App Engine
This is Rietveld 408576698