0

[Nearby] Implement BleMedium scanning.

Implement BleMedium::StartScanning() and BleMedium::StopScanning().
This requires adding a ServiceDataMap (mapping from service id to
service data) to bluetooth::mojom::DeviceInfo, to represent BLE
advertisements.

See go/nearby-chrome-bt for more details.

Bug: b:154848193
Change-Id: I40489f8128bcda9409b20b43be52e73b2a9a2240
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2370094
Commit-Queue: Ryan Hansberry <hansberry@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Reviewed-by: James Vecore <vecore@google.com>
Cr-Commit-Position: refs/heads/master@{#805582}
This commit is contained in:
Ryan Hansberry
2020-09-10 00:57:32 +00:00
committed by Commit Bot
parent d3cd5999d1
commit ced2fad602
9 changed files with 523 additions and 22 deletions

@ -139,8 +139,17 @@ ImplementationPlatform::CreateBluetoothClassicMedium(
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(
api::BluetoothAdapter& adapter) {
// TODO (hansberry): Inject bluetooth::mojom::Adapter into BleMedium.
return std::make_unique<chrome::BleMedium>();
// Ignore the provided |adapter| argument. It provides no interface useful
// to implement chrome::BleMedium.
auto& connections = connections::NearbyConnections::GetInstance();
bluetooth::mojom::Adapter* bluetooth_adapter =
connections.GetBluetoothAdapter();
if (!bluetooth_adapter)
return nullptr;
return std::make_unique<chrome::BleMedium>(bluetooth_adapter);
}
std::unique_ptr<ble_v2::BleMedium> ImplementationPlatform::CreateBleV2Medium(

@ -4,11 +4,13 @@
#include "chrome/services/sharing/nearby/platform_v2/ble_medium.h"
#include "chrome/services/sharing/nearby/platform_v2/bluetooth_device.h"
namespace location {
namespace nearby {
namespace chrome {
BleMedium::BleMedium() = default;
BleMedium::BleMedium(bluetooth::mojom::Adapter* adapter) : adapter_(adapter) {}
BleMedium::~BleMedium() = default;
@ -28,15 +30,59 @@ bool BleMedium::StopAdvertising(const std::string& service_id) {
bool BleMedium::StartScanning(const std::string& service_id,
api::BleMedium::DiscoveredPeripheralCallback
discovered_peripheral_callback) {
// TODO(b/154848193): Implement this method.
NOTIMPLEMENTED();
auto service_uuid = device::BluetoothUUID(service_id);
if (IsScanning() &&
base::Contains(discovered_peripheral_callbacks_map_, service_uuid)) {
return true;
}
// We only need to start discovery if no other discovery request is active.
if (discovered_peripheral_callbacks_map_.empty()) {
discovered_ble_peripherals_map_.clear();
bool success =
adapter_->AddObserver(adapter_observer_.BindNewPipeAndPassRemote());
if (!success) {
adapter_observer_.reset();
return false;
}
mojo::PendingRemote<bluetooth::mojom::DiscoverySession> discovery_session;
success = adapter_->StartDiscoverySession(&discovery_session);
if (!success || !discovery_session.is_valid()) {
adapter_observer_.reset();
return false;
}
discovery_session_.Bind(std::move(discovery_session));
discovery_session_.set_disconnect_handler(
base::BindOnce(&BleMedium::DiscoveringChanged, base::Unretained(this),
/*discovering=*/false));
}
// A different DiscoveredPeripheralCallback is being passed on each call, so
// each must be captured and associated with its |service_id|.
discovered_peripheral_callbacks_map_.insert(
{service_uuid, discovered_peripheral_callback});
return true;
}
bool BleMedium::StopScanning(const std::string& service_id) {
// TODO(b/154848193): Implement this method.
NOTIMPLEMENTED();
return false;
discovered_peripheral_callbacks_map_.erase(device::BluetoothUUID(service_id));
if (!discovered_peripheral_callbacks_map_.empty())
return true;
bool stop_discovery_success = true;
if (discovery_session_) {
bool message_success = discovery_session_->Stop(&stop_discovery_success);
stop_discovery_success = stop_discovery_success && message_success;
}
adapter_observer_.reset();
discovery_session_.reset();
return stop_discovery_success;
}
bool BleMedium::StartAcceptingConnections(
@ -62,6 +108,127 @@ std::unique_ptr<api::BleSocket> BleMedium::Connect(
return nullptr;
}
void BleMedium::PresentChanged(bool present) {
// TODO(hansberry): It is unclear to me how the API implementation can signal
// to Core that |present| has become unexpectedly false. Need to ask
// Nearby team.
if (!present)
StopScanning();
}
void BleMedium::PoweredChanged(bool powered) {
// TODO(hansberry): It is unclear to me how the API implementation can signal
// to Core that |powered| has become unexpectedly false. Need to ask
// Nearby team.
if (!powered)
StopScanning();
}
void BleMedium::DiscoverableChanged(bool discoverable) {
// Do nothing. BleMedium is not responsible for managing
// discoverable state.
}
void BleMedium::DiscoveringChanged(bool discovering) {
// TODO(hansberry): It is unclear to me how the API implementation can signal
// to Core that |discovering| has become unexpectedly false. Need to ask
// Nearby team.
if (!discovering)
StopScanning();
}
void BleMedium::DeviceAdded(bluetooth::mojom::DeviceInfoPtr device) {
if (!IsScanning())
return;
// Best-effort attempt to filter out BT Classic devices. Dual-mode (BT
// Classic and BLE) devices which the system has paired and/or connected to
// may also expose service data, but all BLE advertisements that we are
// interested in are captured in an element of |service_data_map|. See
// BluetoothClassicMedium for separate discovery of BT Classic devices.
if (device->service_data_map.empty())
return;
const std::string& address = device->address;
auto* ble_peripheral = GetDiscoveredBlePeripheral(address);
if (ble_peripheral)
ble_peripheral->UpdateDeviceInfo(std::move(device));
else
discovered_ble_peripherals_map_.emplace(address, std::move(device));
// Invoking one of the callbacks in |discovered_peripheral_callbacks_map_| may
// lead to invalidating one or all elements of
// |discovered_peripheral_callbacks_map_|, e.g., triggering StopScanning()
// while looping through it. Callbacks are copied to ensure they are not
// modified as we loop through them.
auto callbacks_map_copy = discovered_peripheral_callbacks_map_;
for (auto& it : callbacks_map_copy) {
// Must fetch |ble_peripheral| again because it may have been invalidated by
// a prior callback in this loop.
ble_peripheral = GetDiscoveredBlePeripheral(address);
if (!ble_peripheral)
break;
const auto& service_id = it.first.value();
if (ble_peripheral->GetAdvertisementBytes(service_id).Empty())
continue;
it.second.peripheral_discovered_cb(*ble_peripheral, service_id);
}
}
void BleMedium::DeviceChanged(bluetooth::mojom::DeviceInfoPtr device) {
DeviceAdded(std::move(device));
}
void BleMedium::DeviceRemoved(bluetooth::mojom::DeviceInfoPtr device) {
if (!IsScanning())
return;
const std::string& address = device->address;
if (!GetDiscoveredBlePeripheral(address))
return;
// Invoking one of the callbacks in |discovered_peripheral_callbacks_map_| may
// lead to invalidating one or all elements of
// |discovered_peripheral_callbacks_map_|, e.g., triggering StopScanning()
// while looping through it. Callbacks are copied to ensure they are not
// modified as we loop through them.
auto callbacks_map_copy = discovered_peripheral_callbacks_map_;
for (auto& it : callbacks_map_copy) {
// Must fetch |ble_peripheral| again because it may have been invalidated by
// a prior callback in this loop.
auto* ble_peripheral = GetDiscoveredBlePeripheral(address);
if (!ble_peripheral)
break;
it.second.peripheral_lost_cb(*ble_peripheral,
/*service_id=*/it.first.value());
}
discovered_ble_peripherals_map_.erase(address);
}
bool BleMedium::IsScanning() {
return adapter_observer_.is_bound() && discovery_session_.is_bound() &&
!discovered_peripheral_callbacks_map_.empty();
}
void BleMedium::StopScanning() {
// We cannot simply iterate over |discovered_peripheral_callbacks_map_|
// because StopScanning() will erase the provided element.
while (!discovered_peripheral_callbacks_map_.empty()) {
StopScanning(/*service_id=*/discovered_peripheral_callbacks_map_.begin()
->first.value());
}
}
chrome::BlePeripheral* BleMedium::GetDiscoveredBlePeripheral(
const std::string& address) {
auto it = discovered_ble_peripherals_map_.find(address);
return it == discovered_ble_peripherals_map_.end() ? nullptr : &it->second;
}
} // namespace chrome
} // namespace nearby
} // namespace location

@ -7,7 +7,10 @@
#include <string>
#include "chrome/services/sharing/nearby/platform_v2/ble_peripheral.h"
#include "device/bluetooth/public/mojom/adapter.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/nearby/src/cpp/platform_v2/api/ble.h"
namespace location {
@ -15,9 +18,12 @@ namespace nearby {
namespace chrome {
// Concrete BleMedium implementation.
class BleMedium : public api::BleMedium {
// api::BleMedium is a synchronous interface, so this implementation consumes
// the synchronous signatures of bluetooth::mojom::Adapter methods.
class BleMedium : public api::BleMedium,
public bluetooth::mojom::AdapterObserver {
public:
BleMedium();
explicit BleMedium(bluetooth::mojom::Adapter* adapter);
~BleMedium() override;
BleMedium(const BleMedium&) = delete;
@ -38,6 +44,44 @@ class BleMedium : public api::BleMedium {
std::unique_ptr<api::BleSocket> Connect(
api::BlePeripheral& ble_peripheral,
const std::string& service_id) override;
private:
// bluetooth::mojom::AdapterObserver:
void PresentChanged(bool present) override;
void PoweredChanged(bool powered) override;
void DiscoverableChanged(bool discoverable) override;
void DiscoveringChanged(bool discovering) override;
void DeviceAdded(bluetooth::mojom::DeviceInfoPtr device) override;
void DeviceChanged(bluetooth::mojom::DeviceInfoPtr device) override;
void DeviceRemoved(bluetooth::mojom::DeviceInfoPtr device) override;
// Query if any service IDs are being scanned for.
bool IsScanning();
// End discovery for all requested services.
void StopScanning();
// Returns nullptr if no BlePeripheral at |address| exists.
chrome::BlePeripheral* GetDiscoveredBlePeripheral(const std::string& address);
// This reference is owned by the top-level Nearby Connections interface and
// will always outlive this object.
bluetooth::mojom::Adapter* adapter_ = nullptr;
// |adapter_observer_| is only set and bound during active discovery so that
// events we don't care about outside of discovery don't pile up.
mojo::Receiver<bluetooth::mojom::AdapterObserver> adapter_observer_{this};
// Keyed by requested service UUID. Discovery is active as long as this map is
// non-empty.
std::map<device::BluetoothUUID, DiscoveredPeripheralCallback>
discovered_peripheral_callbacks_map_;
// Only set while discovery is active.
mojo::Remote<bluetooth::mojom::DiscoverySession> discovery_session_;
// Keyed by address of advertising remote device.
std::map<std::string, chrome::BlePeripheral> discovered_ble_peripherals_map_;
};
} // namespace chrome

@ -6,9 +6,16 @@
#include <memory>
#include "base/bind.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
#include "chrome/services/sharing/nearby/platform_v2/ble_peripheral.h"
#include "chrome/services/sharing/nearby/platform_v2/bluetooth_device.h"
#include "chrome/services/sharing/nearby/test_support/fake_adapter.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace location {
@ -18,6 +25,11 @@ namespace chrome {
namespace {
const char kServiceName[] = "NearbySharing";
const char kServiceId1[] = "00000000-0000-0000-0000-000000000001";
const char kServiceId2[] = "00000000-0000-0000-0000-000000000002";
const char kDeviceAddress[] = "DeviceAddress";
const char kDeviceServiceData1Str[] = "Device_Advertisement1";
const char kDeviceServiceData2Str[] = "Device_Advertisement2";
} // namespace
@ -28,11 +40,181 @@ class BleMediumTest : public testing::Test {
BleMediumTest(const BleMediumTest&) = delete;
BleMediumTest& operator=(const BleMediumTest&) = delete;
void SetUp() override { ble_medium_ = std::make_unique<BleMedium>(); }
void SetUp() override {
auto fake_adapter = std::make_unique<bluetooth::FakeAdapter>();
fake_adapter_ = fake_adapter.get();
mojo::PendingRemote<bluetooth::mojom::Adapter> pending_adapter;
mojo::MakeSelfOwnedReceiver(
std::move(fake_adapter),
pending_adapter.InitWithNewPipeAndPassReceiver());
remote_adapter_.Bind(std::move(pending_adapter),
/*bind_task_runner=*/nullptr);
ble_medium_ = std::make_unique<BleMedium>(remote_adapter_.get());
discovered_peripheral_callback_ = {
.peripheral_discovered_cb =
[this](api::BlePeripheral& peripheral,
const std::string& service_id) {
OnPeripheralDiscovered(peripheral, service_id);
},
.peripheral_lost_cb =
[this](api::BlePeripheral& peripheral,
const std::string& service_id) {
OnPeripheralLost(peripheral, service_id);
}};
}
protected:
void StartScanning(const std::string& service_id) {
EXPECT_EQ(!scanning_service_ids_set_.empty(),
fake_adapter_->IsDiscoverySessionActive());
scanning_service_ids_set_.insert(service_id);
EXPECT_TRUE(ble_medium_->StartScanning(service_id,
discovered_peripheral_callback_));
EXPECT_TRUE(fake_adapter_->IsDiscoverySessionActive());
}
void StopScanning(const std::string& service_id) {
base::RunLoop run_loop;
bool is_last_service = scanning_service_ids_set_.size() == 1u;
if (is_last_service) {
fake_adapter_->SetDiscoverySessionDestroyedCallback(
run_loop.QuitClosure());
}
ble_medium_->StopScanning(service_id);
if (is_last_service)
run_loop.Run();
EXPECT_EQ(!is_last_service, fake_adapter_->IsDiscoverySessionActive());
scanning_service_ids_set_.erase(service_id);
}
void NotifyDeviceAdded(
const std::string& address,
const base::flat_map<device::BluetoothUUID, std::vector<uint8_t>>&
service_data_map,
uint32_t num_expected_peripherals_discovered) {
base::RunLoop run_loop;
SetOnExpectedPeripheralsDiscoveredCallback(
run_loop.QuitClosure(), num_expected_peripherals_discovered);
fake_adapter_->NotifyDeviceAdded(
CreateDeviceInfo(address, service_data_map));
run_loop.Run();
}
void NotifyDeviceChanged(
const std::string& address,
const base::flat_map<device::BluetoothUUID, std::vector<uint8_t>>&
service_data_map,
uint32_t num_expected_peripherals_discovered) {
base::RunLoop run_loop;
SetOnExpectedPeripheralsDiscoveredCallback(
run_loop.QuitClosure(), num_expected_peripherals_discovered);
fake_adapter_->NotifyDeviceChanged(
CreateDeviceInfo(address, service_data_map));
run_loop.Run();
}
void NotifyDeviceRemoved(const std::string& address,
uint32_t num_expected_peripherals_lost) {
base::RunLoop run_loop;
SetOnExpectedPeripheralsLostCallback(run_loop.QuitClosure(),
num_expected_peripherals_lost);
fake_adapter_->NotifyDeviceRemoved(
CreateDeviceInfo(address, /*service_data_map=*/{}));
run_loop.Run();
}
std::vector<uint8_t> GetByteVector(const std::string& str) {
return std::vector<uint8_t>(str.begin(), str.end());
}
void VerifyByteArrayEquals(const ByteArray& byte_array,
const std::string& expected_value) {
EXPECT_EQ(expected_value,
std::string(byte_array.data(), byte_array.size()));
}
bluetooth::FakeAdapter* fake_adapter_;
mojo::SharedRemote<bluetooth::mojom::Adapter> remote_adapter_;
std::unique_ptr<BleMedium> ble_medium_;
BleMedium::DiscoveredPeripheralCallback discovered_peripheral_callback_;
std::vector<std::pair<api::BlePeripheral*, std::string>>
last_peripheral_discovered_args_;
std::vector<std::pair<api::BlePeripheral*, std::string>>
last_peripheral_lost_args_;
private:
void SetOnExpectedPeripheralsDiscoveredCallback(
base::OnceClosure callback,
uint32_t num_expected_peripherals_discovered) {
on_expected_peripherals_discovered_callback_ = std::move(callback);
num_expected_peripherals_discovered_ = num_expected_peripherals_discovered;
last_peripheral_discovered_args_.clear();
}
void SetOnExpectedPeripheralsLostCallback(
base::OnceClosure callback,
uint32_t num_expected_peripherals_lost) {
on_expected_peripherals_lost_callback_ = std::move(callback);
num_expected_peripherals_lost_ = num_expected_peripherals_lost;
last_peripheral_lost_args_.clear();
}
void OnPeripheralDiscovered(api::BlePeripheral& ble_peripheral,
const std::string& service_id) {
last_peripheral_discovered_args_.emplace_back(
std::make_pair(&ble_peripheral, service_id));
if (last_peripheral_discovered_args_.size() ==
num_expected_peripherals_discovered_) {
std::move(on_expected_peripherals_discovered_callback_).Run();
num_expected_peripherals_discovered_ = 0;
}
}
void OnPeripheralLost(api::BlePeripheral& ble_peripheral,
const std::string& service_id) {
last_peripheral_lost_args_.emplace_back(
std::make_pair(&ble_peripheral, service_id));
if (last_peripheral_lost_args_.size() == num_expected_peripherals_lost_) {
std::move(on_expected_peripherals_lost_callback_).Run();
num_expected_peripherals_lost_ = 0;
}
}
bluetooth::mojom::DeviceInfoPtr CreateDeviceInfo(
const std::string& address,
const base::flat_map<device::BluetoothUUID, std::vector<uint8_t>>&
service_data_map) {
// Do not set |name|. This reflects Chrome's usual representation of a BLE
// advertisement.
auto device_info = bluetooth::mojom::DeviceInfo::New();
device_info->address = address;
device_info->name_for_display = address;
device_info->service_data_map = service_data_map;
return device_info;
}
std::set<std::string> scanning_service_ids_set_;
base::OnceClosure on_expected_peripherals_discovered_callback_;
uint32_t num_expected_peripherals_discovered_ = 0;
base::OnceClosure on_expected_peripherals_lost_callback_;
uint32_t num_expected_peripherals_lost_ = 0;
base::test::TaskEnvironment task_environment_;
};
@ -40,8 +222,77 @@ TEST_F(BleMediumTest, TestAdvertising) {
// TODO(b/154845685): Write test.
}
TEST_F(BleMediumTest, TestScanning) {
// TODO(b/154848193): Write test.
TEST_F(BleMediumTest, TestScanning_OneService) {
StartScanning(kServiceId1);
base::flat_map<device::BluetoothUUID, std::vector<uint8_t>> service_data_map;
service_data_map.insert_or_assign(device::BluetoothUUID(kServiceId1),
GetByteVector(kDeviceServiceData1Str));
NotifyDeviceAdded(kDeviceAddress, service_data_map,
/*num_expected_peripherals_discovered=*/1u);
ASSERT_EQ(1u, last_peripheral_discovered_args_.size());
auto& last_peripheral_discovered_args = last_peripheral_discovered_args_[0];
const auto* first_discovered_ble_peripheral =
last_peripheral_discovered_args.first;
EXPECT_EQ(kServiceId1, last_peripheral_discovered_args.second);
VerifyByteArrayEquals(
first_discovered_ble_peripheral->GetAdvertisementBytes(kServiceId1),
kDeviceServiceData1Str);
// The same information should be returned on a DeviceChanged event, with
// the same BlePeripheral reference.
NotifyDeviceChanged(kDeviceAddress, service_data_map,
/*num_expected_peripherals_discovered=*/1u);
ASSERT_EQ(1u, last_peripheral_discovered_args_.size());
last_peripheral_discovered_args = last_peripheral_discovered_args_[0];
EXPECT_EQ(first_discovered_ble_peripheral,
last_peripheral_discovered_args.first);
EXPECT_EQ(kServiceId1, last_peripheral_discovered_args.second);
VerifyByteArrayEquals(
last_peripheral_discovered_args.first->GetAdvertisementBytes(kServiceId1),
kDeviceServiceData1Str);
// Again, the same BlePeripheral reference should be marked as lost.
NotifyDeviceRemoved(kDeviceAddress, /*num_expected_peripherals_lost=*/1u);
ASSERT_EQ(1u, last_peripheral_lost_args_.size());
const auto& last_peripheral_lost_args = last_peripheral_lost_args_[0];
const auto* lost_ble_peripheral = last_peripheral_lost_args.first;
EXPECT_EQ(first_discovered_ble_peripheral, lost_ble_peripheral);
EXPECT_EQ(kServiceId1, last_peripheral_lost_args.second);
StopScanning(kServiceId1);
}
TEST_F(BleMediumTest, TestScanning_MultipleServices) {
StartScanning(kServiceId1);
StartScanning(kServiceId2);
base::flat_map<device::BluetoothUUID, std::vector<uint8_t>> service_data_map;
service_data_map.insert_or_assign(device::BluetoothUUID(kServiceId1),
GetByteVector(kDeviceServiceData1Str));
service_data_map.insert_or_assign(device::BluetoothUUID(kServiceId2),
GetByteVector(kDeviceServiceData2Str));
// Discovering a device with 2 desired service ids should trigger discovery
// callbacks for both.
NotifyDeviceAdded(kDeviceAddress, service_data_map,
/*num_expected_peripherals_discovered=*/2u);
ASSERT_EQ(2u, last_peripheral_discovered_args_.size());
VerifyByteArrayEquals(
last_peripheral_discovered_args_[0].first->GetAdvertisementBytes(
kServiceId1),
kDeviceServiceData1Str);
VerifyByteArrayEquals(
last_peripheral_discovered_args_[1].first->GetAdvertisementBytes(
kServiceId2),
kDeviceServiceData2Str);
NotifyDeviceRemoved(kDeviceAddress, /*num_expected_peripherals_lost=*/2u);
ASSERT_EQ(2u, last_peripheral_lost_args_.size());
StopScanning(kServiceId1);
StopScanning(kServiceId2);
}
TEST_F(BleMediumTest, TestStartAcceptingConnections) {
@ -51,8 +302,7 @@ TEST_F(BleMediumTest, TestStartAcceptingConnections) {
}
TEST_F(BleMediumTest, TestConnect) {
BluetoothDevice bluetooth_device(bluetooth::mojom::DeviceInfo::New());
BlePeripheral ble_peripheral(bluetooth_device);
chrome::BlePeripheral ble_peripheral(bluetooth::mojom::DeviceInfo::New());
// Connect() should do nothing and not return a valid api::BleSocket.
EXPECT_FALSE(ble_medium_->Connect(ble_peripheral, kServiceName));

@ -8,19 +8,31 @@ namespace location {
namespace nearby {
namespace chrome {
BlePeripheral::BlePeripheral(api::BluetoothDevice& bluetooth_device) {}
BlePeripheral::BlePeripheral(bluetooth::mojom::DeviceInfoPtr device_info)
: device_info_(std::move(device_info)) {}
BlePeripheral::~BlePeripheral() = default;
std::string BlePeripheral::GetName() const {
// TODO(hansberry): Implement.
return std::string();
return device_info_->name_for_display;
}
ByteArray BlePeripheral::GetAdvertisementBytes(
const std::string& service_id) const {
// TODO(hansberry): Implement.
return ByteArray();
const auto& service_data_map = device_info_->service_data_map;
auto it = service_data_map.find(device::BluetoothUUID(service_id));
if (it == service_data_map.end())
return ByteArray();
std::string service_data(it->second.begin(), it->second.end());
return ByteArray(service_data);
}
void BlePeripheral::UpdateDeviceInfo(
bluetooth::mojom::DeviceInfoPtr device_info) {
DCHECK_EQ(device_info_->address, device_info->address);
device_info_ = std::move(device_info);
}
} // namespace chrome

@ -5,6 +5,7 @@
#ifndef CHROME_SERVICES_SHARING_NEARBY_PLATFORM_V2_BLE_PERIPHERAL_H_
#define CHROME_SERVICES_SHARING_NEARBY_PLATFORM_V2_BLE_PERIPHERAL_H_
#include "device/bluetooth/public/mojom/adapter.mojom.h"
#include "third_party/nearby/src/cpp/platform_v2/api/ble.h"
namespace location {
@ -14,7 +15,7 @@ namespace chrome {
// Concrete BlePeripheral implementation.
class BlePeripheral : public api::BlePeripheral {
public:
explicit BlePeripheral(api::BluetoothDevice& bluetooth_device);
explicit BlePeripheral(bluetooth::mojom::DeviceInfoPtr device_info);
~BlePeripheral() override;
BlePeripheral(const BlePeripheral&) = delete;
@ -23,6 +24,11 @@ class BlePeripheral : public api::BlePeripheral {
// api::BlePeripheral:
std::string GetName() const override;
ByteArray GetAdvertisementBytes(const std::string& service_id) const override;
void UpdateDeviceInfo(bluetooth::mojom::DeviceInfoPtr device_info);
private:
bluetooth::mojom::DeviceInfoPtr device_info_;
};
} // namespace chrome

@ -262,6 +262,7 @@ BluetoothInternalsTest.prototype = {
nameForDisplay: 'AAA',
rssi: {value: -40},
isGattConnected: false,
serviceDataMap: {},
services: [],
};
},
@ -277,6 +278,7 @@ BluetoothInternalsTest.prototype = {
nameForDisplay: 'BBB',
rssi: null,
isGattConnected: false,
serviceDataMap: {},
services: [],
};
},
@ -291,6 +293,7 @@ BluetoothInternalsTest.prototype = {
address: 'CC:CC:84:96:92:84',
name: 'CCC',
nameForDisplay: 'CCC',
serviceDataMap: {},
isGattConnected: false,
};
},

@ -45,6 +45,9 @@ mojom::DeviceInfoPtr Device::ConstructDeviceInfoStruct(
device_info->rssi->value = device->GetInquiryRSSI().value();
}
for (auto const& it : device->GetServiceData())
device_info->service_data_map.insert_or_assign(it.first, it.second);
return device_info;
}

@ -60,6 +60,13 @@ struct DeviceInfo {
string address;
bool is_gatt_connected;
RSSIWrapper? rssi;
// Important note: the "service data" associated with each UUID is an
// arbitrary binary blob of data provided by a likely untrustworthy device.
// Clients are responsible for safely parsing this information; please see
// "The Rule of 2" (//docs/security/rule-of-2.md). C++ clients must parse this
// blob in a sandbox process.
map<UUID, array<uint8>> service_data_map;
};
struct ServiceInfo {