Implement device loss alarms

PiperOrigin-RevId: 538822094
This commit is contained in:
Anay Wadhera
2023-06-08 10:19:44 -07:00
committed by Copybara-Service
parent dbd42b0de3
commit 0ab31f6312
7 changed files with 345 additions and 14 deletions
@@ -24,6 +24,7 @@
#include "securegcm/ukey2_handshake.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/escaping.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
#include "connections/advertising_options.h"
#include "connections/connection_options.h"
@@ -35,11 +36,16 @@
#include "internal/flags/nearby_flags.h"
#include "internal/platform/base64_utils.h"
#include "internal/platform/bluetooth_utils.h"
#include "internal/platform/cancelable_alarm.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace connections {
namespace {
constexpr int kEndpointCancelAlarmTimeout = 10;
} // namespace
using ::location::nearby::connections::ConnectionRequestFrame;
using ::location::nearby::connections::ConnectionResponseFrame;
using ::location::nearby::connections::MediumMetadata;
@@ -124,6 +130,7 @@ Status BasePcpHandler::StartAdvertising(
client->StartedAdvertising(service_id, GetStrategy(), info.listener,
absl::MakeSpan(result.mediums),
compatible_advertising_options);
client->UpdateLocalEndpointInfo(info.endpoint_info.string_data());
response.Set({Status::kSuccess});
});
return WaitForResult(absl::StrCat("StartAdvertising(", service_id, ")"),
@@ -781,6 +788,48 @@ BasePcpHandler::GetDiscoveredEndpoints(
return result;
}
namespace {
std::string GetEndpointLostByMediumAlarmKey(absl::string_view endpoint_id,
Medium medium) {
return absl::StrCat(location::nearby::proto::connections::Medium_Name(medium),
"_", endpoint_id);
}
} // namespace
void BasePcpHandler::StartEndpointLostByMediumAlarms(
ClientProxy* client, location::nearby::proto::connections::Medium medium) {
auto discovered_endpoints_medium = GetDiscoveredEndpoints(medium);
for (const auto discovered_endpoint : discovered_endpoints_medium) {
std::string key = GetEndpointLostByMediumAlarmKey(
discovered_endpoint->endpoint_id, medium);
StopEndpointLostByMediumAlarm(discovered_endpoint->endpoint_id, medium);
endpoint_lost_by_medium_alarms_.emplace(
key, std::make_unique<CancelableAlarm>(
absl::StrCat("EndpointLostByMediumAlarm_", key),
[this, discovered_endpoint, key, client]() {
RunOnPcpHandlerThread(
"endpoint-lost-by-medium-alarm",
[this, client, discovered_endpoint,
key]() RUN_ON_PCP_HANDLER_THREAD() {
if (endpoint_lost_by_medium_alarms_.erase(key) != 0) {
OnEndpointLost(client, *discovered_endpoint);
}
});
},
absl::Seconds(kEndpointCancelAlarmTimeout), &alarm_executor_));
}
}
void BasePcpHandler::StopEndpointLostByMediumAlarm(
absl::string_view endpoint_id,
location::nearby::proto::connections::Medium medium) {
std::string key = GetEndpointLostByMediumAlarmKey(endpoint_id, medium);
if (endpoint_lost_by_medium_alarms_.contains(key)) {
endpoint_lost_by_medium_alarms_[key]->Cancel();
endpoint_lost_by_medium_alarms_.erase(key);
}
}
mediums::WebrtcPeerId BasePcpHandler::CreatePeerIdFromAdvertisement(
const std::string& service_id, const std::string& endpoint_id,
const ByteArray& endpoint_info) {
@@ -1093,6 +1142,8 @@ void BasePcpHandler::OnEndpointFound(
owned_endpoint =
discovered_endpoints_.emplace(endpoint_id, std::move(endpoint))
->second.get();
StopEndpointLostByMediumAlarm(owned_endpoint->endpoint_id,
owned_endpoint->medium);
client->OnEndpointFound(
owned_endpoint->service_id, owned_endpoint->endpoint_id,
owned_endpoint->endpoint_info, owned_endpoint->medium);
@@ -34,6 +34,7 @@
#include "connections/implementation/pcp.h"
#include "connections/implementation/pcp_handler.h"
#include "connections/listeners.h"
#include "connections/medium_selector.h"
#include "connections/status.h"
#include "internal/platform/atomic_boolean.h"
#include "internal/platform/byte_array.h"
@@ -299,6 +300,15 @@ class BasePcpHandler : public PcpHandler,
std::vector<BasePcpHandler::DiscoveredEndpoint*> GetDiscoveredEndpoints(
const location::nearby::proto::connections::Medium medium);
// Start alarms for endpoints lost by their mediums. Used when updating
// discovery options.
void StartEndpointLostByMediumAlarms(
ClientProxy* client, location::nearby::proto::connections::Medium medium);
void StopEndpointLostByMediumAlarm(
absl::string_view endpoint_id,
location::nearby::proto::connections::Medium medium);
mediums::WebrtcPeerId CreatePeerIdFromAdvertisement(
const string& service_id, const string& endpoint_id,
const ByteArray& endpoint_info);
@@ -308,6 +318,12 @@ class BasePcpHandler : public PcpHandler,
return &serial_executor_;
}
// Test only.
absl::flat_hash_map<std::string, std::unique_ptr<CancelableAlarm>>&
GetEndpointLostByMediumAlarms() {
return endpoint_lost_by_medium_alarms_;
}
Mediums* mediums_;
EndpointManager* endpoint_manager_;
EndpointChannelManager* channel_manager_;
@@ -529,6 +545,11 @@ class BasePcpHandler : public PcpHandler,
// advertising.
ConnectionListener advertising_listener_;
// Mapping from endpoint_id -> CancelableAlarm for triggering endpoint loss
// while discovery options are updated.
absl::flat_hash_map<std::string, std::unique_ptr<CancelableAlarm>>
endpoint_lost_by_medium_alarms_;
Pcp pcp_;
Strategy strategy_{PcpToStrategy(pcp_)};
EncryptionRunner encryption_runner_;
@@ -189,6 +189,26 @@ class MockPcpHandler : public BasePcpHandler {
return BasePcpHandler::GetDiscoveredEndpoints(endpoint_id);
}
std::vector<BasePcpHandler::DiscoveredEndpoint*> GetDiscoveredEndpoints(
location::nearby::proto::connections::Medium medium) {
return BasePcpHandler::GetDiscoveredEndpoints(medium);
}
absl::flat_hash_map<std::string, std::unique_ptr<CancelableAlarm>>&
GetEndpointLostByMediumAlarms() {
return BasePcpHandler::GetEndpointLostByMediumAlarms();
}
void StartEndpointLostByMediumAlarms(
ClientProxy* client, location::nearby::proto::connections::Medium medium) {
BasePcpHandler::StartEndpointLostByMediumAlarms(client, medium);
}
void StopEndpointLostByMediumAlarm(absl::string_view endpoint_id,
location::nearby::proto::connections::Medium medium) {
BasePcpHandler::StopEndpointLostByMediumAlarm(endpoint_id, medium);
}
std::vector<location::nearby::proto::connections::Medium> GetDiscoveryMediums(
ClientProxy* client) {
auto allowed = client->GetDiscoveryOptions().CompatibleOptions().allowed;
@@ -281,6 +301,7 @@ class BasePcpHandlerTest
advertising_options, info),
Status{Status::kSuccess});
EXPECT_TRUE(client->IsAdvertising());
EXPECT_EQ(client->GetLocalEndpointInfo(), info.endpoint_info.string_data());
}
void StartDiscovery(ClientProxy* client, MockPcpHandler* pcp_handler,
@@ -819,6 +840,212 @@ TEST_F(BasePcpHandlerTest, InjectEndpoint) {
env_.Stop();
}
TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) {
env_.Start();
std::string service_id{"service"};
std::string endpoint_id{"ABCD"};
ClientProxy client;
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
BooleanMediumSelector allowed{
.bluetooth = true,
};
DiscoveryOptions discovery_options{
{
Strategy::kP2pPointToPoint,
allowed,
},
false, // auto_upgrade_bandwidth;
false, // enforce_topology_constraints;
};
EXPECT_CALL(pcp_handler, StartDiscoveryImpl)
.WillOnce(Return(MockPcpHandler::StartOperationResult{
.status = {Status::kSuccess},
.mediums = allowed.GetMediums(true),
}));
EXPECT_EQ(pcp_handler.StartDiscovery(&client, service_id, discovery_options,
{}),
Status{Status::kSuccess});
EXPECT_TRUE(client.IsDiscovering());
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.WillOnce(Invoke([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
endpoint_id,
/*endpoint_info=*/ByteArray{"ABCD"},
service_id,
Medium::BLUETOOTH,
WebRtcState::kUndefined,
},
MockContext{nullptr},
}));
return Status{Status::kSuccess};
}));
pcp_handler.InjectEndpoint(
&client, service_id,
OutOfBandConnectionMetadata{
.medium = Medium::BLUETOOTH,
.remote_bluetooth_mac_address = ByteArray(kFakeMacAddress),
});
EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0);
pcp_handler.StartEndpointLostByMediumAlarms(&client, Medium::BLUETOOTH);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 1);
pcp_handler.StopEndpointLostByMediumAlarm(endpoint_id, Medium::BLUETOOTH);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0);
env_.Stop();
}
TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) {
env_.Start();
std::string service_id{"service"};
std::string endpoint_id{"ABCD"};
ClientProxy client;
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
BooleanMediumSelector allowed{
.bluetooth = true,
};
DiscoveryOptions discovery_options{
{
Strategy::kP2pPointToPoint,
allowed,
},
false, // auto_upgrade_bandwidth;
false, // enforce_topology_constraints;
};
EXPECT_CALL(pcp_handler, StartDiscoveryImpl)
.WillOnce(Return(MockPcpHandler::StartOperationResult{
.status = {Status::kSuccess},
.mediums = allowed.GetMediums(true),
}));
EXPECT_EQ(pcp_handler.StartDiscovery(&client, service_id, discovery_options,
{}),
Status{Status::kSuccess});
EXPECT_TRUE(client.IsDiscovering());
EXPECT_CALL(pcp_handler, InjectEndpointImpl)
.WillOnce(Invoke([&pcp_handler, &endpoint_id](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
endpoint_id,
/*endpoint_info=*/ByteArray{"ABCD"},
service_id,
Medium::BLUETOOTH,
WebRtcState::kUndefined,
},
MockContext{nullptr},
}));
return Status{Status::kSuccess};
}));
pcp_handler.InjectEndpoint(
&client, service_id,
OutOfBandConnectionMetadata{
.medium = Medium::BLUETOOTH,
.remote_bluetooth_mac_address = ByteArray(kFakeMacAddress),
});
EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0);
pcp_handler.StartEndpointLostByMediumAlarms(&client, Medium::BLUETOOTH);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 1);
absl::SleepFor(absl::Seconds(11));
EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 0);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0);
env_.Stop();
}
TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) {
env_.Start();
std::string service_id{"service"};
std::string endpoint_id{"ABCD"};
ClientProxy client;
Mediums m;
EndpointChannelManager ecm;
EndpointManager em(&ecm);
BwuManager bwu(m, em, ecm, {}, {});
MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu);
BooleanMediumSelector allowed{
.bluetooth = true,
};
DiscoveryOptions discovery_options{
{
Strategy::kP2pPointToPoint,
allowed,
},
false, // auto_upgrade_bandwidth;
false, // enforce_topology_constraints;
};
EXPECT_CALL(pcp_handler, StartDiscoveryImpl)
.WillOnce(Return(MockPcpHandler::StartOperationResult{
.status = {Status::kSuccess},
.mediums = allowed.GetMediums(true),
}));
EXPECT_EQ(pcp_handler.StartDiscovery(&client, service_id, discovery_options,
{}),
Status{Status::kSuccess});
EXPECT_TRUE(client.IsDiscovering());
bool first_call = true;
EXPECT_CALL(pcp_handler, InjectEndpointImpl).Times(2)
.WillRepeatedly(Invoke([&pcp_handler, &endpoint_id, &first_call](
ClientProxy* client, const std::string& service_id,
const OutOfBandConnectionMetadata& metadata) {
ByteArray endpoint_info;
if (first_call) {
endpoint_info = ByteArray("ABCD");
} else {
endpoint_info = ByteArray("ABCDE");
}
first_call = false;
pcp_handler.OnEndpointFound(
client,
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
{
endpoint_id,
endpoint_info,
service_id,
Medium::BLUETOOTH,
WebRtcState::kUndefined,
},
MockContext{nullptr},
}));
return Status{Status::kSuccess};
}));
pcp_handler.InjectEndpoint(
&client, service_id,
OutOfBandConnectionMetadata{
.medium = Medium::BLUETOOTH,
.remote_bluetooth_mac_address = ByteArray(kFakeMacAddress),
});
EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0);
pcp_handler.StartEndpointLostByMediumAlarms(&client, Medium::BLUETOOTH);
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 1);
pcp_handler.InjectEndpoint(
&client, service_id,
OutOfBandConnectionMetadata{
.medium = Medium::BLUETOOTH,
.remote_bluetooth_mac_address = ByteArray(kFakeMacAddress),
});
EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarms().size(), 0);
env_.Stop();
}
} // namespace
} // namespace connections
} // namespace nearby
@@ -163,6 +163,7 @@ void ClientProxy::StoppedAdvertising() {
if (IsAdvertising()) {
advertising_info_.Clear();
analytics_recorder_->OnStopAdvertising();
local_endpoint_info_.clear();
}
// advertising_options_ is purposefully not cleared here.
OnSessionComplete();
@@ -64,6 +64,7 @@ class ClientProxy final {
std::int64_t GetClientId() const;
std::string GetLocalEndpointId();
std::string GetLocalEndpointInfo() { return local_endpoint_info_; }
analytics::AnalyticsRecorder& GetAnalyticsRecorder() const {
return *analytics_recorder_;
@@ -102,6 +103,11 @@ class ClientProxy final {
bool IsDiscovering() const;
std::string GetDiscoveryServiceId() const;
void UpdateLocalEndpointInfo(absl::string_view endpoint_info) {
MutexLock lock(&mutex_);
local_endpoint_info_ = std::string(endpoint_info);
}
// Proxies to the client's DiscoveryListener::OnEndpointFound() callback.
void OnEndpointFound(const std::string& service_id,
const std::string& endpoint_id,
@@ -295,6 +301,7 @@ class ClientProxy final {
mutable RecursiveMutex mutex_;
std::int64_t client_id_;
std::string local_endpoint_id_;
std::string local_endpoint_info_;
// If currently is advertising in high visibility mode is true: high power and
// Bluetooth Classic enabled. When high_visibility_mode_ is true, the endpoint
// id is stable for 30s. When high_visibility_mode_ is false, the endpoint id
@@ -981,6 +981,11 @@ TEST_F(ClientProxyTest, GetLocalDeviceWorksWithDeviceProvider) {
client1_.GetLocalDevice();
}
TEST_F(ClientProxyTest, TestGetSetLocalEndpointInfo) {
client1_.UpdateLocalEndpointInfo("endpoint_info");
EXPECT_EQ(client1_.GetLocalEndpointInfo(), "endpoint_info");
}
} // namespace
} // namespace connections
} // namespace nearby
@@ -14,6 +14,7 @@
#include "connections/implementation/p2p_cluster_pcp_handler.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
@@ -29,6 +30,7 @@
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "connections/implementation/mediums/utils.h"
#include "connections/implementation/wifi_lan_endpoint_channel.h"
#include "connections/power_level.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/nsd_service_info.h"
#include "internal/platform/types.h"
@@ -485,6 +487,10 @@ void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
BleEndpointState(advertisement.GetEndpointId(),
advertisement.GetEndpointInfo()));
StopEndpointLostByMediumAlarm(
advertisement.GetEndpointId(),
location::nearby::proto::connections::Medium::BLE);
// Report the discovered endpoint to the client.
NEARBY_LOGS(INFO) << "Found BleAdvertisement "
<< absl::BytesToHexString(advertisement_bytes.data())
@@ -493,15 +499,15 @@ void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
<< ", and endpoint_info="
<< absl::BytesToHexString(
advertisement.GetEndpointInfo().data())
<< ").",
OnEndpointFound(
client, std::make_shared<BleEndpoint>(BleEndpoint{
{advertisement.GetEndpointId(),
advertisement.GetEndpointInfo(), service_id,
location::nearby::proto::connections::Medium::BLE,
advertisement.GetWebRtcState()},
peripheral,
}));
<< ").";
OnEndpointFound(
client,
std::make_shared<BleEndpoint>(BleEndpoint{
{advertisement.GetEndpointId(), advertisement.GetEndpointInfo(),
service_id, location::nearby::proto::connections::Medium::BLE,
advertisement.GetWebRtcState()},
peripheral,
}));
// Make sure we can connect to this device via Classic Bluetooth.
std::string remote_bluetooth_mac_address =
@@ -522,6 +528,9 @@ void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
return;
}
StopEndpointLostByMediumAlarm(
advertisement.GetEndpointId(),
location::nearby::proto::connections::Medium::BLUETOOTH);
OnEndpointFound(
client,
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
@@ -665,6 +674,9 @@ void P2pClusterPcpHandler::BleV2PeripheralDiscoveredHandler(
<< absl::BytesToHexString(
advertisement.GetEndpointInfo().data())
<< ").";
StopEndpointLostByMediumAlarm(
advertisement.GetEndpointId(),
location::nearby::proto::connections::Medium::BLE);
OnEndpointFound(
client,
std::make_shared<BleV2Endpoint>(BleV2Endpoint{
@@ -695,6 +707,9 @@ void P2pClusterPcpHandler::BleV2PeripheralDiscoveredHandler(
ble_endpoint_state.bt = true;
found_endpoints_in_ble_discover_cb_[peripheral_id] = ble_endpoint_state;
StopEndpointLostByMediumAlarm(
advertisement.GetEndpointId(),
location::nearby::proto::connections::Medium::BLUETOOTH);
OnEndpointFound(
client,
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
@@ -849,6 +864,9 @@ void P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler(
<< absl::BytesToHexString(
wifi_lan_service_info.GetEndpointInfo().data())
<< ").";
StopEndpointLostByMediumAlarm(
wifi_lan_service_info.GetEndpointId(),
location::nearby::proto::connections::Medium::WIFI_LAN);
OnEndpointFound(
client,
std::make_shared<WifiLanEndpoint>(WifiLanEndpoint{
@@ -1154,8 +1172,8 @@ P2pClusterPcpHandler::StartBluetoothAdvertising(
socket.GetRemoteDevice().GetName();
auto channel =
std::make_unique<BluetoothEndpointChannel>(
service_id, /*channel_name=*/remote_device_name,
socket);
service_id,
/*channel_name=*/remote_device_name, socket);
ByteArray remote_device_info{remote_device_name};
OnIncomingConnection(
@@ -1182,7 +1200,8 @@ P2pClusterPcpHandler::StartBluetoothAdvertising(
<< service_id;
}
// Generate a BluetoothDeviceName with which to become Bluetooth discoverable.
// Generate a BluetoothDeviceName with which to become Bluetooth
// discoverable.
// TODO(b/169550050): Implement UWBAddress.
std::string device_name(BluetoothDeviceName(
kBluetoothDeviceNameVersion, GetPcp(), local_endpoint_id, service_id_hash,
@@ -1658,8 +1677,8 @@ P2pClusterPcpHandler::StartBleV2Advertising(
advertisement_bytes = ByteArray(BleAdvertisement(
kBleAdvertisementVersion, GetPcp(), service_id_hash, local_endpoint_id,
local_endpoint_info, bluetooth_mac_address, /*uwb_address=*/ByteArray{},
web_rtc_state));
local_endpoint_info, bluetooth_mac_address,
/*uwb_address=*/ByteArray{}, web_rtc_state));
}
if (advertisement_bytes.Empty()) {
NEARBY_LOGS(WARNING) << "In StartBleAdvertising("