Commit 9391ece9 authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS PhoneHub] Add cleanup timeout for Nearby process

Allowing a short timeout before shutting down the process works around
race conditions that occur during shutdown, allowing the Nearby utility
process to shut down without any errors.

Bug: 1152609
Change-Id: I56124135cbd67a3256bc37a384ec55f40f583869
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2561541
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarJames Vecore <vecore@google.com>
Cr-Commit-Position: refs/heads/master@{#831181}
parent e29c70f6
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/nearby/nearby_connections_dependencies_provider.h" #include "chrome/browser/chromeos/nearby/nearby_connections_dependencies_provider.h"
#include "chrome/browser/nearby_sharing/logging/logging.h" #include "chrome/browser/nearby_sharing/logging/logging.h"
#include "chrome/browser/sharing/webrtc/sharing_mojo_service.h" #include "chrome/browser/sharing/webrtc/sharing_mojo_service.h"
...@@ -17,6 +18,9 @@ namespace { ...@@ -17,6 +18,9 @@ namespace {
NearbyProcessManagerImpl::Factory* g_test_factory = nullptr; NearbyProcessManagerImpl::Factory* g_test_factory = nullptr;
constexpr base::TimeDelta kProcessCleanupTimeout =
base::TimeDelta::FromSeconds(5);
void OnSharingShutDownComplete( void OnSharingShutDownComplete(
mojo::Remote<sharing::mojom::Sharing> sharing, mojo::Remote<sharing::mojom::Sharing> sharing,
mojo::SharedRemote<location::nearby::connections::mojom::NearbyConnections> mojo::SharedRemote<location::nearby::connections::mojom::NearbyConnections>
...@@ -31,14 +35,15 @@ void OnSharingShutDownComplete( ...@@ -31,14 +35,15 @@ void OnSharingShutDownComplete(
// static // static
std::unique_ptr<NearbyProcessManager> NearbyProcessManagerImpl::Factory::Create( std::unique_ptr<NearbyProcessManager> NearbyProcessManagerImpl::Factory::Create(
NearbyConnectionsDependenciesProvider* NearbyConnectionsDependenciesProvider*
nearby_connections_dependencies_provider) { nearby_connections_dependencies_provider,
std::unique_ptr<base::OneShotTimer> timer) {
if (g_test_factory) { if (g_test_factory) {
return g_test_factory->BuildInstance( return g_test_factory->BuildInstance(
nearby_connections_dependencies_provider); nearby_connections_dependencies_provider, std::move(timer));
} }
return base::WrapUnique(new NearbyProcessManagerImpl( return base::WrapUnique(new NearbyProcessManagerImpl(
nearby_connections_dependencies_provider, nearby_connections_dependencies_provider, std::move(timer),
base::BindRepeating(&sharing::LaunchSharing))); base::BindRepeating(&sharing::LaunchSharing)));
} }
...@@ -80,10 +85,12 @@ NearbyProcessManagerImpl::NearbyReferenceImpl::GetNearbySharingDecoder() const { ...@@ -80,10 +85,12 @@ NearbyProcessManagerImpl::NearbyReferenceImpl::GetNearbySharingDecoder() const {
NearbyProcessManagerImpl::NearbyProcessManagerImpl( NearbyProcessManagerImpl::NearbyProcessManagerImpl(
NearbyConnectionsDependenciesProvider* NearbyConnectionsDependenciesProvider*
nearby_connections_dependencies_provider, nearby_connections_dependencies_provider,
std::unique_ptr<base::OneShotTimer> timer,
const base::RepeatingCallback< const base::RepeatingCallback<
mojo::PendingRemote<sharing::mojom::Sharing>()>& sharing_binder) mojo::PendingRemote<sharing::mojom::Sharing>()>& sharing_binder)
: nearby_connections_dependencies_provider_( : nearby_connections_dependencies_provider_(
nearby_connections_dependencies_provider), nearby_connections_dependencies_provider),
shutdown_debounce_timer_(std::move(timer)),
sharing_binder_(sharing_binder) {} sharing_binder_(sharing_binder) {}
NearbyProcessManagerImpl::~NearbyProcessManagerImpl() = default; NearbyProcessManagerImpl::~NearbyProcessManagerImpl() = default;
...@@ -103,10 +110,16 @@ NearbyProcessManagerImpl::GetNearbyProcessReference( ...@@ -103,10 +110,16 @@ NearbyProcessManagerImpl::GetNearbyProcessReference(
} }
} }
NS_LOG(VERBOSE) << "New Nearby process reference requested.";
auto reference_id = base::UnguessableToken::Create(); auto reference_id = base::UnguessableToken::Create();
id_to_process_stopped_callback_map_.emplace( id_to_process_stopped_callback_map_.emplace(
reference_id, std::move(on_process_stopped_callback)); reference_id, std::move(on_process_stopped_callback));
// If we were waiting to shut down the process but a new client was added,
// stop the timer since the process needs to be kept alive for this new
// client.
shutdown_debounce_timer_->Stop();
return std::make_unique<NearbyReferenceImpl>( return std::make_unique<NearbyReferenceImpl>(
connections_, decoder_, connections_, decoder_,
base::BindOnce(&NearbyProcessManagerImpl::OnReferenceDeleted, base::BindOnce(&NearbyProcessManagerImpl::OnReferenceDeleted,
...@@ -195,10 +208,24 @@ void NearbyProcessManagerImpl::OnReferenceDeleted( ...@@ -195,10 +208,24 @@ void NearbyProcessManagerImpl::OnReferenceDeleted(
if (!id_to_process_stopped_callback_map_.empty()) if (!id_to_process_stopped_callback_map_.empty())
return; return;
ShutDownProcess(); NS_LOG(VERBOSE) << "All Nearby references have been released; will shut down "
<< "process in " << kProcessCleanupTimeout << " unless a new "
<< "reference is obtained.";
// Stop the process, but wait |kProcessCleanupTimeout| before doing so. Adding
// this additional timeout works around issues during Nearby shutdown
// (see https://crbug.com/1152609).
// TODO(https://crbug.com/1152892): Remove this timeout.
shutdown_debounce_timer_->Start(
FROM_HERE, kProcessCleanupTimeout,
base::BindOnce(&NearbyProcessManagerImpl::ShutDownProcess,
weak_ptr_factory_.GetWeakPtr()));
} }
void NearbyProcessManagerImpl::ShutDownProcess() { void NearbyProcessManagerImpl::ShutDownProcess() {
// Ensure that we don't try to stop the process again.
shutdown_debounce_timer_->Stop();
NS_LOG(INFO) << "Shutting down Nearby utility process."; NS_LOG(INFO) << "Shutting down Nearby utility process.";
// Ensure that any in-progress CreateNearbyConnections() or // Ensure that any in-progress CreateNearbyConnections() or
......
...@@ -5,9 +5,12 @@ ...@@ -5,9 +5,12 @@
#ifndef CHROME_BROWSER_CHROMEOS_NEARBY_NEARBY_PROCESS_MANAGER_IMPL_H_ #ifndef CHROME_BROWSER_CHROMEOS_NEARBY_NEARBY_PROCESS_MANAGER_IMPL_H_
#define CHROME_BROWSER_CHROMEOS_NEARBY_NEARBY_PROCESS_MANAGER_IMPL_H_ #define CHROME_BROWSER_CHROMEOS_NEARBY_NEARBY_PROCESS_MANAGER_IMPL_H_
#include <memory>
#include "base/callback.h" #include "base/callback.h"
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "chromeos/services/nearby/public/cpp/nearby_process_manager.h" #include "chromeos/services/nearby/public/cpp/nearby_process_manager.h"
#include "mojo/public/cpp/bindings/shared_remote.h" #include "mojo/public/cpp/bindings/shared_remote.h"
...@@ -32,14 +35,17 @@ class NearbyProcessManagerImpl : public NearbyProcessManager { ...@@ -32,14 +35,17 @@ class NearbyProcessManagerImpl : public NearbyProcessManager {
public: public:
static std::unique_ptr<NearbyProcessManager> Create( static std::unique_ptr<NearbyProcessManager> Create(
NearbyConnectionsDependenciesProvider* NearbyConnectionsDependenciesProvider*
nearby_connections_dependencies_provider); nearby_connections_dependencies_provider,
std::unique_ptr<base::OneShotTimer> timer =
std::make_unique<base::OneShotTimer>());
static void SetFactoryForTesting(Factory* factory); static void SetFactoryForTesting(Factory* factory);
virtual ~Factory() = default; virtual ~Factory() = default;
private: private:
virtual std::unique_ptr<NearbyProcessManager> BuildInstance( virtual std::unique_ptr<NearbyProcessManager> BuildInstance(
NearbyConnectionsDependenciesProvider* NearbyConnectionsDependenciesProvider*
nearby_connections_dependencies_provider) = 0; nearby_connections_dependencies_provider,
std::unique_ptr<base::OneShotTimer> timer) = 0;
}; };
~NearbyProcessManagerImpl() override; ~NearbyProcessManagerImpl() override;
...@@ -75,6 +81,7 @@ class NearbyProcessManagerImpl : public NearbyProcessManager { ...@@ -75,6 +81,7 @@ class NearbyProcessManagerImpl : public NearbyProcessManager {
NearbyProcessManagerImpl( NearbyProcessManagerImpl(
NearbyConnectionsDependenciesProvider* NearbyConnectionsDependenciesProvider*
nearby_connections_dependencies_provider, nearby_connections_dependencies_provider,
std::unique_ptr<base::OneShotTimer> timer,
const base::RepeatingCallback< const base::RepeatingCallback<
mojo::PendingRemote<sharing::mojom::Sharing>()>& sharing_binder); mojo::PendingRemote<sharing::mojom::Sharing>()>& sharing_binder);
...@@ -94,6 +101,7 @@ class NearbyProcessManagerImpl : public NearbyProcessManager { ...@@ -94,6 +101,7 @@ class NearbyProcessManagerImpl : public NearbyProcessManager {
NearbyConnectionsDependenciesProvider* NearbyConnectionsDependenciesProvider*
nearby_connections_dependencies_provider_; nearby_connections_dependencies_provider_;
std::unique_ptr<base::OneShotTimer> shutdown_debounce_timer_;
base::RepeatingCallback<mojo::PendingRemote<sharing::mojom::Sharing>()> base::RepeatingCallback<mojo::PendingRemote<sharing::mojom::Sharing>()>
sharing_binder_; sharing_binder_;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h" #include "base/test/bind.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/timer/mock_timer.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/nearby/nearby_connections_dependencies_provider.h" #include "chrome/browser/chromeos/nearby/nearby_connections_dependencies_provider.h"
#include "chrome/browser/chromeos/nearby/nearby_process_manager_factory.h" #include "chrome/browser/chromeos/nearby/nearby_process_manager_factory.h"
...@@ -130,8 +131,11 @@ class NearbyProcessManagerImplTest : public testing::Test { ...@@ -130,8 +131,11 @@ class NearbyProcessManagerImplTest : public testing::Test {
// testing::Test: // testing::Test:
void SetUp() override { void SetUp() override {
auto mock_timer = std::make_unique<base::MockOneShotTimer>();
mock_timer_ = mock_timer.get();
nearby_process_manager_ = base::WrapUnique(new NearbyProcessManagerImpl( nearby_process_manager_ = base::WrapUnique(new NearbyProcessManagerImpl(
&fake_deps_provider_, &fake_deps_provider_, std::move(mock_timer),
base::BindRepeating(&FakeSharingMojoService::BindSharingService, base::BindRepeating(&FakeSharingMojoService::BindSharingService,
base::Unretained(&fake_sharing_mojo_service_)))); base::Unretained(&fake_sharing_mojo_service_))));
} }
...@@ -166,6 +170,10 @@ class NearbyProcessManagerImplTest : public testing::Test { ...@@ -166,6 +170,10 @@ class NearbyProcessManagerImplTest : public testing::Test {
EXPECT_FALSE(fake_sharing_mojo_service_.AreMocksSet()); EXPECT_FALSE(fake_sharing_mojo_service_.AreMocksSet());
} }
bool IsTimerRunning() const { return mock_timer_->IsRunning(); }
void FireTimer() { mock_timer_->Fire(); }
private: private:
NearbyProcessManagerImpl* GetImpl() { NearbyProcessManagerImpl* GetImpl() {
return static_cast<NearbyProcessManagerImpl*>( return static_cast<NearbyProcessManagerImpl*>(
...@@ -181,6 +189,8 @@ class NearbyProcessManagerImplTest : public testing::Test { ...@@ -181,6 +189,8 @@ class NearbyProcessManagerImplTest : public testing::Test {
FakeNearbyConnectionsDependenciesProvider fake_deps_provider_; FakeNearbyConnectionsDependenciesProvider fake_deps_provider_;
std::unique_ptr<NearbyProcessManager> nearby_process_manager_; std::unique_ptr<NearbyProcessManager> nearby_process_manager_;
base::MockOneShotTimer* mock_timer_ = nullptr;
}; };
TEST_F(NearbyProcessManagerImplTest, StartAndStop) { TEST_F(NearbyProcessManagerImplTest, StartAndStop) {
...@@ -189,6 +199,7 @@ TEST_F(NearbyProcessManagerImplTest, StartAndStop) { ...@@ -189,6 +199,7 @@ TEST_F(NearbyProcessManagerImplTest, StartAndStop) {
VerifyBound(reference.get()); VerifyBound(reference.get());
reference.reset(); reference.reset();
FireTimer();
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
VerifyNotBound(); VerifyNotBound();
EXPECT_EQ(0u, num_process_stopped_calls()); EXPECT_EQ(0u, num_process_stopped_calls());
...@@ -200,6 +211,7 @@ TEST_F(NearbyProcessManagerImplTest, StartAndStop) { ...@@ -200,6 +211,7 @@ TEST_F(NearbyProcessManagerImplTest, StartAndStop) {
VerifyBound(reference.get()); VerifyBound(reference.get());
reference.reset(); reference.reset();
FireTimer();
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
VerifyNotBound(); VerifyNotBound();
EXPECT_EQ(0u, num_process_stopped_calls()); EXPECT_EQ(0u, num_process_stopped_calls());
...@@ -215,10 +227,12 @@ TEST_F(NearbyProcessManagerImplTest, MultipleReferences) { ...@@ -215,10 +227,12 @@ TEST_F(NearbyProcessManagerImplTest, MultipleReferences) {
// Deleting one reference should still keep the other reference bound. // Deleting one reference should still keep the other reference bound.
reference1.reset(); reference1.reset();
EXPECT_FALSE(IsTimerRunning());
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
VerifyBound(reference2.get()); VerifyBound(reference2.get());
reference2.reset(); reference2.reset();
FireTimer();
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
VerifyNotBound(); VerifyNotBound();
EXPECT_EQ(0u, num_process_stopped_calls()); EXPECT_EQ(0u, num_process_stopped_calls());
...@@ -235,6 +249,31 @@ TEST_F(NearbyProcessManagerImplTest, ProcessStopped) { ...@@ -235,6 +249,31 @@ TEST_F(NearbyProcessManagerImplTest, ProcessStopped) {
VerifyNotBound(); VerifyNotBound();
EXPECT_EQ(1u, num_process_stopped_calls()); EXPECT_EQ(1u, num_process_stopped_calls());
EXPECT_FALSE(IsTimerRunning());
}
TEST_F(NearbyProcessManagerImplTest,
NewReferenceObtainedWhileWaitingToShutDown) {
std::unique_ptr<NearbyProcessManager::NearbyProcessReference> reference =
CreateReference();
VerifyBound(reference.get());
// Delete the reference; the timer should be running so that the process is
// shut down after the cleanup timeout.
reference.reset();
EXPECT_TRUE(IsTimerRunning());
// Obtain a new reference; the timer should have stopped.
reference = CreateReference();
VerifyBound(reference.get());
EXPECT_FALSE(IsTimerRunning());
// Delete the reference and let the timer fire to shut down the process.
reference.reset();
FireTimer();
base::RunLoop().RunUntilIdle();
VerifyNotBound();
EXPECT_EQ(0u, num_process_stopped_calls());
} }
} // namespace nearby } // namespace nearby
......
...@@ -62,7 +62,8 @@ class FakeNearbyProcessManagerFactory ...@@ -62,7 +62,8 @@ class FakeNearbyProcessManagerFactory
// chromeos::nearby::NearbyProcessManagerImpl::Factory: // chromeos::nearby::NearbyProcessManagerImpl::Factory:
std::unique_ptr<chromeos::nearby::NearbyProcessManager> BuildInstance( std::unique_ptr<chromeos::nearby::NearbyProcessManager> BuildInstance(
chromeos::nearby::NearbyConnectionsDependenciesProvider* chromeos::nearby::NearbyConnectionsDependenciesProvider*
nearby_connections_dependencies_provider) override { nearby_connections_dependencies_provider,
std::unique_ptr<base::OneShotTimer> timer) override {
auto instance = auto instance =
std::make_unique<chromeos::nearby::FakeNearbyProcessManager>(); std::make_unique<chromeos::nearby::FakeNearbyProcessManager>();
instance_ = instance.get(); instance_ = instance.get();
......
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