Commit e4fe160f authored by khorimoto's avatar khorimoto Committed by Commit bot

[CrOS Tether] Create KeepAliveScheduler, a class which schedules keep-alive...

[CrOS Tether] Create KeepAliveScheduler, a class which schedules keep-alive tickles to be sent to a connected host every 4 minutes until the device disconnects.

BUG=672263

Review-Url: https://codereview.chromium.org/2741253002
Cr-Commit-Position: refs/heads/master@{#456249}
parent a417069d
...@@ -32,6 +32,8 @@ static_library("tether") { ...@@ -32,6 +32,8 @@ static_library("tether") {
"initializer.h", "initializer.h",
"keep_alive_operation.cc", "keep_alive_operation.cc",
"keep_alive_operation.h", "keep_alive_operation.h",
"keep_alive_scheduler.cc",
"keep_alive_scheduler.h",
"local_device_data_provider.cc", "local_device_data_provider.cc",
"local_device_data_provider.h", "local_device_data_provider.h",
"message_transfer_operation.cc", "message_transfer_operation.cc",
...@@ -64,6 +66,8 @@ static_library("test_support") { ...@@ -64,6 +66,8 @@ static_library("test_support") {
testonly = true testonly = true
sources = [ sources = [
"fake_active_host.cc",
"fake_active_host.h",
"fake_ble_connection_manager.cc", "fake_ble_connection_manager.cc",
"fake_ble_connection_manager.h", "fake_ble_connection_manager.h",
"fake_tether_host_fetcher.cc", "fake_tether_host_fetcher.cc",
...@@ -80,6 +84,7 @@ static_library("test_support") { ...@@ -80,6 +84,7 @@ static_library("test_support") {
"//base", "//base",
"//components/cryptauth", "//components/cryptauth",
"//testing/gmock", "//testing/gmock",
"//testing/gtest",
] ]
} }
...@@ -98,6 +103,7 @@ source_set("unit_tests") { ...@@ -98,6 +103,7 @@ source_set("unit_tests") {
"host_scanner_operation_unittest.cc", "host_scanner_operation_unittest.cc",
"host_scanner_unittest.cc", "host_scanner_unittest.cc",
"keep_alive_operation_unittest.cc", "keep_alive_operation_unittest.cc",
"keep_alive_scheduler_unittest.cc",
"local_device_data_provider_unittest.cc", "local_device_data_provider_unittest.cc",
"message_transfer_operation_unittest.cc", "message_transfer_operation_unittest.cc",
"message_wrapper_unittest.cc", "message_wrapper_unittest.cc",
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chromeos/components/tether/active_host.h" #include "chromeos/components/tether/active_host.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/values.h" #include "base/values.h"
#include "chromeos/components/tether/pref_names.h" #include "chromeos/components/tether/pref_names.h"
#include "chromeos/components/tether/tether_host_fetcher.h" #include "chromeos/components/tether/tether_host_fetcher.h"
...@@ -80,22 +81,43 @@ ActiveHost::ActiveHostStatus ActiveHost::GetActiveHostStatus() const { ...@@ -80,22 +81,43 @@ ActiveHost::ActiveHostStatus ActiveHost::GetActiveHostStatus() const {
pref_service_->GetInteger(prefs::kActiveHostStatus)); pref_service_->GetInteger(prefs::kActiveHostStatus));
} }
const std::string ActiveHost::GetActiveHostDeviceId() const { std::string ActiveHost::GetActiveHostDeviceId() const {
return pref_service_->GetString(prefs::kActiveHostDeviceId); return pref_service_->GetString(prefs::kActiveHostDeviceId);
} }
const std::string ActiveHost::GetWifiNetworkId() const { std::string ActiveHost::GetWifiNetworkId() const {
return pref_service_->GetString(prefs::kWifiNetworkId); return pref_service_->GetString(prefs::kWifiNetworkId);
} }
void ActiveHost::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void ActiveHost::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void ActiveHost::SetActiveHost(ActiveHostStatus active_host_status, void ActiveHost::SetActiveHost(ActiveHostStatus active_host_status,
const std::string& active_host_device_id, const std::string& active_host_device_id,
const std::string& wifi_network_id) { const std::string& wifi_network_id) {
bool status_changed = GetActiveHostStatus() != active_host_status;
bool device_changed = GetActiveHostDeviceId() != active_host_device_id;
bool network_id_changed = GetWifiNetworkId() != wifi_network_id;
if (!status_changed && !device_changed && !network_id_changed) {
// If nothing has changed, return early.
return;
}
pref_service_->Set(prefs::kActiveHostStatus, pref_service_->Set(prefs::kActiveHostStatus,
base::Value(static_cast<int>(active_host_status))); base::Value(static_cast<int>(active_host_status)));
pref_service_->Set(prefs::kActiveHostDeviceId, pref_service_->Set(prefs::kActiveHostDeviceId,
base::Value(active_host_device_id)); base::Value(active_host_device_id));
pref_service_->Set(prefs::kWifiNetworkId, base::Value(wifi_network_id)); pref_service_->Set(prefs::kWifiNetworkId, base::Value(wifi_network_id));
// Now, send an active host changed update.
GetActiveHost(base::Bind(&ActiveHost::SendActiveHostChangedUpdate,
weak_ptr_factory_.GetWeakPtr()));
} }
void ActiveHost::OnTetherHostFetched( void ActiveHost::OnTetherHostFetched(
...@@ -134,6 +156,19 @@ void ActiveHost::OnTetherHostFetched( ...@@ -134,6 +156,19 @@ void ActiveHost::OnTetherHostFetched(
std::move(remote_device), GetWifiNetworkId()); std::move(remote_device), GetWifiNetworkId());
} }
void ActiveHost::SendActiveHostChangedUpdate(
ActiveHostStatus active_host_status,
std::unique_ptr<cryptauth::RemoteDevice> active_host,
const std::string& wifi_network_id) {
for (auto& observer : observer_list_) {
std::unique_ptr<cryptauth::RemoteDevice> unique_remote_device =
active_host ? base::MakeUnique<cryptauth::RemoteDevice>(*active_host)
: nullptr;
observer.OnActiveHostChanged(
active_host_status, std::move(unique_remote_device), wifi_network_id);
}
}
} // namespace tether } // namespace tether
} // namespace chromeos } // namespace chromeos
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
class PrefRegistrySimple; class PrefRegistrySimple;
class PrefService; class PrefService;
...@@ -36,6 +37,14 @@ class ActiveHost { ...@@ -36,6 +37,14 @@ class ActiveHost {
CONNECTED = 2 CONNECTED = 2
}; };
class Observer {
public:
virtual void OnActiveHostChanged(
ActiveHostStatus active_host_status,
std::unique_ptr<cryptauth::RemoteDevice> active_host_device,
const std::string& wifi_network_id) = 0;
};
ActiveHost(TetherHostFetcher* tether_host_fetcher, PrefService* pref_service); ActiveHost(TetherHostFetcher* tether_host_fetcher, PrefService* pref_service);
virtual ~ActiveHost(); virtual ~ActiveHost();
...@@ -44,18 +53,19 @@ class ActiveHost { ...@@ -44,18 +53,19 @@ class ActiveHost {
// Sets the active host to be no host at all (i.e., the local device is not // Sets the active host to be no host at all (i.e., the local device is not
// connecting or connected to a tether host). // connecting or connected to a tether host).
void SetActiveHostDisconnected(); virtual void SetActiveHostDisconnected();
// Sets the active host to be the device with ID |active_host_device_id| and // Sets the active host to be the device with ID |active_host_device_id| and
// records that the there is an active attempt to connect to that host (i.e., // records that the there is an active attempt to connect to that host (i.e.,
// the host is not yet connected but it is in the process of connecting). // the host is not yet connected but it is in the process of connecting).
void SetActiveHostConnecting(const std::string& active_host_device_id); virtual void SetActiveHostConnecting(
const std::string& active_host_device_id);
// Sets the active host to be the device with ID |active_host_device_id| and // Sets the active host to be the device with ID |active_host_device_id| and
// that the local device is connected to that device on the mobile hotspot // that the local device is connected to that device on the mobile hotspot
// with Wi-Fi network ID |wifi_network_id|. // with Wi-Fi network ID |wifi_network_id|.
void SetActiveHostConnected(const std::string& active_host_device_id, virtual void SetActiveHostConnected(const std::string& active_host_device_id,
const std::string& wifi_network_id); const std::string& wifi_network_id);
// Gets the active host and associated metadata asynchronously. If // Gets the active host and associated metadata asynchronously. If
// the active host status is... // the active host status is...
...@@ -67,12 +77,21 @@ class ActiveHost { ...@@ -67,12 +77,21 @@ class ActiveHost {
base::Callback<void(ActiveHostStatus active_host_status, base::Callback<void(ActiveHostStatus active_host_status,
std::unique_ptr<cryptauth::RemoteDevice> active_host, std::unique_ptr<cryptauth::RemoteDevice> active_host,
const std::string& wifi_network_id)>; const std::string& wifi_network_id)>;
void GetActiveHost(const ActiveHostCallback& active_host_callback); virtual void GetActiveHost(const ActiveHostCallback& active_host_callback);
// Synchronous getter methods which do not return a full RemoteDevice object. // Synchronous getter methods which do not return a full RemoteDevice object.
ActiveHostStatus GetActiveHostStatus() const; virtual ActiveHostStatus GetActiveHostStatus() const;
const std::string GetActiveHostDeviceId() const; virtual std::string GetActiveHostDeviceId() const;
const std::string GetWifiNetworkId() const; virtual std::string GetWifiNetworkId() const;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
protected:
void SendActiveHostChangedUpdate(
ActiveHostStatus active_host_status,
std::unique_ptr<cryptauth::RemoteDevice> active_host,
const std::string& wifi_network_id);
private: private:
void SetActiveHost(ActiveHostStatus active_host_status, void SetActiveHost(ActiveHostStatus active_host_status,
...@@ -86,6 +105,8 @@ class ActiveHost { ...@@ -86,6 +105,8 @@ class ActiveHost {
TetherHostFetcher* tether_host_fetcher_; TetherHostFetcher* tether_host_fetcher_;
PrefService* pref_service_; PrefService* pref_service_;
base::ObserverList<Observer> observer_list_;
base::WeakPtrFactory<ActiveHost> weak_ptr_factory_; base::WeakPtrFactory<ActiveHost> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ActiveHost); DISALLOW_COPY_AND_ASSIGN(ActiveHost);
......
...@@ -40,6 +40,24 @@ struct GetActiveHostResult { ...@@ -40,6 +40,24 @@ struct GetActiveHostResult {
} }
}; };
class TestObserver : public ActiveHost::Observer {
public:
void OnActiveHostChanged(
ActiveHost::ActiveHostStatus active_host_status,
std::unique_ptr<cryptauth::RemoteDevice> active_host_device,
const std::string& wifi_network_id) override {
host_changed_updates_.push_back(GetActiveHostResult{
active_host_status, std::move(active_host_device), wifi_network_id});
}
std::vector<GetActiveHostResult>& host_changed_updates() {
return host_changed_updates_;
}
private:
std::vector<GetActiveHostResult> host_changed_updates_;
};
} // namespace } // namespace
class ActiveHostTest : public testing::Test { class ActiveHostTest : public testing::Test {
...@@ -56,6 +74,9 @@ class ActiveHostTest : public testing::Test { ...@@ -56,6 +74,9 @@ class ActiveHostTest : public testing::Test {
ActiveHost::RegisterPrefs(test_pref_service_->registry()); ActiveHost::RegisterPrefs(test_pref_service_->registry());
active_host_ = base::MakeUnique<ActiveHost>(fake_tether_host_fetcher_.get(), active_host_ = base::MakeUnique<ActiveHost>(fake_tether_host_fetcher_.get(),
test_pref_service_.get()); test_pref_service_.get());
test_observer_ = base::WrapUnique(new TestObserver);
active_host_->AddObserver(test_observer_.get());
} }
void OnActiveHostFetched(ActiveHost::ActiveHostStatus active_host_status, void OnActiveHostFetched(ActiveHost::ActiveHostStatus active_host_status,
...@@ -84,6 +105,7 @@ class ActiveHostTest : public testing::Test { ...@@ -84,6 +105,7 @@ class ActiveHostTest : public testing::Test {
std::unique_ptr<TestingPrefServiceSimple> test_pref_service_; std::unique_ptr<TestingPrefServiceSimple> test_pref_service_;
std::unique_ptr<FakeTetherHostFetcher> fake_tether_host_fetcher_; std::unique_ptr<FakeTetherHostFetcher> fake_tether_host_fetcher_;
std::unique_ptr<TestObserver> test_observer_;
std::vector<GetActiveHostResult> get_active_host_results_; std::vector<GetActiveHostResult> get_active_host_results_;
...@@ -172,6 +194,48 @@ TEST_F(ActiveHostTest, TestActiveHostChangesDuringFetch) { ...@@ -172,6 +194,48 @@ TEST_F(ActiveHostTest, TestActiveHostChangesDuringFetch) {
get_active_host_results_[0]); get_active_host_results_[0]);
} }
TEST_F(ActiveHostTest, TestObserverCalls) {
// Start as DISCONNECTED.
EXPECT_FALSE(test_observer_->host_changed_updates().size());
// Go to DISCONNECTED again. This should not cause an observer callback to be
// invoked.
active_host_->SetActiveHostDisconnected();
fake_tether_host_fetcher_->InvokePendingCallbacks();
EXPECT_FALSE(test_observer_->host_changed_updates().size());
// Transition to CONNECTING.
active_host_->SetActiveHostConnecting(test_devices_[0].GetDeviceId());
fake_tether_host_fetcher_->InvokePendingCallbacks();
EXPECT_EQ(1u, test_observer_->host_changed_updates().size());
EXPECT_EQ(
(GetActiveHostResult{ActiveHost::ActiveHostStatus::CONNECTING,
std::shared_ptr<cryptauth::RemoteDevice>(
new cryptauth::RemoteDevice(test_devices_[0])),
""}),
test_observer_->host_changed_updates()[0]);
// Transition to CONNECTED.
active_host_->SetActiveHostConnected(test_devices_[0].GetDeviceId(),
"wifiNetworkId");
fake_tether_host_fetcher_->InvokePendingCallbacks();
EXPECT_EQ(2u, test_observer_->host_changed_updates().size());
EXPECT_EQ(
(GetActiveHostResult{ActiveHost::ActiveHostStatus::CONNECTED,
std::shared_ptr<cryptauth::RemoteDevice>(
new cryptauth::RemoteDevice(test_devices_[0])),
"wifiNetworkId"}),
test_observer_->host_changed_updates()[1]);
// Transition to DISCONNECTED.
active_host_->SetActiveHostDisconnected();
fake_tether_host_fetcher_->InvokePendingCallbacks();
EXPECT_EQ(3u, test_observer_->host_changed_updates().size());
EXPECT_EQ((GetActiveHostResult{ActiveHost::ActiveHostStatus::DISCONNECTED,
nullptr, ""}),
test_observer_->host_changed_updates()[2]);
}
} // namespace tether } // namespace tether
} // namespace cryptauth } // namespace cryptauth
// Copyright 2017 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 "chromeos/components/tether/fake_active_host.h"
#include "base/base64.h"
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "components/cryptauth/remote_device.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace tether {
FakeActiveHost::FakeActiveHost()
: ActiveHost(nullptr, nullptr),
active_host_status_(ActiveHost::ActiveHostStatus::DISCONNECTED),
active_host_device_id_(std::string()),
wifi_network_id_(std::string()) {}
FakeActiveHost::~FakeActiveHost() {}
void FakeActiveHost::SetActiveHostDisconnected() {
SetActiveHost(ActiveHost::ActiveHostStatus::DISCONNECTED, "", "");
}
void FakeActiveHost::SetActiveHostConnecting(
const std::string& active_host_device_id) {
SetActiveHost(ActiveHost::ActiveHostStatus::CONNECTING, active_host_device_id,
"");
}
void FakeActiveHost::SetActiveHostConnected(
const std::string& active_host_device_id,
const std::string& wifi_network_id) {
SetActiveHost(ActiveHost::ActiveHostStatus::CONNECTED, active_host_device_id,
wifi_network_id);
}
void FakeActiveHost::GetActiveHost(
const ActiveHost::ActiveHostCallback& active_host_callback) {
std::unique_ptr<cryptauth::RemoteDevice> remote_device;
if (GetActiveHostStatus() == ActiveHost::ActiveHostStatus::DISCONNECTED) {
remote_device = nullptr;
} else {
// Convert the active host ID to a public key.
std::string public_key;
ASSERT_TRUE(base::Base64Decode(GetActiveHostDeviceId(), &public_key));
// Create a new RemoteDevice and set its public key.
remote_device = base::MakeUnique<cryptauth::RemoteDevice>();
remote_device->public_key = public_key;
}
active_host_callback.Run(GetActiveHostStatus(), std::move(remote_device),
GetWifiNetworkId());
}
ActiveHost::ActiveHostStatus FakeActiveHost::GetActiveHostStatus() const {
return active_host_status_;
}
std::string FakeActiveHost::GetActiveHostDeviceId() const {
return active_host_device_id_;
}
std::string FakeActiveHost::GetWifiNetworkId() const {
return wifi_network_id_;
}
void FakeActiveHost::SetActiveHost(ActiveHostStatus active_host_status,
const std::string& active_host_device_id,
const std::string& wifi_network_id) {
bool status_changed = GetActiveHostStatus() != active_host_status;
bool device_changed = GetActiveHostDeviceId() != active_host_device_id;
bool network_id_changed = GetWifiNetworkId() != wifi_network_id;
if (!status_changed && !device_changed && !network_id_changed) {
// If nothing has changed, return early.
return;
}
active_host_status_ = active_host_status;
active_host_device_id_ = active_host_device_id;
wifi_network_id_ = wifi_network_id;
GetActiveHost(base::Bind(&FakeActiveHost::SendActiveHostChangedUpdate,
base::Unretained(this)));
}
} // namespace tether
} // namespace chromeos
// Copyright 2017 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 CHROMEOS_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
#define CHROMEOS_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chromeos/components/tether/active_host.h"
namespace chromeos {
namespace tether {
// Test double for ActiveHost.
class FakeActiveHost : public ActiveHost {
public:
FakeActiveHost();
~FakeActiveHost() override;
// ActiveHost:
void SetActiveHostDisconnected() override;
void SetActiveHostConnecting(
const std::string& active_host_device_id) override;
void SetActiveHostConnected(const std::string& active_host_device_id,
const std::string& wifi_network_id) override;
void GetActiveHost(
const ActiveHost::ActiveHostCallback& active_host_callback) override;
ActiveHostStatus GetActiveHostStatus() const override;
std::string GetActiveHostDeviceId() const override;
std::string GetWifiNetworkId() const override;
private:
void SetActiveHost(ActiveHostStatus active_host_status,
const std::string& active_host_device_id,
const std::string& wifi_network_id);
ActiveHost::ActiveHostStatus active_host_status_;
std::string active_host_device_id_;
std::string wifi_network_id_;
DISALLOW_COPY_AND_ASSIGN(FakeActiveHost);
};
} // namespace tether
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_TETHER_FAKE_ACTIVE_HOST_H_
...@@ -48,12 +48,27 @@ KeepAliveOperation::KeepAliveOperation( ...@@ -48,12 +48,27 @@ KeepAliveOperation::KeepAliveOperation(
KeepAliveOperation::~KeepAliveOperation() {} KeepAliveOperation::~KeepAliveOperation() {}
void KeepAliveOperation::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void KeepAliveOperation::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void KeepAliveOperation::OnDeviceAuthenticated( void KeepAliveOperation::OnDeviceAuthenticated(
const cryptauth::RemoteDevice& remote_device) { const cryptauth::RemoteDevice& remote_device) {
DCHECK(remote_devices().size() == 1u && remote_devices()[0] == remote_device); DCHECK(remote_devices().size() == 1u && remote_devices()[0] == remote_device);
SendMessageToDevice(remote_device, SendMessageToDevice(remote_device,
base::MakeUnique<MessageWrapper>(KeepAliveTickle())); base::MakeUnique<MessageWrapper>(KeepAliveTickle()));
UnregisterDevice(remote_device);
}
void KeepAliveOperation::OnOperationFinished() {
for (auto& observer : observer_list_) {
observer.OnOperationFinished();
}
} }
MessageType KeepAliveOperation::GetMessageTypeForConnection() { MessageType KeepAliveOperation::GetMessageTypeForConnection() {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROMEOS_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_ #ifndef CHROMEOS_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
#define CHROMEOS_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_ #define CHROMEOS_COMPONENTS_TETHER_KEEP_ALIVE_OPERATION_H_
#include "base/observer_list.h"
#include "chromeos/components/tether/message_transfer_operation.h" #include "chromeos/components/tether/message_transfer_operation.h"
namespace chromeos { namespace chromeos {
...@@ -14,9 +15,8 @@ namespace tether { ...@@ -14,9 +15,8 @@ namespace tether {
class BleConnectionManager; class BleConnectionManager;
// Operation which sends a keep-alive message to a tether host. // Operation which sends a keep-alive message to a tether host.
// TODO(khorimoto/hansberry): Consider changing protocol to receive a // TODO(khorimoto/hansberry): Change protocol to receive a DeviceStatus update
// DeviceStatus update after sending the // after sending the KeepAliveTickle message.
// KeepAliveTickle message.
class KeepAliveOperation : public MessageTransferOperation { class KeepAliveOperation : public MessageTransferOperation {
public: public:
class Factory { class Factory {
...@@ -29,13 +29,20 @@ class KeepAliveOperation : public MessageTransferOperation { ...@@ -29,13 +29,20 @@ class KeepAliveOperation : public MessageTransferOperation {
protected: protected:
virtual std::unique_ptr<KeepAliveOperation> BuildInstance( virtual std::unique_ptr<KeepAliveOperation> BuildInstance(
const cryptauth::RemoteDevice& devices_to_connect, const cryptauth::RemoteDevice& device_to_connect,
BleConnectionManager* connection_manager); BleConnectionManager* connection_manager);
private: private:
static Factory* factory_instance_; static Factory* factory_instance_;
}; };
class Observer {
public:
// TODO(khorimoto): This function should take a DeviceStatus once there is
// keep-alive tickle response.
virtual void OnOperationFinished() = 0;
};
KeepAliveOperation(const cryptauth::RemoteDevice& device_to_connect, KeepAliveOperation(const cryptauth::RemoteDevice& device_to_connect,
BleConnectionManager* connection_manager); BleConnectionManager* connection_manager);
~KeepAliveOperation() override; ~KeepAliveOperation() override;
...@@ -47,11 +54,15 @@ class KeepAliveOperation : public MessageTransferOperation { ...@@ -47,11 +54,15 @@ class KeepAliveOperation : public MessageTransferOperation {
// MessageTransferOperation: // MessageTransferOperation:
void OnDeviceAuthenticated( void OnDeviceAuthenticated(
const cryptauth::RemoteDevice& remote_device) override; const cryptauth::RemoteDevice& remote_device) override;
void OnOperationFinished() override;
MessageType GetMessageTypeForConnection() override; MessageType GetMessageTypeForConnection() override;
private: private:
friend class KeepAliveOperationTest; friend class KeepAliveOperationTest;
base::ObserverList<Observer> observer_list_;
bool has_authenticated_;
DISALLOW_COPY_AND_ASSIGN(KeepAliveOperation); DISALLOW_COPY_AND_ASSIGN(KeepAliveOperation);
}; };
......
...@@ -19,6 +19,20 @@ namespace tether { ...@@ -19,6 +19,20 @@ namespace tether {
namespace { namespace {
class TestObserver : public KeepAliveOperation::Observer {
public:
TestObserver() : has_run_callback_(false) {}
virtual ~TestObserver() {}
bool has_run_callback() { return has_run_callback_; }
void OnOperationFinished() override { has_run_callback_ = true; }
private:
bool has_run_callback_;
};
std::string CreateKeepAliveTickleString() { std::string CreateKeepAliveTickleString() {
KeepAliveTickle tickle; KeepAliveTickle tickle;
return MessageWrapper(tickle).ToRawMessage(); return MessageWrapper(tickle).ToRawMessage();
...@@ -37,6 +51,10 @@ class KeepAliveOperationTest : public testing::Test { ...@@ -37,6 +51,10 @@ class KeepAliveOperationTest : public testing::Test {
operation_ = base::WrapUnique(new KeepAliveOperation( operation_ = base::WrapUnique(new KeepAliveOperation(
test_device_, fake_ble_connection_manager_.get())); test_device_, fake_ble_connection_manager_.get()));
test_observer_ = base::WrapUnique(new TestObserver());
operation_->AddObserver(test_observer_.get());
operation_->Initialize(); operation_->Initialize();
} }
...@@ -55,6 +73,8 @@ class KeepAliveOperationTest : public testing::Test { ...@@ -55,6 +73,8 @@ class KeepAliveOperationTest : public testing::Test {
const cryptauth::RemoteDevice test_device_; const cryptauth::RemoteDevice test_device_;
std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_; std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
std::unique_ptr<TestObserver> test_observer_;
std::unique_ptr<KeepAliveOperation> operation_; std::unique_ptr<KeepAliveOperation> operation_;
private: private:
...@@ -62,7 +82,9 @@ class KeepAliveOperationTest : public testing::Test { ...@@ -62,7 +82,9 @@ class KeepAliveOperationTest : public testing::Test {
}; };
TEST_F(KeepAliveOperationTest, TestSendsKeepAliveTickle) { TEST_F(KeepAliveOperationTest, TestSendsKeepAliveTickle) {
EXPECT_FALSE(test_observer_->has_run_callback());
SimulateDeviceAuthenticationAndVerifyMessageSent(); SimulateDeviceAuthenticationAndVerifyMessageSent();
EXPECT_TRUE(test_observer_->has_run_callback());
} }
} // namespace tether } // namespace tether
......
// Copyright 2017 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 "chromeos/components/tether/keep_alive_scheduler.h"
#include "base/bind.h"
namespace chromeos {
namespace tether {
// static
const uint32_t KeepAliveScheduler::kKeepAliveIntervalMinutes = 4;
KeepAliveScheduler::KeepAliveScheduler(ActiveHost* active_host,
BleConnectionManager* connection_manager)
: KeepAliveScheduler(active_host,
connection_manager,
base::MakeUnique<base::RepeatingTimer>()) {}
KeepAliveScheduler::KeepAliveScheduler(ActiveHost* active_host,
BleConnectionManager* connection_manager,
std::unique_ptr<base::Timer> timer)
: active_host_(active_host),
connection_manager_(connection_manager),
timer_(std::move(timer)),
weak_ptr_factory_(this) {
active_host_->AddObserver(this);
}
KeepAliveScheduler::~KeepAliveScheduler() {
active_host_->RemoveObserver(this);
}
void KeepAliveScheduler::OnActiveHostChanged(
ActiveHost::ActiveHostStatus active_host_status,
std::unique_ptr<cryptauth::RemoteDevice> active_host_device,
const std::string& wifi_network_id) {
if (active_host_status == ActiveHost::ActiveHostStatus::DISCONNECTED) {
DCHECK(!active_host_device);
DCHECK(wifi_network_id.empty());
keep_alive_operation_.reset();
active_host_device_.reset();
timer_->Stop();
return;
}
if (active_host_status == ActiveHost::ActiveHostStatus::CONNECTED) {
DCHECK(active_host_device);
active_host_device_ = std::move(active_host_device);
timer_->Start(FROM_HERE,
base::TimeDelta::FromMinutes(kKeepAliveIntervalMinutes),
base::Bind(&KeepAliveScheduler::SendKeepAliveTickle,
weak_ptr_factory_.GetWeakPtr()));
SendKeepAliveTickle();
}
}
void KeepAliveScheduler::OnOperationFinished() {
keep_alive_operation_->RemoveObserver(this);
keep_alive_operation_.reset();
}
void KeepAliveScheduler::SendKeepAliveTickle() {
DCHECK(active_host_device_);
keep_alive_operation_ = KeepAliveOperation::Factory::NewInstance(
*active_host_device_, connection_manager_);
keep_alive_operation_->AddObserver(this);
keep_alive_operation_->Initialize();
}
} // namespace tether
} // namespace chromeos
// Copyright 2017 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 CHROMEOS_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
#define CHROMEOS_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "chromeos/components/tether/active_host.h"
#include "chromeos/components/tether/keep_alive_operation.h"
namespace chromeos {
namespace tether {
// Schedules keep-alive messages to be sent when this device is connected to a
// remote device's tether hotspot. When a device connects, a keep-alive message
// is sent immediately, then another one is scheduled every 4 minutes until the
// device disconnects.
class KeepAliveScheduler : public ActiveHost::Observer,
public KeepAliveOperation::Observer {
public:
KeepAliveScheduler(ActiveHost* active_host,
BleConnectionManager* connection_manager);
virtual ~KeepAliveScheduler();
// ActiveHost::Observer:
void OnActiveHostChanged(ActiveHost::ActiveHostStatus active_host_status,
std::unique_ptr<cryptauth::RemoteDevice> active_host,
const std::string& wifi_network_id) override;
// KeepAliveOperation::Observer:
void OnOperationFinished() override;
private:
friend class KeepAliveSchedulerTest;
KeepAliveScheduler(ActiveHost* active_host,
BleConnectionManager* connection_manager,
std::unique_ptr<base::Timer> timer);
void SendKeepAliveTickle();
static const uint32_t kKeepAliveIntervalMinutes;
ActiveHost* active_host_;
BleConnectionManager* connection_manager_;
std::unique_ptr<base::Timer> timer_;
std::unique_ptr<cryptauth::RemoteDevice> active_host_device_;
std::unique_ptr<KeepAliveOperation> keep_alive_operation_;
base::WeakPtrFactory<KeepAliveScheduler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(KeepAliveScheduler);
};
} // namespace tether
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_TETHER_KEEP_ALIVE_SCHEDULER_H_
// Copyright 2017 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 "chromeos/components/tether/keep_alive_scheduler.h"
#include <memory>
#include <vector>
#include "base/timer/mock_timer.h"
#include "chromeos/components/tether/fake_active_host.h"
#include "chromeos/components/tether/fake_ble_connection_manager.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace tether {
namespace {
const char kWifiNetworkId[] = "wifiNetworkId";
class OperationDeletedHandler {
public:
virtual void OnOperationDeleted() = 0;
};
class FakeKeepAliveOperation : public KeepAliveOperation {
public:
FakeKeepAliveOperation(const cryptauth::RemoteDevice& device_to_connect,
BleConnectionManager* connection_manager,
OperationDeletedHandler* handler)
: KeepAliveOperation(device_to_connect, connection_manager),
handler_(handler),
remote_device_(device_to_connect) {}
~FakeKeepAliveOperation() override { handler_->OnOperationDeleted(); }
void SendOperationFinishedEvent() { OnOperationFinished(); }
cryptauth::RemoteDevice remote_device() { return remote_device_; }
private:
OperationDeletedHandler* handler_;
const cryptauth::RemoteDevice remote_device_;
};
class FakeKeepAliveOperationFactory : public KeepAliveOperation::Factory,
public OperationDeletedHandler {
public:
FakeKeepAliveOperationFactory()
: num_created_(0), num_deleted_(0), last_created_(nullptr) {}
~FakeKeepAliveOperationFactory() {}
uint32_t num_created() { return num_created_; }
uint32_t num_deleted() { return num_deleted_; }
FakeKeepAliveOperation* last_created() { return last_created_; }
void OnOperationDeleted() override { num_deleted_++; }
protected:
std::unique_ptr<KeepAliveOperation> BuildInstance(
const cryptauth::RemoteDevice& device_to_connect,
BleConnectionManager* connection_manager) override {
num_created_++;
last_created_ =
new FakeKeepAliveOperation(device_to_connect, connection_manager, this);
return base::WrapUnique(last_created_);
}
private:
uint32_t num_created_;
uint32_t num_deleted_;
FakeKeepAliveOperation* last_created_;
};
} // namespace
class KeepAliveSchedulerTest : public testing::Test {
protected:
KeepAliveSchedulerTest()
: test_devices_(cryptauth::GenerateTestRemoteDevices(2)) {}
void SetUp() override {
fake_active_host_ = base::MakeUnique<FakeActiveHost>();
fake_ble_connection_manager_ = base::MakeUnique<FakeBleConnectionManager>();
mock_timer_ = new base::MockTimer(true /* retain_user_task */,
true /* is_repeating */);
fake_operation_factory_ =
base::WrapUnique(new FakeKeepAliveOperationFactory());
KeepAliveOperation::Factory::SetInstanceForTesting(
fake_operation_factory_.get());
scheduler_ = base::WrapUnique(new KeepAliveScheduler(
fake_active_host_.get(), fake_ble_connection_manager_.get(),
base::WrapUnique(mock_timer_)));
}
void VerifyTimerRunning(bool is_running) {
EXPECT_EQ(is_running, mock_timer_->IsRunning());
if (is_running) {
EXPECT_EQ(base::TimeDelta::FromMinutes(
KeepAliveScheduler::kKeepAliveIntervalMinutes),
mock_timer_->GetCurrentDelay());
}
}
const std::vector<cryptauth::RemoteDevice> test_devices_;
std::unique_ptr<FakeActiveHost> fake_active_host_;
std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
base::MockTimer* mock_timer_;
std::unique_ptr<FakeKeepAliveOperationFactory> fake_operation_factory_;
std::unique_ptr<KeepAliveScheduler> scheduler_;
private:
DISALLOW_COPY_AND_ASSIGN(KeepAliveSchedulerTest);
};
TEST_F(KeepAliveSchedulerTest, TestSendTickle_OneActiveHost) {
EXPECT_FALSE(fake_operation_factory_->num_created());
EXPECT_FALSE(fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
// Start connecting to a device. No operation should be started.
fake_active_host_->SetActiveHostConnecting(test_devices_[0].GetDeviceId());
EXPECT_FALSE(fake_operation_factory_->num_created());
EXPECT_FALSE(fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
// Connect to the device; the operation should be started.
fake_active_host_->SetActiveHostConnected(test_devices_[0].GetDeviceId(),
std::string(kWifiNetworkId));
EXPECT_EQ(1u, fake_operation_factory_->num_created());
EXPECT_EQ(test_devices_[0],
fake_operation_factory_->last_created()->remote_device());
EXPECT_FALSE(fake_operation_factory_->num_deleted());
VerifyTimerRunning(true /* is_running */);
// Ensure that once the operation is finished, it is deleted.
fake_operation_factory_->last_created()->SendOperationFinishedEvent();
EXPECT_EQ(1u, fake_operation_factory_->num_created());
EXPECT_EQ(1u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(true /* is_running */);
// Fire the timer; this should result in another tickle being sent.
mock_timer_->Fire();
EXPECT_EQ(2u, fake_operation_factory_->num_created());
EXPECT_EQ(test_devices_[0],
fake_operation_factory_->last_created()->remote_device());
EXPECT_EQ(1u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(true /* is_running */);
// Finish this operation.
fake_operation_factory_->last_created()->SendOperationFinishedEvent();
EXPECT_EQ(2u, fake_operation_factory_->num_created());
EXPECT_EQ(2u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(true /* is_running */);
// Disconnect that device.
fake_active_host_->SetActiveHostDisconnected();
EXPECT_EQ(2u, fake_operation_factory_->num_created());
EXPECT_EQ(2u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
}
TEST_F(KeepAliveSchedulerTest, TestSendTickle_MultipleActiveHosts) {
EXPECT_FALSE(fake_operation_factory_->num_created());
EXPECT_FALSE(fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
// Start connecting to a device. No operation should be started.
fake_active_host_->SetActiveHostConnecting(test_devices_[0].GetDeviceId());
EXPECT_FALSE(fake_operation_factory_->num_created());
EXPECT_FALSE(fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
// Connect to the device; the operation should be started.
fake_active_host_->SetActiveHostConnected(test_devices_[0].GetDeviceId(),
std::string(kWifiNetworkId));
EXPECT_EQ(1u, fake_operation_factory_->num_created());
EXPECT_EQ(test_devices_[0],
fake_operation_factory_->last_created()->remote_device());
EXPECT_FALSE(fake_operation_factory_->num_deleted());
VerifyTimerRunning(true /* is_running */);
// Disconnect that device before the operation is finished. It should still be
// deleted.
fake_active_host_->SetActiveHostDisconnected();
EXPECT_EQ(1u, fake_operation_factory_->num_created());
EXPECT_EQ(1u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
// Start connecting to a different. No operation should be started.
fake_active_host_->SetActiveHostConnecting(test_devices_[1].GetDeviceId());
EXPECT_EQ(1u, fake_operation_factory_->num_created());
EXPECT_EQ(1u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
// Connect to the second device; the operation should be started.
fake_active_host_->SetActiveHostConnected(test_devices_[1].GetDeviceId(),
std::string(kWifiNetworkId));
EXPECT_EQ(2u, fake_operation_factory_->num_created());
EXPECT_EQ(test_devices_[1],
fake_operation_factory_->last_created()->remote_device());
EXPECT_EQ(1u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(true /* is_running */);
// Ensure that once the second operation is finished, it is deleted.
fake_operation_factory_->last_created()->SendOperationFinishedEvent();
EXPECT_EQ(2u, fake_operation_factory_->num_created());
EXPECT_EQ(2u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(true /* is_running */);
// Disconnect that device.
fake_active_host_->SetActiveHostDisconnected();
EXPECT_EQ(2u, fake_operation_factory_->num_created());
EXPECT_EQ(2u, fake_operation_factory_->num_deleted());
VerifyTimerRunning(false /* is_running */);
}
} // namespace tether
} // namespace cryptauth
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