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 @@ ...@@ -11,6 +11,8 @@
using NearbyConnectionsMojom = using NearbyConnectionsMojom =
location::nearby::connections::mojom::NearbyConnections; location::nearby::connections::mojom::NearbyConnections;
using AdvertisingOptionsPtr =
location::nearby::connections::mojom::AdvertisingOptionsPtr;
using DiscoveryOptionsPtr = using DiscoveryOptionsPtr =
location::nearby::connections::mojom::DiscoveryOptionsPtr; location::nearby::connections::mojom::DiscoveryOptionsPtr;
using EndpointDiscoveryListener = using EndpointDiscoveryListener =
...@@ -25,28 +27,33 @@ class MockNearbyConnections : public NearbyConnectionsMojom { ...@@ -25,28 +27,33 @@ class MockNearbyConnections : public NearbyConnectionsMojom {
MockNearbyConnections& operator=(const MockNearbyConnections&) = delete; MockNearbyConnections& operator=(const MockNearbyConnections&) = delete;
~MockNearbyConnections() override; ~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, MOCK_METHOD(void,
StartDiscovery, StartDiscovery,
(const std::string& service_id, (const std::string& service_id,
DiscoveryOptionsPtr, DiscoveryOptionsPtr,
mojo::PendingRemote<EndpointDiscoveryListener>, mojo::PendingRemote<EndpointDiscoveryListener>,
StartDiscoveryCallback callback), StartDiscoveryCallback),
(override));
MOCK_METHOD(void,
StopDiscovery,
(StopDiscoveryCallback callback),
(override)); (override));
MOCK_METHOD(void, StopDiscovery, (StopDiscoveryCallback), (override));
MOCK_METHOD(void, MOCK_METHOD(void,
RequestConnection, RequestConnection,
(const std::vector<uint8_t>& endpoint_info, (const std::vector<uint8_t>& endpoint_info,
const std::string& endpoint_id, const std::string& endpoint_id,
mojo::PendingRemote<ConnectionLifecycleListener> listener, mojo::PendingRemote<ConnectionLifecycleListener>,
RequestConnectionCallback callback), RequestConnectionCallback),
(override)); (override));
MOCK_METHOD(void, MOCK_METHOD(void,
DisconnectFromEndpoint, DisconnectFromEndpoint,
(const std::string& endpoint_id, (const std::string& endpoint_id, DisconnectFromEndpointCallback),
DisconnectFromEndpointCallback callback),
(override)); (override));
}; };
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "chrome/browser/nearby_sharing/logging/logging.h" #include "chrome/browser/nearby_sharing/logging/logging.h"
#include "chrome/services/sharing/public/mojom/nearby_connections_types.mojom.h" #include "chrome/services/sharing/public/mojom/nearby_connections_types.mojom.h"
#include "crypto/random.h" #include "crypto/random.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/network_change_notifier.h"
namespace { namespace {
...@@ -16,6 +18,32 @@ const char kServiceId[] = "NearbySharing"; ...@@ -16,6 +18,32 @@ const char kServiceId[] = "NearbySharing";
const location::nearby::connections::mojom::Strategy kStrategy = const location::nearby::connections::mojom::Strategy kStrategy =
location::nearby::connections::mojom::Strategy::kP2pPointToPoint; 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 } // namespace
NearbyConnectionsManagerImpl::NearbyConnectionsManagerImpl( NearbyConnectionsManagerImpl::NearbyConnectionsManagerImpl(
...@@ -39,17 +67,38 @@ void NearbyConnectionsManagerImpl::StartAdvertising( ...@@ -39,17 +67,38 @@ void NearbyConnectionsManagerImpl::StartAdvertising(
PowerLevel power_level, PowerLevel power_level,
DataUsage data_usage, DataUsage data_usage,
ConnectionsCallback callback) { ConnectionsCallback callback) {
DCHECK(listener);
DCHECK(!incoming_connection_listener_);
if (!BindNearbyConnections()) { if (!BindNearbyConnections()) {
std::move(callback).Run(ConnectionsStatus::kError); std::move(callback).Run(ConnectionsStatus::kError);
return; 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() { void NearbyConnectionsManagerImpl::StopAdvertising() {
if (!nearby_connections_) if (nearby_connections_)
return; nearby_connections_->StopAdvertising(base::DoNothing());
incoming_connection_listener_ = nullptr;
} }
void NearbyConnectionsManagerImpl::StartDiscovery( void NearbyConnectionsManagerImpl::StartDiscovery(
...@@ -91,10 +140,13 @@ void NearbyConnectionsManagerImpl::Connect( ...@@ -91,10 +140,13 @@ void NearbyConnectionsManagerImpl::Connect(
return; return;
} }
mojo::PendingRemote<ConnectionLifecycleListener> lifecycle_listener;
connection_lifecycle_listeners_.Add(
this, lifecycle_listener.InitWithNewPipeAndPassReceiver());
// TODO(crbug/10706008): Add MediumSelector and bluetooth_mac_address. // TODO(crbug/10706008): Add MediumSelector and bluetooth_mac_address.
nearby_connections_->RequestConnection( nearby_connections_->RequestConnection(
endpoint_info, endpoint_id, endpoint_info, endpoint_id, std::move(lifecycle_listener),
connection_lifecycle_listener_.BindNewPipeAndPassRemote(),
base::BindOnce(&NearbyConnectionsManagerImpl::OnConnectionRequested, base::BindOnce(&NearbyConnectionsManagerImpl::OnConnectionRequested,
weak_ptr_factory_.GetWeakPtr(), endpoint_id, weak_ptr_factory_.GetWeakPtr(), endpoint_id,
std::move(callback))); std::move(callback)));
...@@ -260,7 +312,17 @@ void NearbyConnectionsManagerImpl::OnConnectionAccepted( ...@@ -260,7 +312,17 @@ void NearbyConnectionsManagerImpl::OnConnectionAccepted(
return; return;
if (it->second->is_incoming_connection) { 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 { } else {
auto it = pending_outgoing_connections_.find(endpoint_id); auto it = pending_outgoing_connections_.find(endpoint_id);
if (it == pending_outgoing_connections_.end()) { if (it == pending_outgoing_connections_.end()) {
...@@ -324,5 +386,6 @@ void NearbyConnectionsManagerImpl::Reset() { ...@@ -324,5 +386,6 @@ void NearbyConnectionsManagerImpl::Reset() {
nearby_connections_ = nullptr; nearby_connections_ = nullptr;
discovered_endpoints_.clear(); discovered_endpoints_.clear();
discovery_listener_ = nullptr; discovery_listener_ = nullptr;
incoming_connection_listener_ = nullptr;
endpoint_discovery_listener_.reset(); endpoint_discovery_listener_.reset();
} }
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "chrome/browser/nearby_sharing/nearby_process_manager.h" #include "chrome/browser/nearby_sharing/nearby_process_manager.h"
#include "chrome/services/sharing/public/mojom/nearby_connections.mojom.h" #include "chrome/services/sharing/public/mojom/nearby_connections.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
class Profile; class Profile;
...@@ -63,6 +64,9 @@ class NearbyConnectionsManagerImpl ...@@ -63,6 +64,9 @@ class NearbyConnectionsManagerImpl
void UpgradeBandwidth(const std::string& endpoint_id) override; void UpgradeBandwidth(const std::string& endpoint_id) override;
private: private:
using AdvertisingOptions =
location::nearby::connections::mojom::AdvertisingOptions;
using MediumSelection = location::nearby::connections::mojom::MediumSelection;
using DiscoveryOptions = using DiscoveryOptions =
location::nearby::connections::mojom::DiscoveryOptions; location::nearby::connections::mojom::DiscoveryOptions;
using EndpointDiscoveryListener = using EndpointDiscoveryListener =
...@@ -106,6 +110,7 @@ class NearbyConnectionsManagerImpl ...@@ -106,6 +110,7 @@ class NearbyConnectionsManagerImpl
NearbyProcessManager* process_manager_; NearbyProcessManager* process_manager_;
Profile* profile_; Profile* profile_;
IncomingConnectionListener* incoming_connection_listener_ = nullptr;
DiscoveryListener* discovery_listener_ = nullptr; DiscoveryListener* discovery_listener_ = nullptr;
base::flat_set<std::string> discovered_endpoints_; base::flat_set<std::string> discovered_endpoints_;
// A map of endpoint_id to NearbyConnectionCallback. // A map of endpoint_id to NearbyConnectionCallback.
...@@ -120,8 +125,8 @@ class NearbyConnectionsManagerImpl ...@@ -120,8 +125,8 @@ class NearbyConnectionsManagerImpl
ScopedObserver<NearbyProcessManager, NearbyProcessManager::Observer> ScopedObserver<NearbyProcessManager, NearbyProcessManager::Observer>
nearby_process_observer_{this}; nearby_process_observer_{this};
mojo::Receiver<EndpointDiscoveryListener> endpoint_discovery_listener_{this}; mojo::Receiver<EndpointDiscoveryListener> endpoint_discovery_listener_{this};
mojo::Receiver<ConnectionLifecycleListener> connection_lifecycle_listener_{ mojo::ReceiverSet<ConnectionLifecycleListener>
this}; connection_lifecycle_listeners_;
location::nearby::connections::mojom::NearbyConnections* nearby_connections_ = location::nearby::connections::mojom::NearbyConnections* nearby_connections_ =
nullptr; nullptr;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
#include "mojo/public/cpp/bindings/remote.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/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -40,6 +41,7 @@ using Status = location::nearby::connections::mojom::Status; ...@@ -40,6 +41,7 @@ using Status = location::nearby::connections::mojom::Status;
using DiscoveredEndpointInfo = using DiscoveredEndpointInfo =
location::nearby::connections::mojom::DiscoveredEndpointInfo; location::nearby::connections::mojom::DiscoveredEndpointInfo;
using ConnectionInfo = location::nearby::connections::mojom::ConnectionInfo; using ConnectionInfo = location::nearby::connections::mojom::ConnectionInfo;
using MediumSelection = location::nearby::connections::mojom::MediumSelection;
class MockDiscoveryListener class MockDiscoveryListener
: public NearbyConnectionsManager::DiscoveryListener { : public NearbyConnectionsManager::DiscoveryListener {
...@@ -55,6 +57,17 @@ class MockDiscoveryListener ...@@ -55,6 +57,17 @@ class MockDiscoveryListener
(override)); (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 { class NearbyConnectionsManagerImplTest : public testing::Test {
public: public:
void SetUp() override { void SetUp() override {
...@@ -85,6 +98,33 @@ class NearbyConnectionsManagerImplTest : public testing::Test { ...@@ -85,6 +98,33 @@ class NearbyConnectionsManagerImplTest : public testing::Test {
callback.Get()); 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 }; enum class ConnectionResponse { kAccepted, kRejceted, kDisconnected };
NearbyConnection* Connect( NearbyConnection* Connect(
...@@ -145,6 +185,8 @@ class NearbyConnectionsManagerImplTest : public testing::Test { ...@@ -145,6 +185,8 @@ class NearbyConnectionsManagerImplTest : public testing::Test {
content::BrowserTaskEnvironment task_environment_; content::BrowserTaskEnvironment task_environment_;
TestingProfile profile_; TestingProfile profile_;
std::unique_ptr<net::test::MockNetworkChangeNotifier> network_notifier_ =
net::test::MockNetworkChangeNotifier::Create();
testing::NiceMock<MockNearbyConnections> nearby_connections_; testing::NiceMock<MockNearbyConnections> nearby_connections_;
testing::NiceMock<MockNearbyProcessManager> nearby_process_manager_; testing::NiceMock<MockNearbyProcessManager> nearby_process_manager_;
NearbyConnectionsManagerImpl nearby_connections_manager_{ NearbyConnectionsManagerImpl nearby_connections_manager_{
...@@ -254,7 +296,7 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectRejected) { ...@@ -254,7 +296,7 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectRejected) {
nearby_connections_manager_.GetRawAuthenticationToken(kRemoteEndpointId)); nearby_connections_manager_.GetRawAuthenticationToken(kRemoteEndpointId));
} }
TEST_F(NearbyConnectionsManagerImplTest, ConnectDisconnted) { TEST_F(NearbyConnectionsManagerImplTest, ConnectDisconnected) {
// StartDiscovery will succeed. // StartDiscovery will succeed.
mojo::Remote<EndpointDiscoveryListener> discovery_listener_remote; mojo::Remote<EndpointDiscoveryListener> discovery_listener_remote;
testing::NiceMock<MockDiscoveryListener> discovery_listener; testing::NiceMock<MockDiscoveryListener> discovery_listener;
...@@ -481,3 +523,117 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectClosedByClient) { ...@@ -481,3 +523,117 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectClosedByClient) {
EXPECT_FALSE( EXPECT_FALSE(
nearby_connections_manager_.GetRawAuthenticationToken(kRemoteEndpointId)); 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 { ...@@ -13,6 +13,65 @@ namespace location {
namespace nearby { namespace nearby {
namespace connections { 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. // Should only be accessed by objects within lifetime of NearbyConnections.
NearbyConnections* g_instance = nullptr; NearbyConnections* g_instance = nullptr;
...@@ -128,6 +187,34 @@ NearbyConnections::GetWebRtcSignalingMessenger() { ...@@ -128,6 +187,34 @@ NearbyConnections::GetWebRtcSignalingMessenger() {
return webrtc_signaling_messenger_.get(); 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( void NearbyConnections::StartDiscovery(
const std::string& service_id, const std::string& service_id,
mojom::DiscoveryOptionsPtr options, mojom::DiscoveryOptionsPtr options,
...@@ -176,59 +263,10 @@ void NearbyConnections::RequestConnection( ...@@ -176,59 +263,10 @@ void NearbyConnections::RequestConnection(
const std::string& endpoint_id, const std::string& endpoint_id,
mojo::PendingRemote<mojom::ConnectionLifecycleListener> listener, mojo::PendingRemote<mojom::ConnectionLifecycleListener> listener,
RequestConnectionCallback callback) { RequestConnectionCallback callback) {
mojo::SharedRemote<mojom::ConnectionLifecycleListener> remote( core_->RequestConnection(
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, endpoint_id,
mojom::ConnectionInfo::New( CreateConnectionRequestInfo(endpoint_info, std::move(listener)),
info.authentication_token, ResultCallbackFromMojom(std::move(callback)));
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));
} }
void NearbyConnections::DisconnectFromEndpoint( void NearbyConnections::DisconnectFromEndpoint(
......
...@@ -58,6 +58,13 @@ class NearbyConnections : public mojom::NearbyConnections { ...@@ -58,6 +58,13 @@ class NearbyConnections : public mojom::NearbyConnections {
sharing::mojom::WebRtcSignalingMessenger* GetWebRtcSignalingMessenger(); sharing::mojom::WebRtcSignalingMessenger* GetWebRtcSignalingMessenger();
// mojom::NearbyConnections: // 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( void StartDiscovery(
const std::string& service_id, const std::string& service_id,
mojom::DiscoveryOptionsPtr options, mojom::DiscoveryOptionsPtr options,
......
...@@ -38,6 +38,16 @@ const char kAuthenticationToken[] = "authentication_token"; ...@@ -38,6 +38,16 @@ const char kAuthenticationToken[] = "authentication_token";
const char kRawAuthenticationToken[] = {0x00, 0x05, 0x04, 0x03, 0x02}; const char kRawAuthenticationToken[] = {0x00, 0x05, 0x04, 0x03, 0x02};
const int32_t kQuality = 5201314; 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 } // namespace
class FakeEndpointDiscoveryListener : public mojom::EndpointDiscoveryListener { class FakeEndpointDiscoveryListener : public mojom::EndpointDiscoveryListener {
...@@ -406,6 +416,139 @@ TEST_F(NearbyConnectionsTest, RequestConnection) { ...@@ -406,6 +416,139 @@ TEST_F(NearbyConnectionsTest, RequestConnection) {
EXPECT_CALL(*service_controller_ptr_, DisconnectFromEndpoint).Times(1); 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 connections
} // namespace nearby } // namespace nearby
} // namespace location } // namespace location
...@@ -97,12 +97,45 @@ interface ConnectionLifecycleListener { ...@@ -97,12 +97,45 @@ interface ConnectionLifecycleListener {
// packets is not part of the NearbyConnections library and is done in a // packets is not part of the NearbyConnections library and is done in a
// separate interface. // separate interface.
interface NearbyConnections { 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. // Starts discovery for remote endpoints with the specified service ID.
// //
// service_id - The ID for the service to be discovered, as specified in // service_id - The ID for the service to be discovered, as specified in
// the corresponding call to StartAdvertising. // the corresponding call to StartAdvertising.
// options - The options for discovery. // 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: // Possible status codes include:
// Status::kSuccess if discovery started successfully. // Status::kSuccess if discovery started successfully.
// Status::kAlreadyDiscovering if the app is already // Status::kAlreadyDiscovering if the app is already
...@@ -130,7 +163,7 @@ interface NearbyConnections { ...@@ -130,7 +163,7 @@ interface NearbyConnections {
// connection request will be sent. Should match the value // connection request will be sent. Should match the value
// provided in a call to // provided in a call to
// EndpointDiscoveryListener::OnEndpointFound(). // 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. // response to the connection request.
// Possible return values include: // Possible return values include:
// Status::kSuccess if the connection request was sent. // Status::kSuccess if the connection request was sent.
......
...@@ -99,11 +99,25 @@ enum Strategy { ...@@ -99,11 +99,25 @@ enum Strategy {
kP2pPointToPoint, 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(). // Options for a call to NearbyConnections::StartAdvertising().
struct AdvertisingOptions { struct AdvertisingOptions {
// The strategy to use for advertising. Must match the strategy used in // The strategy to use for advertising. Must match the strategy used in
// DiscoveryOptions for remote devices to see this advertisement. // DiscoveryOptions for remote devices to see this advertisement.
Strategy strategy; 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 // By default, this option is true. If false, we will not attempt to upgrade
// the bandwidth until a call to InitiateBandwidthUpgrade() is made. // the bandwidth until a call to InitiateBandwidthUpgrade() is made.
bool auto_upgrade_bandwidth = true; 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