| Index: components/arc/arc_bridge_service_impl.cc
|
| diff --git a/components/arc/arc_bridge_service_impl.cc b/components/arc/arc_bridge_service_impl.cc
|
| index fbc8f0b08218bc6e2312da5d545ddd5e12d23381..3205cfe554abf92fd726c002a8289ec3f87ada58 100644
|
| --- a/components/arc/arc_bridge_service_impl.cc
|
| +++ b/components/arc/arc_bridge_service_impl.cc
|
| @@ -22,13 +22,18 @@
|
| #include "components/prefs/pref_service.h"
|
|
|
| namespace arc {
|
| +
|
| namespace {
|
| -constexpr int64_t kReconnectDelayInSeconds = 5;
|
| +
|
| +constexpr base::TimeDelta kDefaultRestartDelay =
|
| + base::TimeDelta::FromSeconds(5);
|
| +
|
| } // namespace
|
|
|
| ArcBridgeServiceImpl::ArcBridgeServiceImpl(
|
| const scoped_refptr<base::TaskRunner>& blocking_task_runner)
|
| : session_started_(false),
|
| + restart_delay_(kDefaultRestartDelay),
|
| factory_(base::Bind(ArcSession::Create, this, blocking_task_runner)),
|
| weak_factory_(this) {}
|
|
|
| @@ -57,13 +62,18 @@ void ArcBridgeServiceImpl::RequestStop() {
|
|
|
| void ArcBridgeServiceImpl::OnShutdown() {
|
| DCHECK(CalledOnValidThread());
|
| +
|
| VLOG(1) << "OnShutdown";
|
| - if (!session_started_)
|
| - return;
|
| session_started_ = false;
|
| - reconnect_ = false;
|
| - if (arc_session_)
|
| + restart_timer_.Stop();
|
| + if (arc_session_) {
|
| + if (state() != State::STOPPING)
|
| + SetState(State::STOPPING);
|
| arc_session_->OnShutdown();
|
| + }
|
| + // ArcSession::OnShutdown() invokes OnSessionStopped() synchronously.
|
| + // In the observer method, |arc_session_| should be destroyed.
|
| + DCHECK(!arc_session_);
|
| }
|
|
|
| void ArcBridgeServiceImpl::SetArcSessionFactoryForTesting(
|
| @@ -72,8 +82,12 @@ void ArcBridgeServiceImpl::SetArcSessionFactoryForTesting(
|
| factory_ = factory;
|
| }
|
|
|
| -void ArcBridgeServiceImpl::DisableReconnectDelayForTesting() {
|
| - use_delay_before_reconnecting_ = false;
|
| +void ArcBridgeServiceImpl::SetRestartDelayForTesting(
|
| + const base::TimeDelta& restart_delay) {
|
| + DCHECK_EQ(state(), State::STOPPED);
|
| + DCHECK(!arc_session_);
|
| + DCHECK(!restart_timer_.IsRunning());
|
| + restart_delay_ = restart_delay;
|
| }
|
|
|
| void ArcBridgeServiceImpl::PrerequisitesChanged() {
|
| @@ -82,19 +96,16 @@ void ArcBridgeServiceImpl::PrerequisitesChanged() {
|
| << "state=" << static_cast<uint32_t>(state())
|
| << ", session_started=" << session_started_;
|
| if (state() == State::STOPPED) {
|
| - if (!session_started_)
|
| + if (!session_started_) {
|
| + // We were explicitly asked to stop, so do not restart.
|
| + restart_timer_.Stop();
|
| return;
|
| + }
|
| + DCHECK(!restart_timer_.IsRunning());
|
| VLOG(0) << "Prerequisites met, starting ARC";
|
| - SetStopReason(StopReason::SHUTDOWN);
|
| -
|
| - if (arc_session_)
|
| - arc_session_->RemoveObserver(this);
|
| -
|
| - SetState(State::CONNECTING);
|
| - arc_session_ = factory_.Run();
|
| - arc_session_->AddObserver(this);
|
| - arc_session_->Start();
|
| + StartArcSession();
|
| } else {
|
| + DCHECK(!restart_timer_.IsRunning());
|
| if (session_started_)
|
| return;
|
| VLOG(0) << "Prerequisites stopped being met, stopping ARC";
|
| @@ -102,16 +113,30 @@ void ArcBridgeServiceImpl::PrerequisitesChanged() {
|
| }
|
| }
|
|
|
| +void ArcBridgeServiceImpl::StartArcSession() {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK_EQ(state(), State::STOPPED);
|
| + DCHECK(!arc_session_);
|
| + DCHECK(!restart_timer_.IsRunning());
|
| +
|
| + VLOG(1) << "Starting ARC instance";
|
| + SetStopReason(StopReason::SHUTDOWN);
|
| + arc_session_ = factory_.Run();
|
| + arc_session_->AddObserver(this);
|
| + SetState(State::CONNECTING);
|
| + arc_session_->Start();
|
| +}
|
| +
|
| void ArcBridgeServiceImpl::StopInstance() {
|
| DCHECK(CalledOnValidThread());
|
| - if (state() == State::STOPPED || state() == State::STOPPING) {
|
| + DCHECK_NE(state(), State::STOPPED);
|
| + DCHECK(!restart_timer_.IsRunning());
|
| +
|
| + if (state() == State::STOPPING) {
|
| VLOG(1) << "StopInstance() called when ARC is not running";
|
| return;
|
| }
|
|
|
| - // We were explicitly asked to stop, so do not reconnect.
|
| - reconnect_ = false;
|
| -
|
| VLOG(1) << "Stopping ARC";
|
| DCHECK(arc_session_.get());
|
| SetState(State::STOPPING);
|
| @@ -127,39 +152,47 @@ void ArcBridgeServiceImpl::OnSessionReady() {
|
| return;
|
| }
|
|
|
| - // The container can be considered to have been successfully launched, so
|
| - // restart if the connection goes down without being requested.
|
| - reconnect_ = true;
|
| VLOG(0) << "ARC ready";
|
| SetState(State::READY);
|
| }
|
|
|
| void ArcBridgeServiceImpl::OnSessionStopped(StopReason stop_reason) {
|
| DCHECK(CalledOnValidThread());
|
| + DCHECK(!restart_timer_.IsRunning());
|
| +
|
| VLOG(0) << "ARC stopped: " << stop_reason;
|
| arc_session_->RemoveObserver(this);
|
| arc_session_.reset();
|
| - SetStopReason(stop_reason);
|
| - SetState(State::STOPPED);
|
|
|
| - if (reconnect_) {
|
| + // If READY, ARC instance unexpectedly crashed so we need to restart it
|
| + // automatically.
|
| + // If STOPPING, at least once RequestStop() is called. If |session_started_|
|
| + // is true, RequestStart() is following so schedule to restart ARC session.
|
| + // Otherwise, do nothing.
|
| + // If CONNECTING, ARC instance has not been booted properly, so do not
|
| + // restart it automatically.
|
| + if (state() == State::READY ||
|
| + (state() == State::STOPPING && session_started_)) {
|
| + // This check is for READY case. In READY case |session_started_| should be
|
| + // always true, because if once RequestStop() is called, the state() will
|
| + // be set to STOPPING.
|
| + DCHECK(session_started_);
|
| +
|
| // There was a previous invocation and it crashed for some reason. Try
|
| - // starting the container again.
|
| - reconnect_ = false;
|
| - VLOG(0) << "ARC reconnecting";
|
| - if (use_delay_before_reconnecting_) {
|
| - // Instead of immediately trying to restart the container, give it some
|
| - // time to finish tearing down in case it is still in the process of
|
| - // stopping.
|
| - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| - FROM_HERE, base::Bind(&ArcBridgeServiceImpl::PrerequisitesChanged,
|
| - weak_factory_.GetWeakPtr()),
|
| - base::TimeDelta::FromSeconds(kReconnectDelayInSeconds));
|
| - } else {
|
| - // Restart immediately.
|
| - PrerequisitesChanged();
|
| - }
|
| + // starting ARC instance later again.
|
| + // Note that even |restart_delay_| is 0 (for testing), it needs to
|
| + // PostTask, because observer callback may call RequestStart()/Stop(),
|
| + // which can change restarting.
|
| + VLOG(0) << "ARC restarting";
|
| + restart_timer_.Start(FROM_HERE, restart_delay_,
|
| + base::Bind(&ArcBridgeServiceImpl::StartArcSession,
|
| + weak_factory_.GetWeakPtr()));
|
| }
|
| +
|
| + // TODO(hidehiko): Consider to let observers know whether there is scheduled
|
| + // restarting event, or not.
|
| + SetStopReason(stop_reason);
|
| + SetState(State::STOPPED);
|
| }
|
|
|
| } // namespace arc
|
|
|