Commit 4af152ae authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS PhoneHub] Create chromeos::secure_channel::NearbyConnectionBroker

This class creates an out-of-band Nearby connection using a pre-sycned
Bluetooth address. It will be used by the SecureChannel service to
implement connections for Phone Hub.

Bug: 1106937
Change-Id: I5dec7c8edc58b1188e423f1368d47727cd48eb1f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2499361
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarJames Vecore <vecore@google.com>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#824997}
parent 95c3873e
...@@ -2601,6 +2601,10 @@ source_set("chromeos") { ...@@ -2601,6 +2601,10 @@ source_set("chromeos") {
"scanning/zeroconf_scanner_detector_utils.h", "scanning/zeroconf_scanner_detector_utils.h",
"scheduler_configuration_manager.cc", "scheduler_configuration_manager.cc",
"scheduler_configuration_manager.h", "scheduler_configuration_manager.h",
"secure_channel/nearby_connection_broker.cc",
"secure_channel/nearby_connection_broker.h",
"secure_channel/nearby_connection_broker_impl.cc",
"secure_channel/nearby_connection_broker_impl.h",
"secure_channel/nearby_endpoint_finder.cc", "secure_channel/nearby_endpoint_finder.cc",
"secure_channel/nearby_endpoint_finder.h", "secure_channel/nearby_endpoint_finder.h",
"secure_channel/nearby_endpoint_finder_impl.cc", "secure_channel/nearby_endpoint_finder_impl.cc",
...@@ -3175,6 +3179,8 @@ static_library("test_support") { ...@@ -3175,6 +3179,8 @@ static_library("test_support") {
"printing/printing_stubs.h", "printing/printing_stubs.h",
"scoped_set_running_on_chromeos_for_testing.cc", "scoped_set_running_on_chromeos_for_testing.cc",
"scoped_set_running_on_chromeos_for_testing.h", "scoped_set_running_on_chromeos_for_testing.h",
"secure_channel/fake_nearby_connection_broker.cc",
"secure_channel/fake_nearby_connection_broker.h",
"secure_channel/fake_nearby_endpoint_finder.cc", "secure_channel/fake_nearby_endpoint_finder.cc",
"secure_channel/fake_nearby_endpoint_finder.h", "secure_channel/fake_nearby_endpoint_finder.h",
"settings/scoped_testing_cros_settings.cc", "settings/scoped_testing_cros_settings.cc",
...@@ -3770,6 +3776,7 @@ source_set("unit_tests") { ...@@ -3770,6 +3776,7 @@ source_set("unit_tests") {
"scanning/scanning_type_converters_unittest.cc", "scanning/scanning_type_converters_unittest.cc",
"scanning/zeroconf_scanner_detector_unittest.cc", "scanning/zeroconf_scanner_detector_unittest.cc",
"scheduler_configuration_manager_unittest.cc", "scheduler_configuration_manager_unittest.cc",
"secure_channel/nearby_connection_broker_impl_unittest.cc",
"secure_channel/nearby_endpoint_finder_impl_unittest.cc", "secure_channel/nearby_endpoint_finder_impl_unittest.cc",
"session_length_limiter_unittest.cc", "session_length_limiter_unittest.cc",
"settings/cros_settings_unittest.cc", "settings/cros_settings_unittest.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/secure_channel/fake_nearby_connection_broker.h"
namespace chromeos {
namespace secure_channel {
FakeNearbyConnectionBroker::FakeNearbyConnectionBroker(
const std::vector<uint8_t>& bluetooth_public_address,
mojo::PendingReceiver<mojom::NearbyMessageSender> message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver> message_receiver_remote,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback)
: NearbyConnectionBroker(bluetooth_public_address,
std::move(message_sender_receiver),
std::move(message_receiver_remote),
std::move(on_connected_callback),
std::move(on_disconnected_callback)) {}
FakeNearbyConnectionBroker::~FakeNearbyConnectionBroker() = default;
void FakeNearbyConnectionBroker::SendMessage(const std::string& message,
SendMessageCallback callback) {
sent_messages_.push_back(message);
std::move(callback).Run(should_send_message_succeed_);
}
} // namespace secure_channel
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_FAKE_NEARBY_CONNECTION_BROKER_H_
#define CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_FAKE_NEARBY_CONNECTION_BROKER_H_
#include "chrome/browser/chromeos/secure_channel/nearby_connection_broker.h"
namespace chromeos {
namespace secure_channel {
class FakeNearbyConnectionBroker : public NearbyConnectionBroker {
public:
FakeNearbyConnectionBroker(
const std::vector<uint8_t>& bluetooth_public_address,
mojo::PendingReceiver<mojom::NearbyMessageSender> message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver> message_receiver_remote,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback);
~FakeNearbyConnectionBroker() override;
using NearbyConnectionBroker::bluetooth_public_address;
using NearbyConnectionBroker::Disconnect;
using NearbyConnectionBroker::NotifyConnected;
using NearbyConnectionBroker::NotifyMessageReceived;
void set_should_send_message_succeed(bool should_send_message_succeed) {
should_send_message_succeed_ = should_send_message_succeed;
}
const std::vector<std::string>& sent_messages() const {
return sent_messages_;
}
private:
// mojom::NearbyMessageSender:
void SendMessage(const std::string& message,
SendMessageCallback callback) override;
std::vector<std::string> sent_messages_;
bool should_send_message_succeed_ = true;
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_FAKE_NEARBY_CONNECTION_BROKER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/secure_channel/nearby_connection_broker.h"
#include "base/bind.h"
#include "base/check.h"
namespace chromeos {
namespace secure_channel {
NearbyConnectionBroker::NearbyConnectionBroker(
const std::vector<uint8_t>& bluetooth_public_address,
mojo::PendingReceiver<mojom::NearbyMessageSender> message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver> message_receiver_remote,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback)
: bluetooth_public_address_(bluetooth_public_address),
message_sender_receiver_(this, std::move(message_sender_receiver)),
message_receiver_remote_(std::move(message_receiver_remote)),
on_connected_callback_(std::move(on_connected_callback)),
on_disconnected_callback_(std::move(on_disconnected_callback)) {
message_sender_receiver_.set_disconnect_handler(base::BindOnce(
&NearbyConnectionBroker::Disconnect, base::Unretained(this)));
message_receiver_remote_.set_disconnect_handler(base::BindOnce(
&NearbyConnectionBroker::Disconnect, base::Unretained(this)));
}
NearbyConnectionBroker::~NearbyConnectionBroker() = default;
void NearbyConnectionBroker::Disconnect() {
message_sender_receiver_.reset();
message_receiver_remote_.reset();
if (on_disconnected_callback_)
std::move(on_disconnected_callback_).Run();
}
void NearbyConnectionBroker::NotifyConnected() {
DCHECK(on_connected_callback_);
std::move(on_connected_callback_).Run();
}
void NearbyConnectionBroker::NotifyMessageReceived(
const std::string& received_message) {
message_receiver_remote_->OnMessageReceived(received_message);
}
} // namespace secure_channel
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_NEARBY_CONNECTION_BROKER_H_
#define CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_NEARBY_CONNECTION_BROKER_H_
#include <string>
#include <vector>
#include "base/callback.h"
#include "chromeos/services/secure_channel/public/mojom/nearby_connector.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace chromeos {
namespace secure_channel {
// Attempts to create a Nearby Connection to a remote device and exchange
// messages on behalf of the SecureChannel service. Implements the
// mojom::NearbyMessageSender interface so that SecureChannel can send messages
// to Nearby Connections, and uses the mojom::NearbyMessageReceiver interface to
// relay messages received from Nearby Connections back to SecureChannel.
//
// An instance of this class is only meant to be used for one connection
// request to a single device. To make a new request, create a new object.
class NearbyConnectionBroker : public mojom::NearbyMessageSender {
public:
~NearbyConnectionBroker() override;
protected:
NearbyConnectionBroker(
const std::vector<uint8_t>& bluetooth_public_address,
mojo::PendingReceiver<mojom::NearbyMessageSender> message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver> message_receiver_remote,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback);
const std::vector<uint8_t>& bluetooth_public_address() const {
return bluetooth_public_address_;
}
void Disconnect();
void NotifyConnected();
void NotifyMessageReceived(const std::string& received_message);
private:
std::vector<uint8_t> bluetooth_public_address_;
mojo::Receiver<mojom::NearbyMessageSender> message_sender_receiver_;
mojo::Remote<mojom::NearbyMessageReceiver> message_receiver_remote_;
base::OnceClosure on_connected_callback_;
base::OnceClosure on_disconnected_callback_;
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_NEARBY_CONNECTION_BROKER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/secure_channel/nearby_connection_broker_impl.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/chromeos/secure_channel/nearby_endpoint_finder.h"
#include "chromeos/components/multidevice/logging/logging.h"
namespace chromeos {
namespace secure_channel {
namespace {
NearbyConnectionBrokerImpl::Factory* g_test_factory = nullptr;
using location::nearby::connections::mojom::BytesPayload;
using location::nearby::connections::mojom::ConnectionInfoPtr;
using location::nearby::connections::mojom::ConnectionOptions;
using location::nearby::connections::mojom::DiscoveredEndpointInfoPtr;
using location::nearby::connections::mojom::Medium;
using location::nearby::connections::mojom::MediumSelection;
using location::nearby::connections::mojom::NearbyConnections;
using location::nearby::connections::mojom::Payload;
using location::nearby::connections::mojom::PayloadContent;
using location::nearby::connections::mojom::PayloadPtr;
using location::nearby::connections::mojom::PayloadTransferUpdatePtr;
using location::nearby::connections::mojom::Status;
} // namespace
// static
std::unique_ptr<NearbyConnectionBroker>
NearbyConnectionBrokerImpl::Factory::Create(
const std::vector<uint8_t>& bluetooth_public_address,
NearbyEndpointFinder* endpoint_finder,
mojo::PendingReceiver<mojom::NearbyMessageSender> message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver> message_receiver_remote,
const mojo::SharedRemote<NearbyConnections>& nearby_connections,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback) {
if (g_test_factory) {
return g_test_factory->CreateInstance(
bluetooth_public_address, endpoint_finder,
std::move(message_sender_receiver), std::move(message_receiver_remote),
nearby_connections, std::move(on_connected_callback),
std::move(on_disconnected_callback));
}
return base::WrapUnique(new NearbyConnectionBrokerImpl(
bluetooth_public_address, endpoint_finder,
std::move(message_sender_receiver), std::move(message_receiver_remote),
nearby_connections, std::move(on_connected_callback),
std::move(on_disconnected_callback)));
}
// static
void NearbyConnectionBrokerImpl::Factory::SetFactoryForTesting(
Factory* test_factory) {
g_test_factory = test_factory;
}
NearbyConnectionBrokerImpl::NearbyConnectionBrokerImpl(
const std::vector<uint8_t>& bluetooth_public_address,
NearbyEndpointFinder* endpoint_finder,
mojo::PendingReceiver<mojom::NearbyMessageSender> message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver> message_receiver_remote,
const mojo::SharedRemote<NearbyConnections>& nearby_connections,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback)
: NearbyConnectionBroker(bluetooth_public_address,
std::move(message_sender_receiver),
std::move(message_receiver_remote),
std::move(on_connected_callback),
std::move(on_disconnected_callback)),
endpoint_finder_(endpoint_finder),
nearby_connections_(nearby_connections) {
TransitionToStatus(ConnectionStatus::kDiscoveringEndpoint);
endpoint_finder_->FindEndpoint(
bluetooth_public_address,
base::BindOnce(&NearbyConnectionBrokerImpl::OnEndpointDiscovered,
base::Unretained(this)),
base::BindOnce(&NearbyConnectionBrokerImpl::OnDiscoveryFailure,
base::Unretained(this)));
}
NearbyConnectionBrokerImpl::~NearbyConnectionBrokerImpl() = default;
void NearbyConnectionBrokerImpl::TransitionToStatus(
ConnectionStatus connection_status) {
PA_LOG(VERBOSE) << "Nearby Connection status: " << connection_status_
<< " => " << connection_status;
connection_status_ = connection_status;
}
void NearbyConnectionBrokerImpl::TransitionToDisconnected() {
TransitionToStatus(ConnectionStatus::kDisconnected);
Disconnect();
}
void NearbyConnectionBrokerImpl::OnEndpointDiscovered(
const std::string& endpoint_id,
DiscoveredEndpointInfoPtr info) {
DCHECK_EQ(ConnectionStatus::kDiscoveringEndpoint, connection_status_);
remote_endpoint_id_ = endpoint_id;
TransitionToStatus(ConnectionStatus::kRequestingConnection);
nearby_connections_->RequestConnection(
mojom::kServiceId, info->endpoint_info, remote_endpoint_id_,
ConnectionOptions::New(MediumSelection::New(/*bluetooth=*/true,
/*ble=*/false,
/*webrtc=*/true,
/*wifi_lan=*/false),
bluetooth_public_address()),
connection_lifecycle_listener_receiver_.BindNewPipeAndPassRemote(),
base::BindOnce(&NearbyConnectionBrokerImpl::OnRequestConnectionResult,
weak_ptr_factory_.GetWeakPtr()));
}
void NearbyConnectionBrokerImpl::OnDiscoveryFailure() {
DCHECK_EQ(ConnectionStatus::kDiscoveringEndpoint, connection_status_);
TransitionToDisconnected();
}
void NearbyConnectionBrokerImpl::OnRequestConnectionResult(Status status) {
if (status == Status::kSuccess) {
DCHECK_EQ(ConnectionStatus::kRequestingConnection, connection_status_);
TransitionToStatus(ConnectionStatus::kWaitingForConnectionInitiation);
return;
}
PA_LOG(WARNING) << "RequestConnection() failed: " << status;
TransitionToDisconnected();
}
void NearbyConnectionBrokerImpl::OnAcceptConnectionResult(Status status) {
if (status == Status::kSuccess) {
DCHECK_EQ(ConnectionStatus::kAcceptingConnection, connection_status_);
TransitionToStatus(
ConnectionStatus::kWaitingForConnectionToBeAcceptedByRemoteDevice);
return;
}
PA_LOG(WARNING) << "AcceptConnection() failed: " << status;
TransitionToDisconnected();
}
void NearbyConnectionBrokerImpl::OnSendPayloadResult(
SendMessageCallback callback,
Status status) {
bool success = status == Status::kSuccess;
std::move(callback).Run(success);
if (success)
return;
PA_LOG(WARNING) << "OnSendPayloadResult() failed: " << status;
TransitionToDisconnected();
}
void NearbyConnectionBrokerImpl::SendMessage(const std::string& message,
SendMessageCallback callback) {
DCHECK_EQ(ConnectionStatus::kConnected, connection_status_);
std::vector<uint8_t> message_as_bytes(message.begin(), message.end());
nearby_connections_->SendPayload(
mojom::kServiceId, std::vector<std::string>{remote_endpoint_id_},
Payload::New(
next_sent_payload_id_++,
PayloadContent::NewBytes(BytesPayload::New(message_as_bytes))),
base::BindOnce(&NearbyConnectionBrokerImpl::OnSendPayloadResult,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void NearbyConnectionBrokerImpl::OnConnectionInitiated(
const std::string& endpoint_id,
ConnectionInfoPtr info) {
if (remote_endpoint_id_ != endpoint_id) {
PA_LOG(WARNING) << "OnConnectionInitiated(): unexpected endpoint ID "
<< endpoint_id;
return;
}
DCHECK_EQ(ConnectionStatus::kWaitingForConnectionInitiation,
connection_status_);
TransitionToStatus(ConnectionStatus::kAcceptingConnection);
nearby_connections_->AcceptConnection(
mojom::kServiceId, remote_endpoint_id_,
payload_listener_receiver_.BindNewPipeAndPassRemote(),
base::BindOnce(&NearbyConnectionBrokerImpl::OnAcceptConnectionResult,
weak_ptr_factory_.GetWeakPtr()));
}
void NearbyConnectionBrokerImpl::OnConnectionAccepted(
const std::string& endpoint_id) {
if (remote_endpoint_id_ != endpoint_id) {
PA_LOG(WARNING) << "OnConnectionAccepted(): unexpected endpoint ID "
<< endpoint_id;
return;
}
DCHECK_EQ(ConnectionStatus::kWaitingForConnectionToBeAcceptedByRemoteDevice,
connection_status_);
TransitionToStatus(ConnectionStatus::kConnected);
NotifyConnected();
}
void NearbyConnectionBrokerImpl::OnConnectionRejected(
const std::string& endpoint_id,
Status status) {
if (remote_endpoint_id_ != endpoint_id) {
PA_LOG(WARNING) << "OnConnectionRejected(): unexpected endpoint ID "
<< endpoint_id;
return;
}
PA_LOG(WARNING) << "Connection rejected: " << status;
TransitionToDisconnected();
}
void NearbyConnectionBrokerImpl::OnDisconnected(
const std::string& endpoint_id) {
if (remote_endpoint_id_ != endpoint_id) {
PA_LOG(WARNING) << "OnDisconnected(): unexpected endpoint ID "
<< endpoint_id;
return;
}
PA_LOG(WARNING) << "Connection disconnected";
TransitionToDisconnected();
}
void NearbyConnectionBrokerImpl::OnBandwidthChanged(
const std::string& endpoint_id,
Medium medium) {
if (remote_endpoint_id_ != endpoint_id) {
PA_LOG(WARNING) << "OnBandwidthChanged(): unexpected endpoint ID "
<< endpoint_id;
return;
}
PA_LOG(VERBOSE) << "Bandwidth changed: " << medium;
}
void NearbyConnectionBrokerImpl::OnPayloadReceived(
const std::string& endpoint_id,
PayloadPtr payload) {
if (remote_endpoint_id_ != endpoint_id) {
PA_LOG(WARNING) << "OnPayloadReceived(): unexpected endpoint ID "
<< endpoint_id;
return;
}
// TODO(khorimoto): Handle received payloads.
}
void NearbyConnectionBrokerImpl::OnPayloadTransferUpdate(
const std::string& endpoint_id,
PayloadTransferUpdatePtr update) {
if (remote_endpoint_id_ != endpoint_id) {
PA_LOG(WARNING) << "OnPayloadTransferUpdate(): unexpected endpoint ID "
<< endpoint_id;
return;
}
// TODO(khorimoto): Handle received payload updates.
}
std::ostream& operator<<(std::ostream& stream,
NearbyConnectionBrokerImpl::ConnectionStatus status) {
switch (status) {
case NearbyConnectionBrokerImpl::ConnectionStatus::kUninitialized:
stream << "[Uninitialized]";
break;
case NearbyConnectionBrokerImpl::ConnectionStatus::kDiscoveringEndpoint:
stream << "[Discovering endpoint]";
break;
case NearbyConnectionBrokerImpl::ConnectionStatus::kRequestingConnection:
stream << "[Requesting connection]";
break;
case NearbyConnectionBrokerImpl::ConnectionStatus::
kWaitingForConnectionInitiation:
stream << "[Waiting for connection initiation]";
break;
case NearbyConnectionBrokerImpl::ConnectionStatus::kAcceptingConnection:
stream << "[Accepting connection]";
break;
case NearbyConnectionBrokerImpl::ConnectionStatus::
kWaitingForConnectionToBeAcceptedByRemoteDevice:
stream << "[Waiting for connection to be accepted]";
break;
case NearbyConnectionBrokerImpl::ConnectionStatus::kConnected:
stream << "[Connected]";
break;
case NearbyConnectionBrokerImpl::ConnectionStatus::kDisconnected:
stream << "[Disconnected]";
break;
}
return stream;
}
} // namespace secure_channel
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_NEARBY_CONNECTION_BROKER_IMPL_H_
#define CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_NEARBY_CONNECTION_BROKER_IMPL_H_
#include <memory>
#include <ostream>
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/secure_channel/nearby_connection_broker.h"
#include "chromeos/services/nearby/public/mojom/nearby_connections.mojom.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
namespace chromeos {
namespace secure_channel {
class NearbyEndpointFinder;
// NearbyConnectionBroker implementation which utilizes NearbyEndpointFinder to
// find an endpoint, then uses Nearby Connections to create and maintain a
// connection. The overall process consists of:
// (1) Finding an endpoint via NearbyEndpointFinder.
// (2) Requesting a connection using that endpoint.
// (3) Accepting a connection.
// (4) Exchanging messages over the connection.
//
// Deleting an instance of this class tears down any active connection and
// performs cleanup if necessary.
//
// TODO(khorimoto): Add the ability to upgrade bandwidth to WebRTC and to
// receive payloads.
class NearbyConnectionBrokerImpl
: public NearbyConnectionBroker,
public location::nearby::connections::mojom::ConnectionLifecycleListener,
public location::nearby::connections::mojom::PayloadListener {
public:
class Factory {
public:
static std::unique_ptr<NearbyConnectionBroker> Create(
const std::vector<uint8_t>& bluetooth_public_address,
NearbyEndpointFinder* endpoint_finder,
mojo::PendingReceiver<mojom::NearbyMessageSender>
message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver>
message_receiver_remote,
const mojo::SharedRemote<
location::nearby::connections::mojom::NearbyConnections>&
nearby_connections,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback);
static void SetFactoryForTesting(Factory* test_factory);
virtual ~Factory() = default;
protected:
virtual std::unique_ptr<NearbyConnectionBroker> CreateInstance(
const std::vector<uint8_t>& bluetooth_public_address,
NearbyEndpointFinder* endpoint_finder,
mojo::PendingReceiver<mojom::NearbyMessageSender>
message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver>
message_receiver_remote,
const mojo::SharedRemote<
location::nearby::connections::mojom::NearbyConnections>&
nearby_connections,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback) = 0;
};
~NearbyConnectionBrokerImpl() override;
private:
enum class ConnectionStatus {
kUninitialized,
kDiscoveringEndpoint,
kRequestingConnection,
kWaitingForConnectionInitiation,
kAcceptingConnection,
kWaitingForConnectionToBeAcceptedByRemoteDevice,
kConnected,
kDisconnected,
};
friend std::ostream& operator<<(
std::ostream& stream,
NearbyConnectionBrokerImpl::ConnectionStatus status);
NearbyConnectionBrokerImpl(
const std::vector<uint8_t>& bluetooth_public_address,
NearbyEndpointFinder* endpoint_finder,
mojo::PendingReceiver<mojom::NearbyMessageSender> message_sender_receiver,
mojo::PendingRemote<mojom::NearbyMessageReceiver> message_receiver_remote,
const mojo::SharedRemote<
location::nearby::connections::mojom::NearbyConnections>&
nearby_connections,
base::OnceClosure on_connected_callback,
base::OnceClosure on_disconnected_callback);
void TransitionToStatus(ConnectionStatus connection_status);
void TransitionToDisconnected();
void OnEndpointDiscovered(
const std::string& endpoint_id,
location::nearby::connections::mojom::DiscoveredEndpointInfoPtr info);
void OnDiscoveryFailure();
void OnRequestConnectionResult(
location::nearby::connections::mojom::Status status);
void OnAcceptConnectionResult(
location::nearby::connections::mojom::Status status);
void OnSendPayloadResult(SendMessageCallback callback,
location::nearby::connections::mojom::Status status);
// mojom::NearbyMessageSender:
void SendMessage(const std::string& message,
SendMessageCallback callback) override;
// location::nearby::connections::mojom::ConnectionLifecycleListener:
void OnConnectionInitiated(
const std::string& endpoint_id,
location::nearby::connections::mojom::ConnectionInfoPtr info) override;
void OnConnectionAccepted(const std::string& endpoint_id) override;
void OnConnectionRejected(
const std::string& endpoint_id,
location::nearby::connections::mojom::Status status) override;
void OnDisconnected(const std::string& endpoint_id) override;
void OnBandwidthChanged(
const std::string& endpoint_id,
location::nearby::connections::mojom::Medium medium) override;
// location::nearby::connections::mojom::PayloadListener:
void OnPayloadReceived(
const std::string& endpoint_id,
location::nearby::connections::mojom::PayloadPtr payload) override;
void OnPayloadTransferUpdate(
const std::string& endpoint_id,
location::nearby::connections::mojom::PayloadTransferUpdatePtr update)
override;
NearbyEndpointFinder* endpoint_finder_;
mojo::SharedRemote<location::nearby::connections::mojom::NearbyConnections>
nearby_connections_;
mojo::Receiver<
location::nearby::connections::mojom::ConnectionLifecycleListener>
connection_lifecycle_listener_receiver_{this};
mojo::Receiver<location::nearby::connections::mojom::PayloadListener>
payload_listener_receiver_{this};
ConnectionStatus connection_status_ = ConnectionStatus::kUninitialized;
int64_t next_sent_payload_id_ = 0L;
// Set once an endpoint is discovered.
std::string remote_endpoint_id_;
base::WeakPtrFactory<NearbyConnectionBrokerImpl> weak_ptr_factory_{this};
};
std::ostream& operator<<(std::ostream& stream,
NearbyConnectionBrokerImpl::ConnectionStatus status);
} // namespace secure_channel
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_SECURE_CHANNEL_NEARBY_CONNECTION_BROKER_IMPL_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/secure_channel/nearby_connection_broker_impl.h"
#include <memory>
#include <vector>
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
#include "chrome/browser/chromeos/secure_channel/fake_nearby_endpoint_finder.h"
#include "chromeos/services/nearby/public/cpp/mock_nearby_connections.h"
#include "chromeos/services/secure_channel/public/mojom/nearby_connector.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace secure_channel {
namespace {
using location::nearby::connections::mojom::ConnectionInfo;
using location::nearby::connections::mojom::ConnectionLifecycleListener;
using location::nearby::connections::mojom::ConnectionOptionsPtr;
using location::nearby::connections::mojom::DiscoveredEndpointInfo;
using location::nearby::connections::mojom::EndpointDiscoveryListener;
using location::nearby::connections::mojom::PayloadListener;
using location::nearby::connections::mojom::PayloadPtr;
using location::nearby::connections::mojom::Status;
using testing::_;
using testing::Invoke;
const char kEndpointId[] = "endpointId";
const std::vector<uint8_t>& GetBluetoothAddress() {
static const std::vector<uint8_t> address{0, 1, 2, 3, 4, 5};
return address;
}
const std::vector<uint8_t>& GetEndpointInfo() {
static const std::vector<uint8_t> info{6, 7, 8, 9, 10};
return info;
}
} // namespace
class NearbyConnectionBrokerImplTest : public testing::Test,
public mojom::NearbyMessageReceiver {
protected:
NearbyConnectionBrokerImplTest() = default;
~NearbyConnectionBrokerImplTest() override = default;
// testing::Test:
void SetUp() override {
broker_ = NearbyConnectionBrokerImpl::Factory::Create(
GetBluetoothAddress(), &fake_endpoint_finder_,
message_sender_.BindNewPipeAndPassReceiver(),
message_receiver_.BindNewPipeAndPassRemote(),
mock_nearby_connections_.shared_remote(),
base::BindOnce(&NearbyConnectionBrokerImplTest::OnConnected,
base::Unretained(this)),
base::BindOnce(&NearbyConnectionBrokerImplTest::OnDisconnected,
base::Unretained(this)));
EXPECT_EQ(GetBluetoothAddress(),
fake_endpoint_finder_.remote_device_bluetooth_address());
}
void DiscoverEndpoint() {
base::RunLoop run_loop;
EXPECT_CALL(mock_nearby_connections_, RequestConnection(_, _, _, _, _, _))
.WillOnce(Invoke(
[&](const std::string& service_id,
const std::vector<uint8_t>& endpoint_info,
const std::string& endpoint_id, ConnectionOptionsPtr options,
mojo::PendingRemote<ConnectionLifecycleListener> listener,
NearbyConnectionsMojom::RequestConnectionCallback callback) {
request_connection_callback_ = std::move(callback);
connection_lifecycle_listener_.Bind(std::move(listener));
run_loop.Quit();
}));
fake_endpoint_finder_.NotifyEndpointFound(
kEndpointId,
DiscoveredEndpointInfo::New(GetEndpointInfo(), mojom::kServiceId));
run_loop.Run();
}
void FailDiscovery() {
base::RunLoop run_loop;
on_disconnected_closure_ = run_loop.QuitClosure();
fake_endpoint_finder_.NotifyEndpointDiscoveryFailure();
run_loop.Run();
}
void InvokeRequestConnectionCallback(bool success) {
if (!success) {
base::RunLoop run_loop;
on_disconnected_closure_ = run_loop.QuitClosure();
std::move(request_connection_callback_).Run(Status::kError);
run_loop.Run();
return;
}
std::move(request_connection_callback_).Run(Status::kSuccess);
// Ensure that callback result is received; cannot use external event
// because the success callback only updates internal state.
base::RunLoop().RunUntilIdle();
}
void NotifyConnectionInitiated() {
base::RunLoop run_loop;
EXPECT_CALL(mock_nearby_connections_, AcceptConnection(_, _, _, _))
.WillOnce(Invoke(
[&](const std::string& service_id, const std::string& endpoint_id,
mojo::PendingRemote<PayloadListener> listener,
NearbyConnectionsMojom::AcceptConnectionCallback callback) {
accept_connection_callback_ = std::move(callback);
payload_listener_listener_.Bind(std::move(listener));
run_loop.Quit();
}));
connection_lifecycle_listener_->OnConnectionInitiated(
kEndpointId, ConnectionInfo::New());
run_loop.Run();
}
void InvokeAcceptConnectionCallback(bool success) {
if (!success) {
base::RunLoop run_loop;
on_disconnected_closure_ = run_loop.QuitClosure();
std::move(accept_connection_callback_).Run(Status::kError);
run_loop.Run();
return;
}
std::move(accept_connection_callback_).Run(Status::kSuccess);
// Ensure that callback result is received; cannot use external event
// because the success callback only updates internal state.
base::RunLoop().RunUntilIdle();
}
void NotifyConnectionAccepted() {
base::RunLoop run_loop;
on_connected_closure_ = run_loop.QuitClosure();
connection_lifecycle_listener_->OnConnectionAccepted(kEndpointId);
run_loop.Run();
}
void SetUpFullConnection() {
DiscoverEndpoint();
InvokeRequestConnectionCallback(/*success=*/true);
NotifyConnectionInitiated();
InvokeAcceptConnectionCallback(/*success=*/true);
NotifyConnectionAccepted();
}
void SendMessage(const std::string& message, bool success) {
base::RunLoop send_message_run_loop;
base::RunLoop send_message_response_run_loop;
NearbyConnectionsMojom::SendPayloadCallback send_payload_callback;
std::string sent_message;
EXPECT_CALL(mock_nearby_connections_, SendPayload(_, _, _, _))
.WillOnce(
Invoke([&](const std::string& service_id,
const std::vector<std::string>& endpoint_ids,
PayloadPtr payload,
NearbyConnectionsMojom::SendPayloadCallback callback) {
send_payload_callback = std::move(callback);
const std::vector<uint8_t>& payload_bytes =
payload->content->get_bytes()->bytes;
sent_message =
std::string(payload_bytes.begin(), payload_bytes.end());
send_message_run_loop.Quit();
}));
message_sender_->SendMessage(
message, base::BindLambdaForTesting([&](bool did_send_succeeed) {
EXPECT_EQ(success, did_send_succeeed);
send_message_response_run_loop.Quit();
}));
send_message_run_loop.Run();
EXPECT_EQ(message, sent_message);
if (success) {
std::move(send_payload_callback).Run(Status::kSuccess);
send_message_response_run_loop.Run();
return;
}
// Failure to send should disconnect the ongoing connection.
base::RunLoop disconnect_run_loop;
on_disconnected_closure_ = disconnect_run_loop.QuitClosure();
std::move(send_payload_callback).Run(Status::kError);
send_message_response_run_loop.Run();
disconnect_run_loop.Run();
}
// TODO(khormoto): Verify received messages once this functionality is
// implemented.
std::vector<std::string> received_messages_;
private:
// mojom::NearbyMessageReceiver:
void OnMessageReceived(const std::string& message) override {
received_messages_.push_back(message);
}
void OnConnected() { std::move(on_connected_closure_).Run(); }
void OnDisconnected() { std::move(on_disconnected_closure_).Run(); }
base::test::TaskEnvironment task_environment_;
nearby::MockNearbyConnections mock_nearby_connections_;
FakeNearbyEndpointFinder fake_endpoint_finder_;
mojo::Remote<mojom::NearbyMessageSender> message_sender_;
mojo::Receiver<mojom::NearbyMessageReceiver> message_receiver_{this};
std::unique_ptr<NearbyConnectionBroker> broker_;
base::OnceClosure on_connected_closure_;
base::OnceClosure on_disconnected_closure_;
NearbyConnectionsMojom::RequestConnectionCallback
request_connection_callback_;
NearbyConnectionsMojom::AcceptConnectionCallback accept_connection_callback_;
mojo::Remote<ConnectionLifecycleListener> connection_lifecycle_listener_;
mojo::Remote<PayloadListener> payload_listener_listener_;
};
// TODO(khorimoto): Add test for receiving incoming messages.
TEST_F(NearbyConnectionBrokerImplTest, SendAndReceive) {
SetUpFullConnection();
SendMessage("test1", /*success=*/true);
SendMessage("test2", /*success=*/true);
}
TEST_F(NearbyConnectionBrokerImplTest, FailToSend) {
SetUpFullConnection();
SendMessage("test", /*success=*/false);
}
TEST_F(NearbyConnectionBrokerImplTest, FailDiscovery) {
FailDiscovery();
}
TEST_F(NearbyConnectionBrokerImplTest, FailRequestingConnection) {
DiscoverEndpoint();
InvokeRequestConnectionCallback(/*success=*/false);
}
TEST_F(NearbyConnectionBrokerImplTest, FailAcceptingConnection) {
DiscoverEndpoint();
InvokeRequestConnectionCallback(/*success=*/true);
NotifyConnectionInitiated();
InvokeAcceptConnectionCallback(/*success=*/false);
}
} // namespace secure_channel
} // namespace chromeos
...@@ -8,4 +8,15 @@ module chromeos.secure_channel.mojom; ...@@ -8,4 +8,15 @@ module chromeos.secure_channel.mojom;
// with each connection request. // with each connection request.
const string kServiceId = "secure_channel"; const string kServiceId = "secure_channel";
// TODO(khorimoto): Add SecureChannel interfaces for Nearby Connections. // Sends messages over a Nearby Connection.
\ No newline at end of file interface NearbyMessageSender {
// Sends |message|, returning whether the message was sent successfully.
SendMessage(string message) => (bool success);
};
// Receives messages over a Nearby connection.
interface NearbyMessageReceiver {
// Called whenever a message is received over the connection.
OnMessageReceived(string message);
};
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