Commit 0c9dabff authored by nya's avatar nya Committed by Commit bot

arc: Notify ARC instance failures via callbacks.

StopReason is passed to following observer methods:
- ArcBridgeBootstrap::Observer::OnStopped
- ArcBridgeService::Observer::OnBridgeStopped

Those callbacks can now tell the reason the bridge stopped.

I am planning to use this soon to show notifications on failures.
See the bug entry for more details.

BUG=chromium:625923
TEST=components_unittests --gtest_filter=ArcBridgeTest.*
TEST=Manually verified that ARC boots.

Review-Url: https://codereview.chromium.org/2133653002
Cr-Commit-Position: refs/heads/master@{#405241}
parent 38e3bf34
...@@ -192,7 +192,8 @@ void ArcAuthService::OnInstanceReady() { ...@@ -192,7 +192,8 @@ void ArcAuthService::OnInstanceReady() {
binding_.CreateInterfacePtrAndBind()); binding_.CreateInterfacePtrAndBind());
} }
void ArcAuthService::OnBridgeStopped() { void ArcAuthService::OnBridgeStopped(ArcBridgeService::StopReason reason) {
// TODO(crbug.com/625923): Use |reason| to report more detailed errors.
if (waiting_for_reply_) { if (waiting_for_reply_) {
// Using SERVICE_UNAVAILABLE instead of UNKNOWN_ERROR, since the latter // Using SERVICE_UNAVAILABLE instead of UNKNOWN_ERROR, since the latter
// causes this code to not try to stop ARC, so it would retry without the // causes this code to not try to stop ARC, so it would retry without the
......
...@@ -124,7 +124,7 @@ class ArcAuthService : public ArcService, ...@@ -124,7 +124,7 @@ class ArcAuthService : public ArcService,
void RemoveObserver(Observer* observer); void RemoveObserver(Observer* observer);
// ArcBridgeService::Observer: // ArcBridgeService::Observer:
void OnBridgeStopped() override; void OnBridgeStopped(ArcBridgeService::StopReason reason) override;
// InstanceHolder<mojom::AuthInstance>::Observer: // InstanceHolder<mojom::AuthInstance>::Observer:
void OnInstanceReady() override; void OnInstanceReady() override;
......
...@@ -237,7 +237,7 @@ ArcAppListPrefs::ArcAppListPrefs(const base::FilePath& base_path, ...@@ -237,7 +237,7 @@ ArcAppListPrefs::ArcAppListPrefs(const base::FilePath& base_path,
bridge_service->app()->AddObserver(this); bridge_service->app()->AddObserver(this);
bridge_service->AddObserver(this); bridge_service->AddObserver(this);
if (!bridge_service->ready()) if (!bridge_service->ready())
OnBridgeStopped(); OnBridgeStopped(arc::ArcBridgeService::StopReason::SHUTDOWN);
} }
ArcAppListPrefs::~ArcAppListPrefs() { ArcAppListPrefs::~ArcAppListPrefs() {
...@@ -563,7 +563,8 @@ void ArcAppListPrefs::OnOptInEnabled(bool enabled) { ...@@ -563,7 +563,8 @@ void ArcAppListPrefs::OnOptInEnabled(bool enabled) {
RemoveAllApps(); RemoveAllApps();
} }
void ArcAppListPrefs::OnBridgeStopped() { void ArcAppListPrefs::OnBridgeStopped(
arc::ArcBridgeService::StopReason reason) {
DisableAllApps(); DisableAllApps();
} }
......
...@@ -209,7 +209,7 @@ class ArcAppListPrefs ...@@ -209,7 +209,7 @@ class ArcAppListPrefs
ArcAppListPrefs(const base::FilePath& base_path, PrefService* prefs); ArcAppListPrefs(const base::FilePath& base_path, PrefService* prefs);
// arc::ArcBridgeService::Observer: // arc::ArcBridgeService::Observer:
void OnBridgeStopped() override; void OnBridgeStopped(arc::ArcBridgeService::StopReason reason) override;
// arc::InstanceHolder<arc::mojom::AppInstance>::Observer: // arc::InstanceHolder<arc::mojom::AppInstance>::Observer:
void OnInstanceReady() override; void OnInstanceReady() override;
......
...@@ -73,11 +73,11 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap, ...@@ -73,11 +73,11 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
// AcceptInstanceConnection() -> OnInstanceConnected() -> // AcceptInstanceConnection() -> OnInstanceConnected() ->
// READY // READY
// //
// When Stop() is called from any state, either because an operation // When Stop() or AbortBoot() is called from any state, either because an
// resulted in an error or because the user is logging out: // operation resulted in an error or because the user is logging out:
// //
// (any) // (any)
// Stop() -> // Stop()/AbortBoot() ->
// STOPPING // STOPPING
// StopInstance() -> // StopInstance() ->
// STOPPED // STOPPED
...@@ -86,6 +86,9 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap, ...@@ -86,6 +86,9 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
// READY -> STOPPING -> STOPPED // READY -> STOPPING -> STOPPED
// and then restarted: // and then restarted:
// STOPPED -> SOCKET_CREATING -> ... -> READY). // STOPPED -> SOCKET_CREATING -> ... -> READY).
//
// Note: Order of constants below matters. Please make sure to sort them
// in chronological order.
enum class State { enum class State {
// ARC is not currently running. // ARC is not currently running.
STOPPED, STOPPED,
...@@ -114,6 +117,10 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap, ...@@ -114,6 +117,10 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
void Stop() override; void Stop() override;
private: private:
// Aborts ARC instance boot. This is called from various state-machine
// functions when they encounter an error during boot.
void AbortBoot(ArcBridgeService::StopReason reason);
// Creates the UNIX socket on the bootstrap thread and then processes its // Creates the UNIX socket on the bootstrap thread and then processes its
// file descriptor. // file descriptor.
static base::ScopedFD CreateSocket(); static base::ScopedFD CreateSocket();
...@@ -135,6 +142,10 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap, ...@@ -135,6 +142,10 @@ class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
// The state of the bootstrap connection. // The state of the bootstrap connection.
State state_ = State::STOPPED; State state_ = State::STOPPED;
// The reason the ARC instance is stopped.
ArcBridgeService::StopReason stop_reason_ =
ArcBridgeService::StopReason::SHUTDOWN;
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
// WeakPtrFactory to use callbacks. // WeakPtrFactory to use callbacks.
...@@ -168,6 +179,7 @@ void ArcBridgeBootstrapImpl::Start() { ...@@ -168,6 +179,7 @@ void ArcBridgeBootstrapImpl::Start() {
VLOG(1) << "Start() called when instance is not stopped"; VLOG(1) << "Start() called when instance is not stopped";
return; return;
} }
stop_reason_ = ArcBridgeService::StopReason::SHUTDOWN;
SetState(State::SOCKET_CREATING); SetState(State::SOCKET_CREATING);
base::PostTaskAndReplyWithResult( base::PostTaskAndReplyWithResult(
base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
...@@ -236,7 +248,7 @@ void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) { ...@@ -236,7 +248,7 @@ void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) {
if (!socket_fd.is_valid()) { if (!socket_fd.is_valid()) {
LOG(ERROR) << "ARC: Error creating socket"; LOG(ERROR) << "ARC: Error creating socket";
Stop(); AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return; return;
} }
...@@ -261,7 +273,7 @@ void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, ...@@ -261,7 +273,7 @@ void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd,
// Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal
// to stop the failed instance. // to stop the failed instance.
SetState(State::SOCKET_CREATING); SetState(State::SOCKET_CREATING);
Stop(); AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return; return;
} }
if (state_ != State::STARTING) { if (state_ != State::STARTING) {
...@@ -318,12 +330,14 @@ void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) { ...@@ -318,12 +330,14 @@ void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) {
} }
if (!fd.is_valid()) { if (!fd.is_valid()) {
LOG(ERROR) << "Invalid handle"; LOG(ERROR) << "Invalid handle";
AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return; return;
} }
mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe( mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe(
mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release()))); mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release())));
if (!server_pipe.is_valid()) { if (!server_pipe.is_valid()) {
LOG(ERROR) << "Invalid pipe"; LOG(ERROR) << "Invalid pipe";
AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
return; return;
} }
SetState(State::READY); SetState(State::READY);
...@@ -339,11 +353,10 @@ void ArcBridgeBootstrapImpl::Stop() { ...@@ -339,11 +353,10 @@ void ArcBridgeBootstrapImpl::Stop() {
VLOG(1) << "Stop() called when ARC is not running"; VLOG(1) << "Stop() called when ARC is not running";
return; return;
} }
if (state_ == State::SOCKET_CREATING) { if (state_ < State::STARTING) {
// This was stopped before the D-Bus command to start the instance. Skip // This was stopped before the D-Bus command to start the instance. Skip
// the D-Bus command to stop it. // the D-Bus command to stop it.
SetState(State::STOPPING); SetState(State::STOPPED);
ArcInstanceStopped(true);
return; return;
} }
SetState(State::STOPPING); SetState(State::STOPPING);
...@@ -354,13 +367,26 @@ void ArcBridgeBootstrapImpl::Stop() { ...@@ -354,13 +367,26 @@ void ArcBridgeBootstrapImpl::Stop() {
base::Bind(&DoNothingInstanceStopped)); base::Bind(&DoNothingInstanceStopped));
} }
void ArcBridgeBootstrapImpl::AbortBoot(ArcBridgeService::StopReason reason) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(reason != ArcBridgeService::StopReason::SHUTDOWN);
// In case of multiple errors, report the first one.
if (stop_reason_ == ArcBridgeService::StopReason::SHUTDOWN) {
stop_reason_ = reason;
}
Stop();
}
void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) { void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (!clean) if (!clean) {
LOG(ERROR) << "ARC instance crashed"; LOG(ERROR) << "ARC instance crashed";
DCHECK(delegate_); // In case of multiple errors, report the first one.
if (stop_reason_ == ArcBridgeService::StopReason::SHUTDOWN) {
stop_reason_ = ArcBridgeService::StopReason::CRASH;
}
}
SetState(State::STOPPED); SetState(State::STOPPED);
delegate_->OnStopped();
} }
void ArcBridgeBootstrapImpl::SetState(State state) { void ArcBridgeBootstrapImpl::SetState(State state) {
...@@ -369,6 +395,10 @@ void ArcBridgeBootstrapImpl::SetState(State state) { ...@@ -369,6 +395,10 @@ void ArcBridgeBootstrapImpl::SetState(State state) {
DCHECK(state_ != state); DCHECK(state_ != state);
state_ = state; state_ = state;
VLOG(2) << "State: " << static_cast<uint32_t>(state_); VLOG(2) << "State: " << static_cast<uint32_t>(state_);
if (state_ == State::STOPPED) {
DCHECK(delegate_);
delegate_->OnStopped(stop_reason_);
}
} }
} // namespace } // namespace
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/common/arc_bridge.mojom.h" #include "components/arc/common/arc_bridge.mojom.h"
namespace arc { namespace arc {
...@@ -21,9 +22,12 @@ class ArcBridgeBootstrap { ...@@ -21,9 +22,12 @@ class ArcBridgeBootstrap {
public: public:
class Delegate { class Delegate {
public: public:
// Called when the connection with ARC instance has been established.
virtual void OnConnectionEstablished( virtual void OnConnectionEstablished(
mojom::ArcBridgeInstancePtr instance_ptr) = 0; mojom::ArcBridgeInstancePtr instance_ptr) = 0;
virtual void OnStopped() = 0;
// Called when ARC instance is stopped.
virtual void OnStopped(ArcBridgeService::StopReason reason) = 0;
}; };
// Creates a default instance of ArcBridgeBootstrap. // Creates a default instance of ArcBridgeBootstrap.
......
...@@ -17,8 +17,10 @@ namespace arc { ...@@ -17,8 +17,10 @@ namespace arc {
ArcBridgeService* g_arc_bridge_service = nullptr; ArcBridgeService* g_arc_bridge_service = nullptr;
ArcBridgeService::ArcBridgeService() ArcBridgeService::ArcBridgeService()
: available_(false), state_(State::STOPPED), weak_factory_(this) { : available_(false),
} state_(State::STOPPED),
stop_reason_(StopReason::SHUTDOWN),
weak_factory_(this) {}
ArcBridgeService::~ArcBridgeService() { ArcBridgeService::~ArcBridgeService() {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
...@@ -167,7 +169,7 @@ void ArcBridgeService::SetState(State state) { ...@@ -167,7 +169,7 @@ void ArcBridgeService::SetState(State state) {
if (state_ == State::READY) if (state_ == State::READY)
FOR_EACH_OBSERVER(Observer, observer_list(), OnBridgeReady()); FOR_EACH_OBSERVER(Observer, observer_list(), OnBridgeReady());
else if (state == State::STOPPED) else if (state == State::STOPPED)
FOR_EACH_OBSERVER(Observer, observer_list(), OnBridgeStopped()); FOR_EACH_OBSERVER(Observer, observer_list(), OnBridgeStopped(stop_reason_));
} }
void ArcBridgeService::SetAvailable(bool available) { void ArcBridgeService::SetAvailable(bool available) {
...@@ -177,6 +179,11 @@ void ArcBridgeService::SetAvailable(bool available) { ...@@ -177,6 +179,11 @@ void ArcBridgeService::SetAvailable(bool available) {
FOR_EACH_OBSERVER(Observer, observer_list(), OnAvailableChanged(available_)); FOR_EACH_OBSERVER(Observer, observer_list(), OnAvailableChanged(available_));
} }
void ArcBridgeService::SetStopReason(StopReason stop_reason) {
DCHECK(CalledOnValidThread());
stop_reason_ = stop_reason;
}
bool ArcBridgeService::CalledOnValidThread() { bool ArcBridgeService::CalledOnValidThread() {
return thread_checker_.CalledOnValidThread(); return thread_checker_.CalledOnValidThread();
} }
......
...@@ -22,7 +22,6 @@ class CommandLine; ...@@ -22,7 +22,6 @@ class CommandLine;
namespace arc { namespace arc {
class ArcBridgeBootstrap;
class ArcBridgeTest; class ArcBridgeTest;
// The Chrome-side service that handles ARC instances and ARC bridge creation. // The Chrome-side service that handles ARC instances and ARC bridge creation.
...@@ -30,12 +29,26 @@ class ArcBridgeTest; ...@@ -30,12 +29,26 @@ class ArcBridgeTest;
// communication channel (the ARC bridge) used to send and receive messages. // communication channel (the ARC bridge) used to send and receive messages.
class ArcBridgeService : public mojom::ArcBridgeHost { class ArcBridgeService : public mojom::ArcBridgeHost {
public: public:
// Describes the reason the bridge is stopped.
enum class StopReason {
// ARC instance has been gracefully shut down.
SHUTDOWN,
// Errors occurred during the ARC instance boot. This includes any failures
// before the instance is actually attempted to be started, and also
// failures on bootstrapping IPC channels with Android.
GENERIC_BOOT_FAILURE,
// ARC instance has crashed.
CRASH,
};
// Notifies life cycle events of ArcBridgeService. // Notifies life cycle events of ArcBridgeService.
class Observer { class Observer {
public: public:
// Called whenever the state of the bridge has changed. // Called whenever the state of the bridge has changed.
virtual void OnBridgeReady() {} virtual void OnBridgeReady() {}
virtual void OnBridgeStopped() {} virtual void OnBridgeStopped(StopReason reason) {}
// Called whenever ARC's availability has changed for this system. // Called whenever ARC's availability has changed for this system.
virtual void OnAvailableChanged(bool available) {} virtual void OnAvailableChanged(bool available) {}
...@@ -195,6 +208,11 @@ class ArcBridgeService : public mojom::ArcBridgeHost { ...@@ -195,6 +208,11 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
// Changes the current availability and notifies all observers. // Changes the current availability and notifies all observers.
void SetAvailable(bool availability); void SetAvailable(bool availability);
// Sets the reason the bridge is stopped. This function must be always called
// before SetState(State::STOPPED) to report a correct reason with
// Observer::OnBridgeStopped().
void SetStopReason(StopReason stop_reason);
base::ObserverList<Observer>& observer_list() { return observer_list_; } base::ObserverList<Observer>& observer_list() { return observer_list_; }
bool CalledOnValidThread(); bool CalledOnValidThread();
...@@ -208,6 +226,7 @@ class ArcBridgeService : public mojom::ArcBridgeHost { ...@@ -208,6 +226,7 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Prerequisites); FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Prerequisites);
FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, ShutdownMidStartup); FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, ShutdownMidStartup);
FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart); FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart);
FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, OnBridgeStopped);
// Instance holders. // Instance holders.
InstanceHolder<mojom::AppInstance> app_; InstanceHolder<mojom::AppInstance> app_;
...@@ -240,6 +259,9 @@ class ArcBridgeService : public mojom::ArcBridgeHost { ...@@ -240,6 +259,9 @@ class ArcBridgeService : public mojom::ArcBridgeHost {
// The current state of the bridge. // The current state of the bridge.
ArcBridgeService::State state_; ArcBridgeService::State state_;
// The reason the bridge is stopped.
StopReason stop_reason_;
// WeakPtrFactory to use callbacks. // WeakPtrFactory to use callbacks.
base::WeakPtrFactory<ArcBridgeService> weak_factory_; base::WeakPtrFactory<ArcBridgeService> weak_factory_;
......
...@@ -78,6 +78,7 @@ void ArcBridgeServiceImpl::PrerequisitesChanged() { ...@@ -78,6 +78,7 @@ void ArcBridgeServiceImpl::PrerequisitesChanged() {
if (!available() || !session_started_) if (!available() || !session_started_)
return; return;
VLOG(0) << "Prerequisites met, starting ARC"; VLOG(0) << "Prerequisites met, starting ARC";
SetStopReason(StopReason::SHUTDOWN);
SetState(State::CONNECTING); SetState(State::CONNECTING);
bootstrap_->Start(); bootstrap_->Start();
} else { } else {
...@@ -136,8 +137,9 @@ void ArcBridgeServiceImpl::OnConnectionEstablished( ...@@ -136,8 +137,9 @@ void ArcBridgeServiceImpl::OnConnectionEstablished(
SetState(State::READY); SetState(State::READY);
} }
void ArcBridgeServiceImpl::OnStopped() { void ArcBridgeServiceImpl::OnStopped(StopReason stop_reason) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
SetStopReason(stop_reason);
SetState(State::STOPPED); SetState(State::STOPPED);
VLOG(0) << "ARC stopped"; VLOG(0) << "ARC stopped";
if (reconnect_) { if (reconnect_) {
......
...@@ -44,6 +44,7 @@ class ArcBridgeServiceImpl : public ArcBridgeService, ...@@ -44,6 +44,7 @@ class ArcBridgeServiceImpl : public ArcBridgeService,
private: private:
friend class ArcBridgeTest; friend class ArcBridgeTest;
FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart); FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart);
FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, OnBridgeStopped);
// If all pre-requisites are true (ARC is available, it has been enabled, and // If all pre-requisites are true (ARC is available, it has been enabled, and
// the session has started), and ARC is stopped, start ARC. If ARC is running // the session has started), and ARC is stopped, start ARC. If ARC is running
...@@ -55,7 +56,7 @@ class ArcBridgeServiceImpl : public ArcBridgeService, ...@@ -55,7 +56,7 @@ class ArcBridgeServiceImpl : public ArcBridgeService,
// ArcBridgeBootstrap::Delegate: // ArcBridgeBootstrap::Delegate:
void OnConnectionEstablished(mojom::ArcBridgeInstancePtr instance) override; void OnConnectionEstablished(mojom::ArcBridgeInstancePtr instance) override;
void OnStopped() override; void OnStopped(StopReason reason) override;
// Called when the bridge channel is closed. This typically only happens when // Called when the bridge channel is closed. This typically only happens when
// the ARC instance crashes. This is not called during shutdown. // the ARC instance crashes. This is not called during shutdown.
......
...@@ -34,8 +34,9 @@ class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer { ...@@ -34,8 +34,9 @@ class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer {
ready_ = true; ready_ = true;
} }
void OnBridgeStopped() override { void OnBridgeStopped(ArcBridgeService::StopReason stop_reason) override {
state_ = ArcBridgeService::State::STOPPED; state_ = ArcBridgeService::State::STOPPED;
stop_reason_ = stop_reason;
message_loop_.PostTask(FROM_HERE, message_loop_.QuitWhenIdleClosure()); message_loop_.PostTask(FROM_HERE, message_loop_.QuitWhenIdleClosure());
} }
...@@ -45,6 +46,7 @@ class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer { ...@@ -45,6 +46,7 @@ class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer {
protected: protected:
std::unique_ptr<ArcBridgeServiceImpl> service_; std::unique_ptr<ArcBridgeServiceImpl> service_;
std::unique_ptr<FakeArcBridgeInstance> instance_; std::unique_ptr<FakeArcBridgeInstance> instance_;
ArcBridgeService::StopReason stop_reason_;
private: private:
void SetUp() override { void SetUp() override {
...@@ -52,6 +54,7 @@ class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer { ...@@ -52,6 +54,7 @@ class ArcBridgeTest : public testing::Test, public ArcBridgeService::Observer {
ready_ = false; ready_ = false;
state_ = ArcBridgeService::State::STOPPED; state_ = ArcBridgeService::State::STOPPED;
stop_reason_ = ArcBridgeService::StopReason::SHUTDOWN;
instance_.reset(new FakeArcBridgeInstance()); instance_.reset(new FakeArcBridgeInstance());
service_.reset(new ArcBridgeServiceImpl( service_.reset(new ArcBridgeServiceImpl(
...@@ -129,7 +132,7 @@ TEST_F(ArcBridgeTest, Restart) { ...@@ -129,7 +132,7 @@ TEST_F(ArcBridgeTest, Restart) {
// Simulate a connection loss. // Simulate a connection loss.
service_->DisableReconnectDelayForTesting(); service_->DisableReconnectDelayForTesting();
service_->OnChannelClosed(); service_->OnChannelClosed();
instance_->SimulateCrash(); instance_->Stop(ArcBridgeService::StopReason::CRASH);
instance_->WaitForInitCall(); instance_->WaitForInitCall();
ASSERT_EQ(ArcBridgeService::State::READY, state()); ASSERT_EQ(ArcBridgeService::State::READY, state());
ASSERT_EQ(2, instance_->init_calls()); ASSERT_EQ(2, instance_->init_calls());
...@@ -138,6 +141,36 @@ TEST_F(ArcBridgeTest, Restart) { ...@@ -138,6 +141,36 @@ TEST_F(ArcBridgeTest, Restart) {
ASSERT_EQ(ArcBridgeService::State::STOPPED, state()); ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
} }
// Makes sure OnBridgeStopped is called on stop.
TEST_F(ArcBridgeTest, OnBridgeStopped) {
ASSERT_FALSE(ready());
service_->DisableReconnectDelayForTesting();
service_->SetAvailable(true);
service_->HandleStartup();
instance_->WaitForInitCall();
ASSERT_EQ(ArcBridgeService::State::READY, state());
// Simulate boot failure.
service_->OnChannelClosed();
instance_->Stop(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
instance_->WaitForInitCall();
ASSERT_EQ(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE, stop_reason_);
ASSERT_EQ(ArcBridgeService::State::READY, state());
// Simulate crash.
service_->OnChannelClosed();
instance_->Stop(ArcBridgeService::StopReason::CRASH);
instance_->WaitForInitCall();
ASSERT_EQ(ArcBridgeService::StopReason::CRASH, stop_reason_);
ASSERT_EQ(ArcBridgeService::State::READY, state());
// Graceful shutdown.
service_->Shutdown();
ASSERT_EQ(ArcBridgeService::StopReason::SHUTDOWN, stop_reason_);
ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
}
// Removing the same observer more than once should be okay. // Removing the same observer more than once should be okay.
TEST_F(ArcBridgeTest, RemoveObserverTwice) { TEST_F(ArcBridgeTest, RemoveObserverTwice) {
ASSERT_FALSE(ready()); ASSERT_FALSE(ready());
......
...@@ -28,11 +28,13 @@ void FakeArcBridgeBootstrap::Start() { ...@@ -28,11 +28,13 @@ void FakeArcBridgeBootstrap::Start() {
void FakeArcBridgeBootstrap::Stop() { void FakeArcBridgeBootstrap::Stop() {
DCHECK(delegate_); DCHECK(delegate_);
instance_->Unbind(); instance_->Unbind();
delegate_->OnStopped(); delegate_->OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
} }
void FakeArcBridgeBootstrap::OnCrashed() { void FakeArcBridgeBootstrap::OnStopped(ArcBridgeService::StopReason reason) {
Stop(); DCHECK(delegate_);
instance_->Unbind();
delegate_->OnStopped(reason);
} }
} // namespace arc } // namespace arc
...@@ -24,7 +24,7 @@ class FakeArcBridgeBootstrap : public ArcBridgeBootstrap, ...@@ -24,7 +24,7 @@ class FakeArcBridgeBootstrap : public ArcBridgeBootstrap,
private: private:
// FakeArcBridgeInstance::Delegate: // FakeArcBridgeInstance::Delegate:
void OnCrashed() override; void OnStopped(ArcBridgeService::StopReason reason) override;
// Owned by the caller. // Owned by the caller.
FakeArcBridgeInstance* instance_; FakeArcBridgeInstance* instance_;
......
...@@ -31,10 +31,10 @@ void FakeArcBridgeInstance::WaitForInitCall() { ...@@ -31,10 +31,10 @@ void FakeArcBridgeInstance::WaitForInitCall() {
binding_.WaitForIncomingMethodCall(); binding_.WaitForIncomingMethodCall();
} }
void FakeArcBridgeInstance::SimulateCrash() { void FakeArcBridgeInstance::Stop(ArcBridgeService::StopReason reason) {
if (!delegate_) if (!delegate_)
return; return;
delegate_->OnCrashed(); delegate_->OnStopped(reason);
} }
} // namespace arc } // namespace arc
...@@ -17,7 +17,7 @@ class FakeArcBridgeInstance : public mojom::ArcBridgeInstance { ...@@ -17,7 +17,7 @@ class FakeArcBridgeInstance : public mojom::ArcBridgeInstance {
class Delegate { class Delegate {
public: public:
virtual ~Delegate() = default; virtual ~Delegate() = default;
virtual void OnCrashed() = 0; virtual void OnStopped(ArcBridgeService::StopReason reason) = 0;
}; };
FakeArcBridgeInstance(); FakeArcBridgeInstance();
...@@ -41,8 +41,8 @@ class FakeArcBridgeInstance : public mojom::ArcBridgeInstance { ...@@ -41,8 +41,8 @@ class FakeArcBridgeInstance : public mojom::ArcBridgeInstance {
// The number of times Init() has been called. // The number of times Init() has been called.
int init_calls() const { return init_calls_; } int init_calls() const { return init_calls_; }
// Simulates a crash by calling Stop() on the ArcBridgeBoostrap. // Stops the instance.
void SimulateCrash(); void Stop(ArcBridgeService::StopReason reason);
private: private:
Delegate* delegate_ = nullptr; Delegate* delegate_ = nullptr;
......
...@@ -31,7 +31,7 @@ ArcUserDataService::~ArcUserDataService() { ...@@ -31,7 +31,7 @@ ArcUserDataService::~ArcUserDataService() {
arc_bridge_service()->RemoveObserver(this); arc_bridge_service()->RemoveObserver(this);
} }
void ArcUserDataService::OnBridgeStopped() { void ArcUserDataService::OnBridgeStopped(ArcBridgeService::StopReason reason) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
const AccountId& account_id = const AccountId& account_id =
user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId(); user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId();
......
...@@ -30,7 +30,7 @@ class ArcUserDataService : public ArcService, ...@@ -30,7 +30,7 @@ class ArcUserDataService : public ArcService,
// ArcBridgeService::Observer: // ArcBridgeService::Observer:
// Called whenever the arc bridge is stopped to potentially remove data if // Called whenever the arc bridge is stopped to potentially remove data if
// the user has not opted in. // the user has not opted in.
void OnBridgeStopped() override; void OnBridgeStopped(ArcBridgeService::StopReason reason) override;
private: private:
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
......
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