Add BLE V1 windows platform implementation

This CL implements the BLE V1 Medium and its corresponding unit tests:
- Start/Stop Advertising
- Start/Stop Scanning
- Receive BLE Advertisement callbacks handler
- BLE Advertisement Publisher/Watcher status callbacks handler

PiperOrigin-RevId: 449824666
This commit is contained in:
aaronyujiaze
2022-05-19 13:48:56 -07:00
committed by Copybara-Service
parent 58d14a36bf
commit 48a91eec73
9 changed files with 883 additions and 139 deletions
@@ -48,6 +48,9 @@ cc_library(
name = "comm",
hdrs = [
"ble.h",
"ble_medium.h",
"ble_peripheral.h",
"ble_socket.h",
"ble_v2.h",
"bluetooth_adapter.h",
"bluetooth_classic.h",
@@ -100,6 +103,8 @@ cc_library(
cc_library(
name = "windows",
srcs = [
"ble_medium.cc",
"ble_socket.cc",
"ble_v2.cc",
"bluetooth_adapter.cc",
"bluetooth_classic_device.cc",
@@ -166,6 +171,7 @@ cc_test(
srcs = [
"atomic_boolean_test.cc",
"atomic_reference_test.cc",
"ble_medium_test.cc",
"ble_v2_test.cc",
"count_down_latch_test.cc",
"crypto_test.cc",
+4 -137
View File
@@ -1,4 +1,4 @@
// Copyright 2020 Google LLC
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,141 +15,8 @@
#ifndef PLATFORM_IMPL_WINDOWS_BLE_H_
#define PLATFORM_IMPL_WINDOWS_BLE_H_
#include "internal/platform/implementation/ble.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
namespace location {
namespace nearby {
namespace windows {
// Opaque wrapper over a BLE peripheral. Must contain enough data about a
// particular BLE device to connect to its GATT server.
class BlePeripheral : public api::BlePeripheral {
public:
// TODO(b/184975123): replace with real implementation.
~BlePeripheral() override = default;
// TODO(b/184975123): replace with real implementation.
std::string GetName() const override { return std::string{""}; }
// TODO(b/184975123): replace with real implementation.
ByteArray GetAdvertisementBytes(
const std::string& service_id) const override {
return ByteArray{};
}
};
class BleSocket : public api::BleSocket {
public:
// TODO(b/184975123): replace with real implementation.
~BleSocket() override;
// Returns the InputStream of the BleSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleSocket object is destroyed.
// TODO(b/184975123): replace with real implementation.
InputStream& GetInputStream() override { return fake_input_stream_; }
// Returns the OutputStream of the BleSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleSocket object is destroyed.
// TODO(b/184975123): replace with real implementation.
OutputStream& GetOutputStream() override { return fake_output_stream_; }
// Conforms to the same contract as
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#close().
//
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
// TODO(b/184975123): replace with real implementation.
Exception Close() override { return Exception{}; }
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
// TODO(b/184975123): replace with real implementation.
BlePeripheral* GetRemotePeripheral() override { return nullptr; }
// Unhooked InputStream & OutputStream for empty implementation.
// TODO(b/184975123): replace with real implementation.
private:
class FakeInputStream : public InputStream {
~FakeInputStream() override = default;
ExceptionOr<ByteArray> Read(std::int64_t size) override {
return ExceptionOr<ByteArray>(Exception::kFailed);
}
Exception Close() override { return {.value = Exception::kFailed}; }
};
class FakeOutputStream : public OutputStream {
~FakeOutputStream() override = default;
Exception Write(const ByteArray& data) override {
return {.value = Exception::kFailed};
}
Exception Flush() override { return {.value = Exception::kFailed}; }
Exception Close() override { return {.value = Exception::kFailed}; }
};
FakeInputStream fake_input_stream_;
FakeOutputStream fake_output_stream_;
};
// Container of operations that can be performed over the BLE medium.
class BleMedium : public api::BleMedium {
public:
// TODO(b/184975123): replace with real implementation.
~BleMedium() override = default;
// TODO(b/184975123): replace with real implementation.
bool StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) override {
return false;
}
// TODO(b/184975123): replace with real implementation.
bool StopAdvertising(const std::string& service_id) override { return false; }
// Returns true once the BLE scan has been initiated.
// TODO(b/184975123): replace with real implementation.
bool StartScanning(const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) override {
return false;
}
// Returns true once BLE scanning for service_id is well and truly stopped;
// after this returns, there must be no more invocations of the
// DiscoveredPeripheralCallback passed in to StartScanning() for service_id.
// TODO(b/184975123): replace with real implementation.
bool StopScanning(const std::string& service_id) override { return false; }
// Returns true once BLE socket connection requests to service_id can be
// accepted.
// TODO(b/184975123): replace with real implementation.
bool StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback) override {
return false;
}
// TODO(b/184975123): replace with real implementation.
bool StopAcceptingConnections(const std::string& service_id) override {
return false;
}
// Connects to a BLE peripheral.
// On success, returns a new BleSocket.
// On error, returns nullptr.
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<api::BleSocket> Connect(
api::BlePeripheral& peripheral, const std::string& service_id,
CancellationFlag* cancellation_flag) override {
return nullptr;
}
};
} // namespace windows
} // namespace nearby
} // namespace location
#include "internal/platform/implementation/windows/ble_peripheral.h"
#include "internal/platform/implementation/windows/ble_medium.h"
#include "internal/platform/implementation/windows/ble_socket.h"
#endif // PLATFORM_IMPL_WINDOWS_BLE_H_
@@ -0,0 +1,354 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/windows/ble_medium.h"
#include <string>
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/logging.h"
#include "winrt/Windows.Devices.Bluetooth.Advertisement.h"
#include "winrt/Windows.Devices.Bluetooth.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/Windows.Storage.Streams.h"
namespace location {
namespace nearby {
namespace windows {
namespace {
using ::winrt::Windows::Devices::Bluetooth::BluetoothError;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisement;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementDataSection;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementDataTypes;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementPublisher;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementPublisherStatus;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementPublisherStatusChangedEventArgs;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementReceivedEventArgs;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcher;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcherStatus;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcherStoppedEventArgs;
using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEScanningMode;
using ::winrt::Windows::Storage::Streams::DataWriter;
template <typename T>
using IVector = winrt::Windows::Foundation::Collections::IVector<T>;
} // namespace
BleMedium::BleMedium(api::BluetoothAdapter& adapter)
: adapter_(static_cast<api::BluetoothAdapter*>(&adapter)) {}
bool BleMedium::StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << "Windows Ble StartAdvertising: service_id=" << service_id
<< ", advertisement bytes=" << advertisement_bytes.data()
<< "(" << advertisement_bytes.size() << "),"
<< " fast advertisement service uuid="
<< fast_advertisement_service_uuid;
DataWriter data_writer;
for (int i = 0; i < advertisement_bytes.size(); ++i) {
data_writer.WriteByte(
static_cast<uint8_t>(*(advertisement_bytes.data() + i)));
}
BluetoothLEAdvertisementDataSection service_data =
BluetoothLEAdvertisementDataSection(0x16, data_writer.DetachBuffer());
IVector<BluetoothLEAdvertisementDataSection> data_sections =
advertisement_.DataSections();
data_sections.Append(service_data);
advertisement_.DataSections() = data_sections;
publisher_ = BluetoothLEAdvertisementPublisher(advertisement_);
publisher_token_ =
publisher_.StatusChanged({this, &BleMedium::PublisherHandler});
std::future<PublisherState> publisher_state_future =
publisher_started_promise_.get_future();
publisher_.Start();
return publisher_state_future.get() == PublisherState::kStarted;
}
bool BleMedium::StopAdvertising(const std::string& service_id) {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << "Windows Ble StopAdvertising: service_id=" << service_id;
std::future<PublisherState> publisher_state_future =
publisher_stopped_promise_.get_future();
publisher_.Stop();
return publisher_state_future.get() == PublisherState::kStopped;
}
bool BleMedium::StartScanning(
const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << "Windows Ble StartScanning: service_id=" << service_id;
advertisement_received_callback_ = std::move(callback);
watcher_token_ = watcher_.Stopped({this, &BleMedium::WatcherHandler});
advertisement_received_token_ =
watcher_.Received({this, &BleMedium::AdvertisementReceivedHandler});
std::future<WatcherState> watcher_state_future =
watcher_started_promise_.get_future();
// Active mode indicates that scan request packets will be sent to query for
// Scan Response
watcher_.ScanningMode(BluetoothLEScanningMode::Active);
watcher_.Start();
while (!is_watcher_started_) {
if (watcher_.Status() == BluetoothLEAdvertisementWatcherStatus::Created) {
watcher_started_promise_.set_value(WatcherState::kStarted);
return true;
}
}
return true;
}
bool BleMedium::StopScanning(const std::string& service_id) {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << "Windows Ble StopScanning: service_id=" << service_id;
std::future<WatcherState> watcher_state_future =
watcher_stopped_promise_.get_future();
watcher_.Stop();
while (!is_watcher_stopped_) {
if (watcher_.Status() == BluetoothLEAdvertisementWatcherStatus::Stopped) {
watcher_stopped_promise_.set_value(WatcherState::kStopped);
watcher_.Stopped(watcher_token_);
watcher_.Received(advertisement_received_token_);
return true;
}
}
return true;
}
bool BleMedium::StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback) {
NEARBY_LOGS(INFO) << "Windows Ble StartAcceptingConnections: service_id="
<< service_id;
return true;
}
bool BleMedium::StopAcceptingConnections(const std::string& service_id) {
NEARBY_LOGS(INFO) << "Windows Ble StopAcceptingConnections: service_id="
<< service_id;
return true;
}
std::unique_ptr<api::BleSocket> BleMedium::Connect(
api::BlePeripheral& remote_peripheral, const std::string& service_id,
CancellationFlag* cancellation_flag) {
if (cancellation_flag->Cancelled()) {
NEARBY_LOGS(ERROR) << "Windows BLE Connect: Has been cancelled: "
"service_id="
<< service_id;
return {};
}
NEARBY_LOGS(ERROR) << "Windows Ble Connect: Cannot connect over BLE socket. "
"service_id="
<< service_id;
return {};
}
void BleMedium::PublisherHandler(
BluetoothLEAdvertisementPublisher publisher,
BluetoothLEAdvertisementPublisherStatusChangedEventArgs args) {
switch (args.Status()) {
case BluetoothLEAdvertisementPublisherStatus::Started:
publisher_started_promise_.set_value(PublisherState::kStarted);
break;
case BluetoothLEAdvertisementPublisherStatus::Stopped:
publisher_stopped_promise_.set_value(PublisherState::kStopped);
publisher_.StatusChanged(publisher_token_);
break;
case BluetoothLEAdvertisementPublisherStatus::Aborted:
switch (args.Error()) {
case BluetoothError::RadioNotAvailable:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"radio not available.";
break;
case BluetoothError::ResourceInUse:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium advertising failed due to resource in use.";
break;
case BluetoothError::DisabledByPolicy:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"disabled by policy.";
break;
case BluetoothError::DisabledByUser:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"disabled by user.";
break;
case BluetoothError::NotSupported:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"hardware not supported.";
break;
case BluetoothError::TransportNotSupported:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"transport not supported.";
break;
case BluetoothError::ConsentRequired:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"consent required.";
break;
case BluetoothError::OtherError:
default:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium advertising failed due to unknown errors.";
break;
}
publisher_started_promise_.set_value(PublisherState::kError);
publisher_stopped_promise_.set_value(PublisherState::kError);
break;
default:
break;
}
}
void BleMedium::WatcherHandler(
BluetoothLEAdvertisementWatcher watcher,
BluetoothLEAdvertisementWatcherStoppedEventArgs args) {
switch (args.Error()) {
case BluetoothError::RadioNotAvailable:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to radio not available.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
case BluetoothError::ResourceInUse:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to resource in use.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
case BluetoothError::DisabledByPolicy:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to disabled by policy.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
case BluetoothError::DisabledByUser:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to disabled by user.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
case BluetoothError::NotSupported:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to hardware not supported.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
case BluetoothError::TransportNotSupported:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium scanning failed due to "
"transport not supported.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
case BluetoothError::ConsentRequired:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to consent required.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
case BluetoothError::OtherError:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to unknown errors.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
break;
default:
if (watcher_.Status() == BluetoothLEAdvertisementWatcherStatus::Started) {
watcher_started_promise_.set_value(WatcherState::kStarted);
is_watcher_started_ = true;
}
if (watcher_.Status() == BluetoothLEAdvertisementWatcherStatus::Stopped) {
watcher_stopped_promise_.set_value(WatcherState::kStopped);
watcher_.Stopped(watcher_token_);
watcher_.Received(advertisement_received_token_);
is_watcher_stopped_ = true;
} else {
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium scanning failed due to unknown errors.";
watcher_started_promise_.set_value(WatcherState::kError);
watcher_stopped_promise_.set_value(WatcherState::kError);
}
break;
}
}
void BleMedium::AdvertisementReceivedHandler(
BluetoothLEAdvertisementWatcher watcher,
BluetoothLEAdvertisementReceivedEventArgs args) {
// Handle all BLE advertisements and determine whether the BLE Medium
// Advertisement Scan Response packet (containing Copresence UUID 0xFEF3) has
// been received in the handler
std::array<uint8_t, 8> bluetooth_base_array = {
static_cast<uint8_t>(0x80), static_cast<uint8_t>(0x00),
static_cast<uint8_t>(0x00), static_cast<uint8_t>(0x80),
static_cast<uint8_t>(0x5F), static_cast<uint8_t>(0x9B),
static_cast<uint8_t>(0x34), static_cast<uint8_t>(0xFB)};
winrt::guid kCopresenceServiceUuid128bit(
static_cast<uint32_t>(0x0000FEF3), static_cast<uint16_t>(0x0000),
static_cast<uint16_t>(0x1000), bluetooth_base_array);
IVector<winrt::guid> guids = args.Advertisement().ServiceUuids();
bool is_advertisement_found = false;
for (const winrt::guid& uuid : guids) {
if (uuid == kCopresenceServiceUuid128bit) {
is_advertisement_found = true;
}
}
if (is_advertisement_found == true) {
BlePeripheral peripheral;
advertisement_received_callback_.peripheral_discovered_cb(peripheral,
"\xfe\xf3", true);
}
}
} // namespace windows
} // namespace nearby
} // namespace location
@@ -0,0 +1,133 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_MEDIUM_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_MEDIUM_H_
#include <guiddef.h>
#include <functional>
#include <future> // NOLINT
#include <string>
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/ble.h"
#include "winrt/Windows.Devices.Bluetooth.Advertisement.h"
namespace location {
namespace nearby {
namespace windows {
// Only Fast Advertisement is supported where the remote device's static
// bluetooth MAC address is resolved from Nearby Share Contact certificates
// using salt and encrypted_metadata_key from the BLE advertisement packet.
// The MAC address is then used directly to establish a Bluetooth Classic
// RFCOMM socket.
// Container of operations that can be performed over the BLE medium.
class BleMedium : public api::BleMedium {
public:
explicit BleMedium(api::BluetoothAdapter& adapter);
~BleMedium() override = default;
bool StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertising(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once the BLE scan has been initiated.
bool StartScanning(const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once BLE scanning for service_id is well and truly stopped;
// after this returns, there must be no more invocations of the
// DiscoveredPeripheralCallback passed in to StartScanning() for service_id.
bool StopScanning(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once BLE socket connection requests to service_id can be
// accepted.
bool StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAcceptingConnections(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Connects to a BLE peripheral.
// On success, returns a new BleSocket.
// On error, returns nullptr.
std::unique_ptr<api::BleSocket> Connect(
api::BlePeripheral& peripheral, const std::string& service_id,
CancellationFlag* cancellation_flag) override ABSL_LOCKS_EXCLUDED(mutex_);
private:
enum class PublisherState { kStarted = 0, kStopped, kError };
enum class WatcherState { kStarted = 0, kStopped, kError };
absl::Mutex mutex_;
api::BluetoothAdapter* adapter_;
ByteArray advertisement_byte_ ABSL_GUARDED_BY(mutex_);
DiscoveredPeripheralCallback advertisement_received_callback_;
// WinRT objects
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementPublisher publisher_;
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcher watcher_;
::winrt::Windows::Devices::Bluetooth::Advertisement::BluetoothLEAdvertisement
advertisement_;
void PublisherHandler(
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementPublisher publisher,
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementPublisherStatusChangedEventArgs args);
void AdvertisementReceivedHandler(
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcher watcher,
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementReceivedEventArgs args);
void WatcherHandler(::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcher watcher,
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcherStoppedEventArgs args);
::winrt::event_token publisher_token_;
std::promise<PublisherState> publisher_started_promise_;
std::promise<PublisherState> publisher_stopped_promise_;
::winrt::event_token watcher_token_;
std::promise<WatcherState> watcher_started_promise_;
std::promise<WatcherState> watcher_stopped_promise_;
bool is_watcher_started_ = false;
bool is_watcher_stopped_ = false;
::winrt::event_token advertisement_received_token_;
};
} // namespace windows
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_MEDIUM_H_
@@ -0,0 +1,203 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/windows/ble_medium.h"
#include <array>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/synchronization/notification.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/ble.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
namespace location {
namespace nearby {
namespace windows {
namespace {
constexpr uint8_t kCopresenceServiceUuid[] = {0xfe, 0xf3};
constexpr uint8_t kVersionBitmask = 0xE0;
constexpr uint8_t kSocketVersionBitmask = 0x1C;
constexpr uint8_t kFastAdvertisementFlagBitmask = 0x02;
constexpr uint8_t kPcpBitmask = 0x1F;
constexpr uint8_t kVisibilityBitmask = 0x01;
TEST(BleMedium, DISABLED_StartAdvertising) {
BluetoothAdapter bluetoothAdapter;
BleMedium ble_medium(bluetoothAdapter);
std::array<char, 29> advertising_data_byte_array;
// (2 bytes) 16-bit Service UUID 0xf3fe
advertising_data_byte_array.at(0) =
static_cast<unsigned char>(kCopresenceServiceUuid[1]);
advertising_data_byte_array.at(1) =
static_cast<unsigned char>(kCopresenceServiceUuid[0]);
// (1 byte) version [3-bits] + socket_version [3-bits] +
// fast_advertisement_flag [1-bit] + reserved [1-bit]
uint8_t ble_medium_version = 0x02; // mediums::BleAdvertisement::Version::kV2
uint8_t socket_version =
0x02; // mediums::BleAdvertisement::SocketVersion::kV2
bool fast_advertisement = true; // Is Fast Advertisement
uint8_t ble_medium_advertisement_metadata_byte =
(ble_medium_version << 5) & kVersionBitmask;
ble_medium_advertisement_metadata_byte |=
(socket_version << 2) & kSocketVersionBitmask;
ble_medium_advertisement_metadata_byte |=
((fast_advertisement ? 1 : 0) << 1) & kFastAdvertisementFlagBitmask;
advertising_data_byte_array.at(2) =
static_cast<unsigned char>(ble_medium_advertisement_metadata_byte);
// (1 byte) body_length
advertising_data_byte_array.at(3) = static_cast<unsigned char>(
0x19); // always 25 bytes for Fast Advertisement
// (1 byte) Nearby Connection version [3-bits] + pcp [5-bits]
uint8_t ble_connections_version =
0x01; // connections::BleAdvertisement::Version::kV1
uint8_t pcp = 0x02; // connections::Pcp::kP2pCluster
uint8_t ble_connections_advertisement_metadata_byte =
(ble_connections_version << 5) & kVersionBitmask;
ble_connections_advertisement_metadata_byte |= pcp & kPcpBitmask;
advertising_data_byte_array.at(4) =
static_cast<unsigned char>(ble_connections_advertisement_metadata_byte);
// (4 bytes) endpoint_id
for (int i = 0; i < 4; ++i) {
advertising_data_byte_array.at(5 + i) = static_cast<unsigned char>(0x00);
}
// (1 byte) endpoint_info_size
advertising_data_byte_array.at(9) = static_cast<unsigned char>(
0x11); // always 17-bytes for Fast Advertisement
// =========endpoint_info [17-bytes]============
// (1 byte) Nearby Share version [3-bits] + visibility [1-bit] + reserved
// [4-bits]
uint8_t nearby_share_version = 0x00; // nearby share v1
uint8_t visibility = 0x00; // [placeholder] sharing::Visibility::kAllContacts
uint8_t nearby_share_metadata_byte =
(nearby_share_version << 5) & kVersionBitmask;
nearby_share_metadata_byte |= ((visibility & kVisibilityBitmask) << 4);
advertising_data_byte_array.at(10) = static_cast<unsigned char>(0x00);
// (2 bytes) salt
for (int i = 0; i < 2; ++i) {
advertising_data_byte_array.at(11 + i) = static_cast<unsigned char>(0x00);
}
// (14 bytes) encrypted_metadata_key
for (int i = 0; i < 14; ++i) {
advertising_data_byte_array.at(13 + i) = static_cast<unsigned char>(0x00);
}
// =========endpoint_info [17-bytes]============
// (2 bytes) device_token
for (int i = 0; i < 2; ++i) {
advertising_data_byte_array.at(27 + i) = static_cast<unsigned char>(0x00);
}
ByteArray advertising_data(advertising_data_byte_array);
EXPECT_TRUE(
ble_medium.StartAdvertising("NearbyShare", advertising_data, "\xfe\xf3"));
}
TEST(BleMedium, DISABLED_StopAdvertising) {
BluetoothAdapter bluetoothAdapter;
BleMedium ble_medium(bluetoothAdapter);
std::array<char, 2> advertising_data_byte_array;
// (2 bytes) 16-bit Service UUID 0xf3fe
advertising_data_byte_array.at(0) =
static_cast<unsigned char>(kCopresenceServiceUuid[1]);
advertising_data_byte_array.at(1) =
static_cast<unsigned char>(kCopresenceServiceUuid[0]);
ByteArray advertising_data(advertising_data_byte_array);
EXPECT_TRUE(
ble_medium.StartAdvertising("NearbyShare", advertising_data, "\xfe\xf3"));
EXPECT_TRUE(ble_medium.StopAdvertising("NearbyShare"));
}
TEST(BleMedium, DISABLED_StartScanning) {
BluetoothAdapter bluetoothAdapter;
BleMedium ble_medium(bluetoothAdapter);
BleMedium::DiscoveredPeripheralCallback discovered_peripheral_callback = {
.peripheral_discovered_cb = [this](api::BlePeripheral& peripheral,
const std::string& service_id,
bool fast_advertisement) {},
.peripheral_lost_cb = [this](api::BlePeripheral& peripheral,
const std::string& service_id) {}};
EXPECT_TRUE(ble_medium.StartScanning("NearbyShare", "\xfe\xf3",
discovered_peripheral_callback));
}
TEST(BleMedium, DISABLED_ReceiveAdvertisement) {
absl::Notification advertisement_received_notification;
BluetoothAdapter bluetoothAdapter;
BleMedium ble_medium(bluetoothAdapter);
BleMedium::DiscoveredPeripheralCallback discovered_peripheral_callback = {
.peripheral_discovered_cb =
[this, &advertisement_received_notification](
api::BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) {
advertisement_received_notification.Notify();
},
.peripheral_lost_cb = [this](api::BlePeripheral& peripheral,
const std::string& service_id) {}};
EXPECT_TRUE(ble_medium.StartScanning("NearbyShare", "\xfe\xf3",
discovered_peripheral_callback));
EXPECT_TRUE(
advertisement_received_notification.WaitForNotificationWithTimeout(
absl::Seconds(5)));
}
TEST(BleMedium, DISABLED_StopScanning) {
BluetoothAdapter bluetoothAdapter;
BleMedium ble_medium(bluetoothAdapter);
BleMedium::DiscoveredPeripheralCallback discovered_peripheral_callback = {
.peripheral_discovered_cb =
[this](api::BlePeripheral& peripheral, const std::string& service_id,
bool fast_advertisement) { EXPECT_TRUE(fast_advertisement); },
.peripheral_lost_cb = [this](api::BlePeripheral& peripheral,
const std::string& service_id) {}};
EXPECT_TRUE(ble_medium.StartScanning("NearbyShare", "\xfe\xf3",
discovered_peripheral_callback));
EXPECT_TRUE(ble_medium.StopScanning("NearbyShare"));
}
} // namespace
} // namespace windows
} // namespace nearby
} // namespace location
@@ -0,0 +1,50 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_PERIPHERAL_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_PERIPHERAL_H_
#include <string>
#include "internal/platform/implementation/ble.h"
namespace location {
namespace nearby {
namespace windows {
// TODO(b/184975123): Implement BLE Peripheral
// This is just a fake stub to appease the BLE Medium abstraction. Windows
// does not support BLE GATT-based advertising/discovery and socket currently,
// so a BlePeripheral is not required. The remote device is recognized as a
// BluetoothClassicDevice instead.
// Opaque wrapper over a BLE peripheral. Must contain enough data about a
// particular BLE device to connect to its GATT server.
class BlePeripheral : public api::BlePeripheral {
public:
~BlePeripheral() override = default;
std::string GetName() const override { return ""; }
ByteArray GetAdvertisementBytes(
const std::string& service_id) const override {
return ByteArray{};
}
};
} // namespace windows
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_PERIPHERAL_H_
@@ -0,0 +1,49 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/windows/ble_socket.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
namespace location {
namespace nearby {
namespace windows {
InputStream& BleSocket::GetInputStream() {
return fake_input_stream_;
}
OutputStream& BleSocket::GetOutputStream() {
return fake_output_stream_;
}
bool BleSocket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
Exception BleSocket::Close() {
absl::MutexLock lock(&mutex_);
return {Exception::kSuccess};
}
BlePeripheral* BleSocket::GetRemotePeripheral() {
absl::MutexLock lock(&mutex_);
return peripheral_;
}
} // namespace windows
} // namespace nearby
} // namespace location
@@ -0,0 +1,83 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_SOCKET_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_SOCKET_H_
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/windows/ble.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
namespace location {
namespace nearby {
namespace windows {
// TODO(b/184975123): Implement BLE Weave Socket
// This is just a fake stub to appease the BLE Medium abstraction. Windows
// does not support BLE Weave sockets currently. BLE is only used in the
// pre-connection phase handshake (advertising & discovering), connection is
// delegated to Bluetooth Classic Medium to establish RFCOMM socket.
class BleSocket : public api::BleSocket {
public:
~BleSocket() override;
// Returns the InputStream of this connected BleSocket.
InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the OutputStream of this connected BleSocket.
// This stream is for local side to write.
OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if socket is closed.
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
BlePeripheral* GetRemotePeripheral() override ABSL_LOCKS_EXCLUDED(mutex_);
// Unhooked InputStream & OutputStream for empty implementation.
private:
class FakeInputStream : public InputStream {
~FakeInputStream() override = default;
ExceptionOr<ByteArray> Read(std::int64_t size) override {
return ExceptionOr<ByteArray>(Exception::kFailed);
}
Exception Close() override { return {.value = Exception::kFailed}; }
};
class FakeOutputStream : public OutputStream {
~FakeOutputStream() override = default;
Exception Write(const ByteArray& data) override {
return {.value = Exception::kFailed};
}
Exception Flush() override { return {.value = Exception::kFailed}; }
Exception Close() override { return {.value = Exception::kFailed}; }
};
FakeInputStream fake_input_stream_;
FakeOutputStream fake_output_stream_;
mutable absl::Mutex mutex_;
BlePeripheral* peripheral_;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
} // namespace windows
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_SOCKET_H_
@@ -208,10 +208,9 @@ ImplementationPlatform::CreateBluetoothClassicMedium(
return absl::make_unique<windows::BluetoothClassicMedium>(adapter);
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(
BluetoothAdapter& adapter) {
return absl::make_unique<windows::BleMedium>();
return absl::make_unique<windows::BleMedium>(adapter);
}
// TODO(b/184975123): replace with real implementation.