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

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: added channel 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 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..4cefd6bc1c6e3e11e81f265f3fc65884c0edc674
--- /dev/null
+++ b/components/proximity_auth/ble/bluetooth_low_energy_weave_server.cc
@@ -0,0 +1,298 @@
+// 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 {
+
+using Property = BluetoothLocalGattCharacteristic::Property;
+using BluetoothUUID = device::BluetoothUUID;
+
+const uint32_t kAdvertisementRotationPeriodInSecs = 5;
+
+// TODO(jingxuy): find out the right UUID
+const char kWeaveServiceUUID[] = "00000100-0004-1000-8000-001A11000100";
+
+// The UUID of the BLE service that host the RX and TX characteristics.
+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::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.
+ // 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() ||
+ !HasChannel(bluetooth_device)) {
+ return;
+ }
+
+ map_to_channel_[bluetooth_device]->ReceivePacket(value);
+
+ // TODO(jingxuy): do I need to care about offset?
+ // TODO(jingxuy): what do I do with the error_callback?
+ callback.Run();
+}
+
+void BluetoothLowEnergyWeaveServer::OnNotificationsStart(
+ const BluetoothDevice* bluetooth_device,
+ const BluetoothLocalGattCharacteristic* characteristic) {
+ if (characteristic != rx_characteristic_.get() ||
+ HasChannel(bluetooth_device)) {
+ return;
+ }
+
+ std::unique_ptr<BluetoothLowEnergyWeaveChannel> channel(
+ new BluetoothLowEnergyWeaveChannel(bluetooth_device, rx_characteristic_));
+
+ map_to_channel_.insert(std::make_pair(bluetooth_device, std::move(channel)));
+}
+
+void BluetoothLowEnergyWeaveServer::OnNotificationsStop(
+ const BluetoothDevice* bluetooth_device,
+ const BluetoothLocalGattCharacteristic* characteristic) {
+ if (characteristic != rx_characteristic_.get() ||
+ !HasChannel(bluetooth_device)) {
+ return;
+ }
+
+ map_to_channel_[bluetooth_device]->GetServerConnection()->Disconnect();
+
+ map_to_channel_.erase(bluetooth_device);
+}
+
+void BluetoothLowEnergyWeaveServer::OnChannelAuthenticated(
+ std::string device_id,
+ const BluetoothDevice* bluetooth_device) {
+ DCHECK(HasDevice(device_id));
+ DCHECK(HasChannel(bluetooth_device));
+
+ DisableAdvertising(device_id);
+
+ for (const auto& observer : observers_) {
+ observer->OnConnectionEstablished(
+ map_to_channel_[bluetooth_device]->GetServerConnection());
+ }
+}
+
+void BluetoothLowEnergyWeaveServer::OnChannelDisconnected(
+ std::string device_id,
+ const BluetoothDevice* bluetooth_device) {
+ DCHECK(HasDevice(device_id));
+ DCHECK(HasChannel(bluetooth_device));
+
+ EnableAdvertising(device_id);
+
+ for (const auto& observer : observers_) {
+ observer->OnConnectionClosed();
+ }
+
+ map_to_channel_.erase(bluetooth_device);
+}
+
+void BluetoothLowEnergyWeaveServer::RegisterDevice(
+ const RemoteDevice& remote_device) {
+ DCHECK(!HasDevice(remote_device.user_id));
+
+ map_to_remote_device_[remote_device.user_id] = remote_device;
+ ad_rotator_->AddDevice(remote_device);
+}
+
+void BluetoothLowEnergyWeaveServer::UnregisterDevice(
+ const RemoteDevice& remote_device) {
+ std::string device_id = remote_device.user_id;
+ DCHECK(HasDevice(device_id));
+
+ if (IsAdvertising(device_id)) {
+ UnregisterAdvertisement(device_id);
+ }
+
+ // TODO(jingxuy): remove current connected channels.
+
+ ad_rotator_->RemoveDevice(remote_device);
+ map_to_remote_device_.erase(remote_device.user_id);
+}
+
+bool BluetoothLowEnergyWeaveServer::HasDevice(std::string device_address) {
+ return map_to_remote_device_.find(device_address) !=
+ map_to_remote_device_.end();
+}
+
+void BluetoothLowEnergyWeaveServer::EnableAdvertising(std::string device_id) {
+ DCHECK(HasDevice(device_id) || !ad_rotator_->HasDeviceWithId(device_id));
+
+ ad_rotator_->AddDevice(map_to_remote_device_[device_id]);
+}
+
+void BluetoothLowEnergyWeaveServer::DisableAdvertising(std::string device_id) {
+ DCHECK(HasDevice(device_id) || ad_rotator_->HasDeviceWithId(device_id));
+
+ const RemoteDevice& remote_device = map_to_remote_device_[device_id];
+
+ ad_rotator_->RemoveDevice(remote_device);
+
+ if (map_to_advertisement_.find(device_id) != map_to_advertisement_.end()) {
+ UnregisterAdvertisement(device_id);
+ }
+}
+
+void BluetoothLowEnergyWeaveServer::SetTaskRunnerForTesting(
+ scoped_refptr<base::TaskRunner> task_runner) {
+ task_runner_ = task_runner;
+}
+
+bool BluetoothLowEnergyWeaveServer::IsAdvertising(
+ std::string bluetooth_address) {
+ return map_to_advertisement_.find(bluetooth_address) !=
+ map_to_advertisement_.end();
+}
+
+bool BluetoothLowEnergyWeaveServer::HasChannel(
+ const BluetoothDevice* bluetooth_device) {
+ return map_to_channel_.find(bluetooth_device) != map_to_channel_.end();
+}
+
+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(IsAdvertising(bluetooth_address));
+ 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();
+}
+
+} // namespace weave
+
+} // namespace

Powered by Google App Engine
This is Rietveld 408576698