Commit 466d92e0 authored by Richard Knoll's avatar Richard Knoll Committed by Commit Bot

[Nearby] Add Start/StopAdvertising mojo calls

This adds Start/StorAdvertising to the NearbyConnections interface and
hooks it up to the NearbyConnectionsManager on the browser side and to
the NearbyConnections class on the utility process that delegates to the
third_party library.

Bug: 1076008
Change-Id: I2cf883432c625d3c34060536fcbfa13f190c98c7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2339470Reviewed-by: default avatarAlex Gough <ajgo@chromium.org>
Reviewed-by: default avatarAlex Chau <alexchau@chromium.org>
Commit-Queue: Richard Knoll <knollr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#796410}
parent 6cda7e21
......@@ -11,6 +11,8 @@
using NearbyConnectionsMojom =
location::nearby::connections::mojom::NearbyConnections;
using AdvertisingOptionsPtr =
location::nearby::connections::mojom::AdvertisingOptionsPtr;
using DiscoveryOptionsPtr =
location::nearby::connections::mojom::DiscoveryOptionsPtr;
using EndpointDiscoveryListener =
......@@ -25,28 +27,33 @@ class MockNearbyConnections : public NearbyConnectionsMojom {
MockNearbyConnections& operator=(const MockNearbyConnections&) = delete;
~MockNearbyConnections() override;
MOCK_METHOD(void,
StartAdvertising,
(const std::vector<uint8_t>& endpoint_info,
const std::string& service_id,
AdvertisingOptionsPtr,
mojo::PendingRemote<ConnectionLifecycleListener>,
StartDiscoveryCallback),
(override));
MOCK_METHOD(void, StopAdvertising, (StopAdvertisingCallback), (override));
MOCK_METHOD(void,
StartDiscovery,
(const std::string& service_id,
DiscoveryOptionsPtr,
mojo::PendingRemote<EndpointDiscoveryListener>,
StartDiscoveryCallback callback),
(override));
MOCK_METHOD(void,
StopDiscovery,
(StopDiscoveryCallback callback),
StartDiscoveryCallback),
(override));
MOCK_METHOD(void, StopDiscovery, (StopDiscoveryCallback), (override));
MOCK_METHOD(void,
RequestConnection,
(const std::vector<uint8_t>& endpoint_info,
const std::string& endpoint_id,
mojo::PendingRemote<ConnectionLifecycleListener> listener,
RequestConnectionCallback callback),
mojo::PendingRemote<ConnectionLifecycleListener>,
RequestConnectionCallback),
(override));
MOCK_METHOD(void,
DisconnectFromEndpoint,
(const std::string& endpoint_id,
DisconnectFromEndpointCallback callback),
(const std::string& endpoint_id, DisconnectFromEndpointCallback),
(override));
};
......
......@@ -9,6 +9,8 @@
#include "chrome/browser/nearby_sharing/logging/logging.h"
#include "chrome/services/sharing/public/mojom/nearby_connections_types.mojom.h"
#include "crypto/random.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/network_change_notifier.h"
namespace {
......@@ -16,6 +18,32 @@ const char kServiceId[] = "NearbySharing";
const location::nearby::connections::mojom::Strategy kStrategy =
location::nearby::connections::mojom::Strategy::kP2pPointToPoint;
bool ShouldEnableWebRtc(bool is_advertising,
DataUsage data_usage,
PowerLevel power_level) {
// We won't use internet if the user requested we don't.
if (data_usage == DataUsage::kOffline)
return false;
// We won't use internet in a low power mode.
if (power_level == PowerLevel::kLowPower)
return false;
net::NetworkChangeNotifier::ConnectionType connection_type =
net::NetworkChangeNotifier::GetConnectionType();
// Verify that this network has an internet connection.
if (connection_type == net::NetworkChangeNotifier::CONNECTION_NONE)
return false;
// If the user wants to limit WebRTC, then only use it on unmetered networks.
if (data_usage == DataUsage::kWifiOnly)
return !net::NetworkChangeNotifier::IsConnectionCellular(connection_type);
// We're online, the user hasn't disabled WebRTC, let's use it!
return true;
}
} // namespace
NearbyConnectionsManagerImpl::NearbyConnectionsManagerImpl(
......@@ -39,17 +67,38 @@ void NearbyConnectionsManagerImpl::StartAdvertising(
PowerLevel power_level,
DataUsage data_usage,
ConnectionsCallback callback) {
DCHECK(listener);
DCHECK(!incoming_connection_listener_);
if (!BindNearbyConnections()) {
std::move(callback).Run(ConnectionsStatus::kError);
return;
}
// TOOD(crbug/1076008): nearby_connections_->StartAdvertising
bool is_high_power = power_level == PowerLevel::kHighPower;
auto allowed_mediums = MediumSelection::New(
/*bluetooth=*/is_high_power,
ShouldEnableWebRtc(/*is_advertising=*/true, data_usage, power_level),
/*wifi_lan=*/is_high_power);
mojo::PendingRemote<ConnectionLifecycleListener> lifecycle_listener;
connection_lifecycle_listeners_.Add(
this, lifecycle_listener.InitWithNewPipeAndPassReceiver());
incoming_connection_listener_ = listener;
nearby_connections_->StartAdvertising(
endpoint_info, kServiceId,
AdvertisingOptions::New(kStrategy, std::move(allowed_mediums),
/*auto_upgrade_bandwidth=*/is_high_power,
/*enforce_topology_constraints=*/true),
std::move(lifecycle_listener), std::move(callback));
}
void NearbyConnectionsManagerImpl::StopAdvertising() {
if (!nearby_connections_)
return;
if (nearby_connections_)
nearby_connections_->StopAdvertising(base::DoNothing());
incoming_connection_listener_ = nullptr;
}
void NearbyConnectionsManagerImpl::StartDiscovery(
......@@ -91,10 +140,13 @@ void NearbyConnectionsManagerImpl::Connect(
return;
}
mojo::PendingRemote<ConnectionLifecycleListener> lifecycle_listener;
connection_lifecycle_listeners_.Add(
this, lifecycle_listener.InitWithNewPipeAndPassReceiver());
// TODO(crbug/10706008): Add MediumSelector and bluetooth_mac_address.
nearby_connections_->RequestConnection(
endpoint_info, endpoint_id,
connection_lifecycle_listener_.BindNewPipeAndPassRemote(),
endpoint_info, endpoint_id, std::move(lifecycle_listener),
base::BindOnce(&NearbyConnectionsManagerImpl::OnConnectionRequested,
weak_ptr_factory_.GetWeakPtr(), endpoint_id,
std::move(callback)));
......@@ -260,7 +312,17 @@ void NearbyConnectionsManagerImpl::OnConnectionAccepted(
return;
if (it->second->is_incoming_connection) {
// TOOD(crbug/1076008): Handle incoming connection.
if (!incoming_connection_listener_) {
// Not in advertising mode.
Disconnect(endpoint_id);
return;
}
auto result = connections_.emplace(
endpoint_id, std::make_unique<NearbyConnectionImpl>(this, endpoint_id));
DCHECK(result.second);
incoming_connection_listener_->OnIncomingConnection(
endpoint_id, it->second->endpoint_info, result.first->second.get());
} else {
auto it = pending_outgoing_connections_.find(endpoint_id);
if (it == pending_outgoing_connections_.end()) {
......@@ -324,5 +386,6 @@ void NearbyConnectionsManagerImpl::Reset() {
nearby_connections_ = nullptr;
discovered_endpoints_.clear();
discovery_listener_ = nullptr;
incoming_connection_listener_ = nullptr;
endpoint_discovery_listener_.reset();
}
......@@ -15,6 +15,7 @@
#include "chrome/browser/nearby_sharing/nearby_process_manager.h"
#include "chrome/services/sharing/public/mojom/nearby_connections.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
class Profile;
......@@ -63,6 +64,9 @@ class NearbyConnectionsManagerImpl
void UpgradeBandwidth(const std::string& endpoint_id) override;
private:
using AdvertisingOptions =
location::nearby::connections::mojom::AdvertisingOptions;
using MediumSelection = location::nearby::connections::mojom::MediumSelection;
using DiscoveryOptions =
location::nearby::connections::mojom::DiscoveryOptions;
using EndpointDiscoveryListener =
......@@ -106,6 +110,7 @@ class NearbyConnectionsManagerImpl
NearbyProcessManager* process_manager_;
Profile* profile_;
IncomingConnectionListener* incoming_connection_listener_ = nullptr;
DiscoveryListener* discovery_listener_ = nullptr;
base::flat_set<std::string> discovered_endpoints_;
// A map of endpoint_id to NearbyConnectionCallback.
......@@ -120,8 +125,8 @@ class NearbyConnectionsManagerImpl
ScopedObserver<NearbyProcessManager, NearbyProcessManager::Observer>
nearby_process_observer_{this};
mojo::Receiver<EndpointDiscoveryListener> endpoint_discovery_listener_{this};
mojo::Receiver<ConnectionLifecycleListener> connection_lifecycle_listener_{
this};
mojo::ReceiverSet<ConnectionLifecycleListener>
connection_lifecycle_listeners_;
location::nearby::connections::mojom::NearbyConnections* nearby_connections_ =
nullptr;
......
......@@ -17,6 +17,7 @@
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/browser_task_environment.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/mock_network_change_notifier.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -40,6 +41,7 @@ using Status = location::nearby::connections::mojom::Status;
using DiscoveredEndpointInfo =
location::nearby::connections::mojom::DiscoveredEndpointInfo;
using ConnectionInfo = location::nearby::connections::mojom::ConnectionInfo;
using MediumSelection = location::nearby::connections::mojom::MediumSelection;
class MockDiscoveryListener
: public NearbyConnectionsManager::DiscoveryListener {
......@@ -55,6 +57,17 @@ class MockDiscoveryListener
(override));
};
class MockIncomingConnectionListener
: public NearbyConnectionsManager::IncomingConnectionListener {
public:
MOCK_METHOD(void,
OnIncomingConnection,
(const std::string& endpoint_id,
const std::vector<uint8_t>& endpoint_info,
NearbyConnection* connection),
(override));
};
class NearbyConnectionsManagerImplTest : public testing::Test {
public:
void SetUp() override {
......@@ -85,6 +98,33 @@ class NearbyConnectionsManagerImplTest : public testing::Test {
callback.Get());
}
void StartAdvertising(
mojo::Remote<ConnectionLifecycleListener>& listener_remote,
testing::NiceMock<MockIncomingConnectionListener>&
incoming_connection_listener) {
const std::vector<uint8_t> local_endpoint_info(std::begin(kEndpointInfo),
std::end(kEndpointInfo));
EXPECT_CALL(nearby_connections_, StartAdvertising)
.WillOnce(
[&](const std::vector<uint8_t>& endpoint_info,
const std::string& service_id, AdvertisingOptionsPtr options,
mojo::PendingRemote<ConnectionLifecycleListener> listener,
NearbyConnectionsMojom::StartAdvertisingCallback callback) {
EXPECT_EQ(local_endpoint_info, endpoint_info);
EXPECT_EQ(kServiceId, service_id);
EXPECT_EQ(kStrategy, options->strategy);
EXPECT_TRUE(options->enforce_topology_constraints);
listener_remote.Bind(std::move(listener));
std::move(callback).Run(Status::kSuccess);
});
base::MockCallback<NearbyConnectionsManager::ConnectionsCallback> callback;
EXPECT_CALL(callback, Run(testing::Eq(Status::kSuccess)));
nearby_connections_manager_.StartAdvertising(
local_endpoint_info, &incoming_connection_listener,
PowerLevel::kHighPower, DataUsage::kOnline, callback.Get());
}
enum class ConnectionResponse { kAccepted, kRejceted, kDisconnected };
NearbyConnection* Connect(
......@@ -145,6 +185,8 @@ class NearbyConnectionsManagerImplTest : public testing::Test {
content::BrowserTaskEnvironment task_environment_;
TestingProfile profile_;
std::unique_ptr<net::test::MockNetworkChangeNotifier> network_notifier_ =
net::test::MockNetworkChangeNotifier::Create();
testing::NiceMock<MockNearbyConnections> nearby_connections_;
testing::NiceMock<MockNearbyProcessManager> nearby_process_manager_;
NearbyConnectionsManagerImpl nearby_connections_manager_{
......@@ -254,7 +296,7 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectRejected) {
nearby_connections_manager_.GetRawAuthenticationToken(kRemoteEndpointId));
}
TEST_F(NearbyConnectionsManagerImplTest, ConnectDisconnted) {
TEST_F(NearbyConnectionsManagerImplTest, ConnectDisconnected) {
// StartDiscovery will succeed.
mojo::Remote<EndpointDiscoveryListener> discovery_listener_remote;
testing::NiceMock<MockDiscoveryListener> discovery_listener;
......@@ -481,3 +523,117 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectClosedByClient) {
EXPECT_FALSE(
nearby_connections_manager_.GetRawAuthenticationToken(kRemoteEndpointId));
}
TEST_F(NearbyConnectionsManagerImplTest, StartAdvertising) {
mojo::Remote<ConnectionLifecycleListener> listener_remote;
testing::NiceMock<MockIncomingConnectionListener>
incoming_connection_listener;
StartAdvertising(listener_remote, incoming_connection_listener);
const std::vector<uint8_t> remote_endpoint_info(
std::begin(kRemoteEndpointInfo), std::end(kRemoteEndpointInfo));
const std::vector<uint8_t> raw_authentication_token(
std::begin(kRawAuthenticationToken), std::end(kRawAuthenticationToken));
base::RunLoop run_loop;
EXPECT_CALL(
incoming_connection_listener,
OnIncomingConnection(kRemoteEndpointId, remote_endpoint_info, testing::_))
.WillOnce([&](const std::string&, const std::vector<uint8_t>&,
NearbyConnection* connection) {
EXPECT_TRUE(connection);
run_loop.Quit();
});
listener_remote->OnConnectionInitiated(
kRemoteEndpointId,
ConnectionInfo::New(kAuthenticationToken, raw_authentication_token,
remote_endpoint_info,
/*is_incoming_connection=*/true));
listener_remote->OnConnectionAccepted(kRemoteEndpointId);
run_loop.Run();
EXPECT_EQ(
raw_authentication_token,
nearby_connections_manager_.GetRawAuthenticationToken(kRemoteEndpointId));
}
using MediumsTestParam = std::
tuple<PowerLevel, DataUsage, net::NetworkChangeNotifier::ConnectionType>;
class NearbyConnectionsManagerImplTestMediums
: public NearbyConnectionsManagerImplTest,
public testing::WithParamInterface<MediumsTestParam> {};
TEST_P(NearbyConnectionsManagerImplTestMediums,
StartAdvertising_MediumSelection) {
const MediumsTestParam& param = GetParam();
PowerLevel power_level = std::get<0>(param);
DataUsage data_usage = std::get<1>(param);
net::NetworkChangeNotifier::ConnectionType connection_type =
std::get<2>(param);
network_notifier_->SetConnectionType(connection_type);
bool should_use_web_rtc =
data_usage != DataUsage::kOffline &&
power_level != PowerLevel::kLowPower &&
connection_type != net::NetworkChangeNotifier::CONNECTION_NONE &&
(data_usage != DataUsage::kWifiOnly ||
!net::NetworkChangeNotifier::IsConnectionCellular(connection_type));
bool is_high_power = power_level == PowerLevel::kHighPower;
auto expected_mediums = MediumSelection::New(
/*bluetooth=*/is_high_power,
/*web_rtc=*/should_use_web_rtc,
/*wifi_lan=*/is_high_power);
const std::vector<uint8_t> local_endpoint_info(std::begin(kEndpointInfo),
std::end(kEndpointInfo));
base::MockCallback<NearbyConnectionsManager::ConnectionsCallback> callback;
testing::NiceMock<MockIncomingConnectionListener>
incoming_connection_listener;
EXPECT_CALL(nearby_connections_, StartAdvertising)
.WillOnce([&](const std::vector<uint8_t>& endpoint_info,
const std::string& service_id,
AdvertisingOptionsPtr options,
mojo::PendingRemote<ConnectionLifecycleListener> listener,
NearbyConnectionsMojom::StartAdvertisingCallback callback) {
EXPECT_EQ(is_high_power, options->auto_upgrade_bandwidth);
EXPECT_EQ(expected_mediums, options->allowed_mediums);
std::move(callback).Run(Status::kSuccess);
});
EXPECT_CALL(callback, Run(testing::Eq(Status::kSuccess)));
nearby_connections_manager_.StartAdvertising(
local_endpoint_info, &incoming_connection_listener, power_level,
data_usage, callback.Get());
}
INSTANTIATE_TEST_SUITE_P(
NearbyConnectionsManagerImplTestMediums,
NearbyConnectionsManagerImplTestMediums,
testing::Combine(
testing::Values(PowerLevel::kLowPower, PowerLevel::kHighPower),
testing::Values(DataUsage::kWifiOnly,
DataUsage::kOffline,
DataUsage::kOnline),
testing::Values(net::NetworkChangeNotifier::CONNECTION_NONE,
net::NetworkChangeNotifier::CONNECTION_WIFI,
net::NetworkChangeNotifier::CONNECTION_3G)));
TEST_F(NearbyConnectionsManagerImplTest, StopAdvertising_BeforeStart) {
EXPECT_CALL(nearby_connections_, StopAdvertising).Times(0);
nearby_connections_manager_.StopAdvertising();
}
TEST_F(NearbyConnectionsManagerImplTest, StopAdvertising) {
mojo::Remote<ConnectionLifecycleListener> listener_remote;
testing::NiceMock<MockIncomingConnectionListener>
incoming_connection_listener;
StartAdvertising(listener_remote, incoming_connection_listener);
EXPECT_CALL(nearby_connections_, StopAdvertising);
nearby_connections_manager_.StopAdvertising();
}
......@@ -13,6 +13,65 @@ namespace location {
namespace nearby {
namespace connections {
namespace {
ConnectionRequestInfo CreateConnectionRequestInfo(
const std::vector<uint8_t>& endpoint_info,
mojo::PendingRemote<mojom::ConnectionLifecycleListener> listener) {
mojo::SharedRemote<mojom::ConnectionLifecycleListener> remote(
std::move(listener));
return ConnectionRequestInfo{
.name = std::string(endpoint_info.begin(), endpoint_info.end()),
.listener = {
.initiated_cb =
[remote](const std::string& endpoint_id,
const ConnectionResponseInfo& info) {
if (!remote)
return;
remote->OnConnectionInitiated(
endpoint_id,
mojom::ConnectionInfo::New(
info.authentication_token,
ByteArrayToMojom(info.raw_authentication_token),
ByteArrayToMojom(info.endpoint_info),
info.is_incoming_connection));
},
.accepted_cb =
[remote](const std::string& endpoint_id) {
if (!remote)
return;
remote->OnConnectionAccepted(endpoint_id);
},
.rejected_cb =
[remote](const std::string& endpoint_id, Status status) {
if (!remote)
return;
remote->OnConnectionRejected(endpoint_id,
StatusToMojom(status.value));
},
.disconnected_cb =
[remote](const std::string& endpoint_id) {
if (!remote)
return;
remote->OnDisconnected(endpoint_id);
},
.bandwidth_changed_cb =
[remote](const std::string& endpoint_id, std::int32_t quality) {
if (!remote)
return;
remote->OnBandwidthChanged(endpoint_id, quality);
},
},
};
}
} // namespace
// Should only be accessed by objects within lifetime of NearbyConnections.
NearbyConnections* g_instance = nullptr;
......@@ -128,6 +187,34 @@ NearbyConnections::GetWebRtcSignalingMessenger() {
return webrtc_signaling_messenger_.get();
}
void NearbyConnections::StartAdvertising(
const std::vector<uint8_t>& endpoint_info,
const std::string& service_id,
mojom::AdvertisingOptionsPtr options,
mojo::PendingRemote<mojom::ConnectionLifecycleListener> listener,
StartAdvertisingCallback callback) {
BooleanMediumSelector allowed_mediums = {
.bluetooth = options->allowed_mediums->bluetooth,
.web_rtc = options->allowed_mediums->web_rtc,
.wifi_lan = options->allowed_mediums->wifi_lan,
};
ConnectionOptions connection_options{
.strategy = StrategyFromMojom(options->strategy),
.allowed = std::move(allowed_mediums),
.auto_upgrade_bandwidth = options->auto_upgrade_bandwidth,
.enforce_topology_constraints = options->enforce_topology_constraints,
};
core_->StartAdvertising(
service_id, std::move(connection_options),
CreateConnectionRequestInfo(endpoint_info, std::move(listener)),
ResultCallbackFromMojom(std::move(callback)));
}
void NearbyConnections::StopAdvertising(StopAdvertisingCallback callback) {
core_->StopAdvertising(ResultCallbackFromMojom(std::move(callback)));
}
void NearbyConnections::StartDiscovery(
const std::string& service_id,
mojom::DiscoveryOptionsPtr options,
......@@ -176,59 +263,10 @@ void NearbyConnections::RequestConnection(
const std::string& endpoint_id,
mojo::PendingRemote<mojom::ConnectionLifecycleListener> listener,
RequestConnectionCallback callback) {
mojo::SharedRemote<mojom::ConnectionLifecycleListener> remote(
std::move(listener));
ConnectionRequestInfo connection_request_info{
.name = std::string(endpoint_info.begin(), endpoint_info.end()),
.listener = {
.initiated_cb =
[remote](const std::string& endpoint_id,
const ConnectionResponseInfo& info) {
if (!remote)
return;
remote->OnConnectionInitiated(
endpoint_id,
mojom::ConnectionInfo::New(
info.authentication_token,
ByteArrayToMojom(info.raw_authentication_token),
ByteArrayToMojom(info.endpoint_info),
info.is_incoming_connection));
},
.accepted_cb =
[remote](const std::string& endpoint_id) {
if (!remote)
return;
remote->OnConnectionAccepted(endpoint_id);
},
.rejected_cb =
[remote](const std::string& endpoint_id, Status status) {
if (!remote)
return;
remote->OnConnectionRejected(endpoint_id,
StatusToMojom(status.value));
},
.disconnected_cb =
[remote](const std::string& endpoint_id) {
if (!remote)
return;
remote->OnDisconnected(endpoint_id);
},
.bandwidth_changed_cb =
[remote](const std::string& endpoint_id, std::int32_t quality) {
if (!remote)
return;
remote->OnBandwidthChanged(endpoint_id, quality);
},
}};
ResultCallback result_callback = ResultCallbackFromMojom(std::move(callback));
core_->RequestConnection(endpoint_id, std::move(connection_request_info),
std::move(result_callback));
core_->RequestConnection(
endpoint_id,
CreateConnectionRequestInfo(endpoint_info, std::move(listener)),
ResultCallbackFromMojom(std::move(callback)));
}
void NearbyConnections::DisconnectFromEndpoint(
......
......@@ -58,6 +58,13 @@ class NearbyConnections : public mojom::NearbyConnections {
sharing::mojom::WebRtcSignalingMessenger* GetWebRtcSignalingMessenger();
// mojom::NearbyConnections:
void StartAdvertising(
const std::vector<uint8_t>& endpoint_info,
const std::string& service_id,
mojom::AdvertisingOptionsPtr options,
mojo::PendingRemote<mojom::ConnectionLifecycleListener> listener,
StartAdvertisingCallback callback) override;
void StopAdvertising(StopAdvertisingCallback callback) override;
void StartDiscovery(
const std::string& service_id,
mojom::DiscoveryOptionsPtr options,
......
......@@ -38,6 +38,16 @@ const char kAuthenticationToken[] = "authentication_token";
const char kRawAuthenticationToken[] = {0x00, 0x05, 0x04, 0x03, 0x02};
const int32_t kQuality = 5201314;
mojom::AdvertisingOptionsPtr CreateAdvertisingOptions() {
auto allowed_mediums = mojom::MediumSelection::New(/*bluetooth=*/true,
/*web_rtc=*/true,
/*wifi_lan=*/true);
return mojom::AdvertisingOptions::New(mojom::Strategy::kP2pPointToPoint,
std::move(allowed_mediums),
/*auto_upgrade_bandwidth=*/true,
/*enforce_topology_constraints=*/true);
}
} // namespace
class FakeEndpointDiscoveryListener : public mojom::EndpointDiscoveryListener {
......@@ -406,6 +416,139 @@ TEST_F(NearbyConnectionsTest, RequestConnection) {
EXPECT_CALL(*service_controller_ptr_, DisconnectFromEndpoint).Times(1);
}
TEST_F(NearbyConnectionsTest, StartAdvertising) {
FakeConnectionLifecycleListener fake_connection_life_cycle_listener;
ClientProxy* client_proxy;
ConnectionListener connections_listener;
EXPECT_CALL(*service_controller_ptr_, StartAdvertising)
.WillOnce([&](ClientProxy* client, const std::string& service_id,
const ConnectionOptions& options,
const ConnectionRequestInfo& info) {
EXPECT_EQ(kServiceId, service_id);
EXPECT_EQ(Strategy::kP2pPointToPoint, options.strategy);
EXPECT_TRUE(options.allowed.bluetooth);
EXPECT_TRUE(options.allowed.web_rtc);
EXPECT_TRUE(options.allowed.wifi_lan);
EXPECT_TRUE(options.auto_upgrade_bandwidth);
EXPECT_TRUE(options.enforce_topology_constraints);
EXPECT_EQ(
std::string(std::begin(kEndpointInfo), std::end(kEndpointInfo)),
info.name);
client_proxy = client;
connections_listener = info.listener;
return Status{Status::kSuccess};
});
base::RunLoop start_advertising_run_loop;
nearby_connections_->StartAdvertising(
std::vector<uint8_t>(std::begin(kEndpointInfo), std::end(kEndpointInfo)),
kServiceId, CreateAdvertisingOptions(),
fake_connection_life_cycle_listener.receiver.BindNewPipeAndPassRemote(),
base::BindLambdaForTesting([&](mojom::Status status) {
EXPECT_EQ(mojom::Status::kSuccess, status);
start_advertising_run_loop.Quit();
}));
start_advertising_run_loop.Run();
base::RunLoop initiated_run_loop;
fake_connection_life_cycle_listener.initiated_cb = base::BindLambdaForTesting(
[&](const std::string& endpoint_id, mojom::ConnectionInfoPtr info) {
EXPECT_EQ(kRemoteEndpointId, endpoint_id);
EXPECT_EQ(kAuthenticationToken, info->authentication_token);
EXPECT_EQ(std::vector<uint8_t>(std::begin(kRawAuthenticationToken),
std::end(kRawAuthenticationToken)),
info->raw_authentication_token);
EXPECT_EQ(std::vector<uint8_t>(std::begin(kRemoteEndpointInfo),
std::end(kRemoteEndpointInfo)),
info->endpoint_info);
EXPECT_FALSE(info->is_incoming_connection);
initiated_run_loop.Quit();
});
client_proxy->OnConnectionInitiated(
kRemoteEndpointId,
{.authentication_token = kAuthenticationToken,
.raw_authentication_token =
ByteArray(kRawAuthenticationToken, sizeof(kRawAuthenticationToken)),
.endpoint_info =
ByteArray(kRemoteEndpointInfo, sizeof(kRemoteEndpointInfo)),
.is_incoming_connection = false},
connections_listener);
initiated_run_loop.Run();
base::RunLoop rejected_run_loop;
fake_connection_life_cycle_listener.rejected_cb = base::BindLambdaForTesting(
[&](const std::string& endpoint_id, mojom::Status status) {
EXPECT_EQ(kRemoteEndpointId, endpoint_id);
EXPECT_EQ(mojom::Status::kConnectionRejected, status);
rejected_run_loop.Quit();
});
client_proxy->OnConnectionRejected(kRemoteEndpointId,
{Status::kConnectionRejected});
rejected_run_loop.Run();
// Initiate connection again to test accepted flow.
base::RunLoop initiated_run_loop_2;
fake_connection_life_cycle_listener.initiated_cb = base::BindLambdaForTesting(
[&](const std::string& endpoint_id, mojom::ConnectionInfoPtr info) {
EXPECT_EQ(kRemoteEndpointId, endpoint_id);
EXPECT_FALSE(info->is_incoming_connection);
initiated_run_loop_2.Quit();
});
client_proxy->OnConnectionInitiated(kRemoteEndpointId,
{.is_incoming_connection = false},
connections_listener);
initiated_run_loop_2.Run();
base::RunLoop accepted_run_loop;
fake_connection_life_cycle_listener.accepted_cb =
base::BindLambdaForTesting([&](const std::string& endpoint_id) {
EXPECT_EQ(kRemoteEndpointId, endpoint_id);
accepted_run_loop.Quit();
});
client_proxy->OnConnectionAccepted(kRemoteEndpointId);
accepted_run_loop.Run();
}
TEST_F(NearbyConnectionsTest, StopAdvertising) {
FakeConnectionLifecycleListener fake_connection_life_cycle_listener;
EXPECT_CALL(*service_controller_ptr_, StartAdvertising)
.WillOnce([](ClientProxy* client, const std::string& service_id,
const ConnectionOptions& options,
const ConnectionRequestInfo& info) {
client->StartedAdvertising(service_id, options.strategy, info.listener,
/*mediums=*/{});
return Status{Status::kSuccess};
});
base::RunLoop start_advertising_run_loop;
nearby_connections_->StartAdvertising(
std::vector<uint8_t>(std::begin(kEndpointInfo), std::end(kEndpointInfo)),
kServiceId, CreateAdvertisingOptions(), mojo::NullRemote(),
base::BindLambdaForTesting([&](mojom::Status status) {
EXPECT_EQ(mojom::Status::kSuccess, status);
start_advertising_run_loop.Quit();
}));
start_advertising_run_loop.Run();
EXPECT_CALL(*service_controller_ptr_, StopAdvertising)
.WillOnce([](ClientProxy* client) { client->StoppedAdvertising(); });
base::RunLoop stop_advertising_run_loop;
nearby_connections_->StopAdvertising(
base::BindLambdaForTesting([&](mojom::Status status) {
EXPECT_EQ(mojom::Status::kSuccess, status);
stop_advertising_run_loop.Quit();
}));
stop_advertising_run_loop.Run();
// Expect one more call during shutdown.
EXPECT_CALL(*service_controller_ptr_, StopAdvertising);
}
} // namespace connections
} // namespace nearby
} // namespace location
......@@ -97,12 +97,45 @@ interface ConnectionLifecycleListener {
// packets is not part of the NearbyConnections library and is done in a
// separate interface.
interface NearbyConnections {
// Starts advertising an endpoint with the specified service ID. Only one
// advertisement can be active at a time and calling StartAdvertising() while
// advertising will fail and return Status::kAlreadyAdvertising.
//
// endpoint_info - The local info to be broadcasted. May contain a human
// readable name to appear on other devices if broadcasting
// in high visibility mode.
// service_id - An identifier to advertise your app to other endpoints.
// This can be an arbitrary string, so long as it uniquely
// identifies your service. A good default is to use your
// app's package name.
// options - The options for advertising.
// listener - An interface notified when remote endpoints request a
// connection to this endpoint.
// Possible return values include:
// Status::kSuccess if advertising started successfully.
// Status::kAlreadyAdvertising if the app is already advertising.
// Status::kOutOfOrderApiCall if the app is currently connected to remote
// endpoints; call StopAllEndpoints first.
StartAdvertising(array<uint8> endpoint_info, string service_id,
AdvertisingOptions options,
pending_remote<ConnectionLifecycleListener> listener)
=> (Status status);
// Stops advertising the local endpoint. Should be called after calling
// StartAdvertising, as soon as the application no longer needs to advertise
// itself or goes inactive. Payloads can still be sent to connected
// endpoints after advertising ends.
//
// Possible return values include:
// Status::kSuccess returned after advertising got stopped.
StopAdvertising() => (Status status);
// Starts discovery for remote endpoints with the specified service ID.
//
// service_id - The ID for the service to be discovered, as specified in
// the corresponding call to StartAdvertising.
// options - The options for discovery.
// listener - A callback notified when a remote endpoint is discovered.
// listener - An interface notified when a remote endpoint is discovered.
// Possible status codes include:
// Status::kSuccess if discovery started successfully.
// Status::kAlreadyDiscovering if the app is already
......@@ -130,7 +163,7 @@ interface NearbyConnections {
// connection request will be sent. Should match the value
// provided in a call to
// EndpointDiscoveryListener::OnEndpointFound().
// listener - A callback notified when the remote endpoint sends a
// listener - An interface notified when the remote endpoint sends a
// response to the connection request.
// Possible return values include:
// Status::kSuccess if the connection request was sent.
......
......@@ -99,11 +99,25 @@ enum Strategy {
kP2pPointToPoint,
};
// A selection of on/off toggles to define a set of allowed mediums.
struct MediumSelection {
// Whether Bluetooth should be allowed.
bool bluetooth;
// Whether WebRTC should be allowed.
bool web_rtc;
// Whether WiFi LAN should be allowed.
bool wifi_lan;
};
// Options for a call to NearbyConnections::StartAdvertising().
struct AdvertisingOptions {
// The strategy to use for advertising. Must match the strategy used in
// DiscoveryOptions for remote devices to see this advertisement.
Strategy strategy;
// Describes which mediums are allowed to be used for advertising. Note that
// allowing an otherwise unsupported medium is ok. Only the intersection of
// allowed and supported mediums will be used to advertise.
MediumSelection allowed_mediums;
// By default, this option is true. If false, we will not attempt to upgrade
// the bandwidth until a call to InitiateBandwidthUpgrade() is made.
bool auto_upgrade_bandwidth = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment