| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/arc/arc_bridge_service_impl.h" | 5 #include "components/arc/arc_bridge_service_impl.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
| 12 #include "base/sequenced_task_runner.h" | 12 #include "base/sequenced_task_runner.h" |
| 13 #include "base/sys_info.h" | 13 #include "base/sys_info.h" |
| 14 #include "base/task_runner_util.h" | 14 #include "base/task_runner_util.h" |
| 15 #include "base/threading/thread_task_runner_handle.h" | 15 #include "base/threading/thread_task_runner_handle.h" |
| 16 #include "base/time/time.h" | 16 #include "base/time/time.h" |
| 17 #include "chromeos/chromeos_switches.h" | 17 #include "chromeos/chromeos_switches.h" |
| 18 #include "chromeos/dbus/dbus_method_call_status.h" | 18 #include "chromeos/dbus/dbus_method_call_status.h" |
| 19 #include "chromeos/dbus/dbus_thread_manager.h" | 19 #include "chromeos/dbus/dbus_thread_manager.h" |
| 20 #include "components/arc/arc_session.h" | 20 #include "components/arc/arc_session.h" |
| 21 #include "components/prefs/pref_registry_simple.h" | 21 #include "components/prefs/pref_registry_simple.h" |
| 22 #include "components/prefs/pref_service.h" | 22 #include "components/prefs/pref_service.h" |
| 23 | 23 |
| 24 namespace arc { | 24 namespace arc { |
| 25 |
| 25 namespace { | 26 namespace { |
| 26 constexpr int64_t kReconnectDelayInSeconds = 5; | 27 |
| 28 constexpr base::TimeDelta kDefaultRestartDelay = |
| 29 base::TimeDelta::FromSeconds(5); |
| 30 |
| 27 } // namespace | 31 } // namespace |
| 28 | 32 |
| 29 ArcBridgeServiceImpl::ArcBridgeServiceImpl( | 33 ArcBridgeServiceImpl::ArcBridgeServiceImpl( |
| 30 const scoped_refptr<base::TaskRunner>& blocking_task_runner) | 34 const scoped_refptr<base::TaskRunner>& blocking_task_runner) |
| 31 : session_started_(false), | 35 : session_started_(false), |
| 36 restart_delay_(kDefaultRestartDelay), |
| 32 factory_(base::Bind(ArcSession::Create, this, blocking_task_runner)), | 37 factory_(base::Bind(ArcSession::Create, this, blocking_task_runner)), |
| 33 weak_factory_(this) {} | 38 weak_factory_(this) {} |
| 34 | 39 |
| 35 ArcBridgeServiceImpl::~ArcBridgeServiceImpl() { | 40 ArcBridgeServiceImpl::~ArcBridgeServiceImpl() { |
| 36 if (arc_session_) | 41 if (arc_session_) |
| 37 arc_session_->RemoveObserver(this); | 42 arc_session_->RemoveObserver(this); |
| 38 } | 43 } |
| 39 | 44 |
| 40 void ArcBridgeServiceImpl::RequestStart() { | 45 void ArcBridgeServiceImpl::RequestStart() { |
| 41 DCHECK(CalledOnValidThread()); | 46 DCHECK(CalledOnValidThread()); |
| 42 if (session_started_) | 47 if (session_started_) |
| 43 return; | 48 return; |
| 44 VLOG(1) << "Session started"; | 49 VLOG(1) << "Session started"; |
| 45 session_started_ = true; | 50 session_started_ = true; |
| 46 PrerequisitesChanged(); | 51 PrerequisitesChanged(); |
| 47 } | 52 } |
| 48 | 53 |
| 49 void ArcBridgeServiceImpl::RequestStop() { | 54 void ArcBridgeServiceImpl::RequestStop() { |
| 50 DCHECK(CalledOnValidThread()); | 55 DCHECK(CalledOnValidThread()); |
| 51 if (!session_started_) | 56 if (!session_started_) |
| 52 return; | 57 return; |
| 53 VLOG(1) << "Session ended"; | 58 VLOG(1) << "Session ended"; |
| 54 session_started_ = false; | 59 session_started_ = false; |
| 55 PrerequisitesChanged(); | 60 PrerequisitesChanged(); |
| 56 } | 61 } |
| 57 | 62 |
| 58 void ArcBridgeServiceImpl::OnShutdown() { | 63 void ArcBridgeServiceImpl::OnShutdown() { |
| 59 DCHECK(CalledOnValidThread()); | 64 DCHECK(CalledOnValidThread()); |
| 65 |
| 60 VLOG(1) << "OnShutdown"; | 66 VLOG(1) << "OnShutdown"; |
| 61 if (!session_started_) | |
| 62 return; | |
| 63 session_started_ = false; | 67 session_started_ = false; |
| 64 reconnect_ = false; | 68 restart_timer_.Stop(); |
| 65 if (arc_session_) | 69 if (arc_session_) { |
| 70 if (state() != State::STOPPING) |
| 71 SetState(State::STOPPING); |
| 66 arc_session_->OnShutdown(); | 72 arc_session_->OnShutdown(); |
| 73 } |
| 74 // ArcSession::OnShutdown() invokes OnSessionStopped() synchronously. |
| 75 // In the observer method, |arc_session_| should be destroyed. |
| 76 DCHECK(!arc_session_); |
| 67 } | 77 } |
| 68 | 78 |
| 69 void ArcBridgeServiceImpl::SetArcSessionFactoryForTesting( | 79 void ArcBridgeServiceImpl::SetArcSessionFactoryForTesting( |
| 70 const ArcSessionFactory& factory) { | 80 const ArcSessionFactory& factory) { |
| 71 DCHECK(!factory.is_null()); | 81 DCHECK(!factory.is_null()); |
| 72 factory_ = factory; | 82 factory_ = factory; |
| 73 } | 83 } |
| 74 | 84 |
| 75 void ArcBridgeServiceImpl::DisableReconnectDelayForTesting() { | 85 void ArcBridgeServiceImpl::SetRestartDelayForTesting( |
| 76 use_delay_before_reconnecting_ = false; | 86 const base::TimeDelta& restart_delay) { |
| 87 DCHECK_EQ(state(), State::STOPPED); |
| 88 DCHECK(!arc_session_); |
| 89 DCHECK(!restart_timer_.IsRunning()); |
| 90 restart_delay_ = restart_delay; |
| 77 } | 91 } |
| 78 | 92 |
| 79 void ArcBridgeServiceImpl::PrerequisitesChanged() { | 93 void ArcBridgeServiceImpl::PrerequisitesChanged() { |
| 80 DCHECK(CalledOnValidThread()); | 94 DCHECK(CalledOnValidThread()); |
| 81 VLOG(1) << "Prerequisites changed. " | 95 VLOG(1) << "Prerequisites changed. " |
| 82 << "state=" << static_cast<uint32_t>(state()) | 96 << "state=" << static_cast<uint32_t>(state()) |
| 83 << ", session_started=" << session_started_; | 97 << ", session_started=" << session_started_; |
| 84 if (state() == State::STOPPED) { | 98 if (state() == State::STOPPED) { |
| 85 if (!session_started_) | 99 if (!session_started_) { |
| 100 // We were explicitly asked to stop, so do not restart. |
| 101 restart_timer_.Stop(); |
| 86 return; | 102 return; |
| 103 } |
| 104 DCHECK(!restart_timer_.IsRunning()); |
| 87 VLOG(0) << "Prerequisites met, starting ARC"; | 105 VLOG(0) << "Prerequisites met, starting ARC"; |
| 88 SetStopReason(StopReason::SHUTDOWN); | 106 StartArcSession(); |
| 89 | |
| 90 if (arc_session_) | |
| 91 arc_session_->RemoveObserver(this); | |
| 92 | |
| 93 SetState(State::CONNECTING); | |
| 94 arc_session_ = factory_.Run(); | |
| 95 arc_session_->AddObserver(this); | |
| 96 arc_session_->Start(); | |
| 97 } else { | 107 } else { |
| 108 DCHECK(!restart_timer_.IsRunning()); |
| 98 if (session_started_) | 109 if (session_started_) |
| 99 return; | 110 return; |
| 100 VLOG(0) << "Prerequisites stopped being met, stopping ARC"; | 111 VLOG(0) << "Prerequisites stopped being met, stopping ARC"; |
| 101 StopInstance(); | 112 StopInstance(); |
| 102 } | 113 } |
| 103 } | 114 } |
| 104 | 115 |
| 116 void ArcBridgeServiceImpl::StartArcSession() { |
| 117 DCHECK(CalledOnValidThread()); |
| 118 DCHECK_EQ(state(), State::STOPPED); |
| 119 DCHECK(!arc_session_); |
| 120 DCHECK(!restart_timer_.IsRunning()); |
| 121 |
| 122 VLOG(1) << "Starting ARC instance"; |
| 123 SetStopReason(StopReason::SHUTDOWN); |
| 124 arc_session_ = factory_.Run(); |
| 125 arc_session_->AddObserver(this); |
| 126 SetState(State::CONNECTING); |
| 127 arc_session_->Start(); |
| 128 } |
| 129 |
| 105 void ArcBridgeServiceImpl::StopInstance() { | 130 void ArcBridgeServiceImpl::StopInstance() { |
| 106 DCHECK(CalledOnValidThread()); | 131 DCHECK(CalledOnValidThread()); |
| 107 if (state() == State::STOPPED || state() == State::STOPPING) { | 132 DCHECK_NE(state(), State::STOPPED); |
| 133 DCHECK(!restart_timer_.IsRunning()); |
| 134 |
| 135 if (state() == State::STOPPING) { |
| 108 VLOG(1) << "StopInstance() called when ARC is not running"; | 136 VLOG(1) << "StopInstance() called when ARC is not running"; |
| 109 return; | 137 return; |
| 110 } | 138 } |
| 111 | 139 |
| 112 // We were explicitly asked to stop, so do not reconnect. | |
| 113 reconnect_ = false; | |
| 114 | |
| 115 VLOG(1) << "Stopping ARC"; | 140 VLOG(1) << "Stopping ARC"; |
| 116 DCHECK(arc_session_.get()); | 141 DCHECK(arc_session_.get()); |
| 117 SetState(State::STOPPING); | 142 SetState(State::STOPPING); |
| 118 | 143 |
| 119 // Note: this can call OnStopped() internally as a callback. | 144 // Note: this can call OnStopped() internally as a callback. |
| 120 arc_session_->Stop(); | 145 arc_session_->Stop(); |
| 121 } | 146 } |
| 122 | 147 |
| 123 void ArcBridgeServiceImpl::OnSessionReady() { | 148 void ArcBridgeServiceImpl::OnSessionReady() { |
| 124 DCHECK(CalledOnValidThread()); | 149 DCHECK(CalledOnValidThread()); |
| 125 if (state() != State::CONNECTING) { | 150 if (state() != State::CONNECTING) { |
| 126 VLOG(1) << "StopInstance() called while connecting"; | 151 VLOG(1) << "StopInstance() called while connecting"; |
| 127 return; | 152 return; |
| 128 } | 153 } |
| 129 | 154 |
| 130 // The container can be considered to have been successfully launched, so | |
| 131 // restart if the connection goes down without being requested. | |
| 132 reconnect_ = true; | |
| 133 VLOG(0) << "ARC ready"; | 155 VLOG(0) << "ARC ready"; |
| 134 SetState(State::READY); | 156 SetState(State::READY); |
| 135 } | 157 } |
| 136 | 158 |
| 137 void ArcBridgeServiceImpl::OnSessionStopped(StopReason stop_reason) { | 159 void ArcBridgeServiceImpl::OnSessionStopped(StopReason stop_reason) { |
| 138 DCHECK(CalledOnValidThread()); | 160 DCHECK(CalledOnValidThread()); |
| 161 DCHECK(!restart_timer_.IsRunning()); |
| 162 |
| 139 VLOG(0) << "ARC stopped: " << stop_reason; | 163 VLOG(0) << "ARC stopped: " << stop_reason; |
| 140 arc_session_->RemoveObserver(this); | 164 arc_session_->RemoveObserver(this); |
| 141 arc_session_.reset(); | 165 arc_session_.reset(); |
| 166 |
| 167 // If READY, ARC instance unexpectedly crashed so we need to restart it |
| 168 // automatically. |
| 169 // If STOPPING, at least once RequestStop() is called. If |session_started_| |
| 170 // is true, RequestStart() is following so schedule to restart ARC session. |
| 171 // Otherwise, do nothing. |
| 172 // If CONNECTING, ARC instance has not been booted properly, so do not |
| 173 // restart it automatically. |
| 174 if (state() == State::READY || |
| 175 (state() == State::STOPPING && session_started_)) { |
| 176 // This check is for READY case. In READY case |session_started_| should be |
| 177 // always true, because if once RequestStop() is called, the state() will |
| 178 // be set to STOPPING. |
| 179 DCHECK(session_started_); |
| 180 |
| 181 // There was a previous invocation and it crashed for some reason. Try |
| 182 // starting ARC instance later again. |
| 183 // Note that even |restart_delay_| is 0 (for testing), it needs to |
| 184 // PostTask, because observer callback may call RequestStart()/Stop(), |
| 185 // which can change restarting. |
| 186 VLOG(0) << "ARC restarting"; |
| 187 restart_timer_.Start(FROM_HERE, restart_delay_, |
| 188 base::Bind(&ArcBridgeServiceImpl::StartArcSession, |
| 189 weak_factory_.GetWeakPtr())); |
| 190 } |
| 191 |
| 192 // TODO(hidehiko): Consider to let observers know whether there is scheduled |
| 193 // restarting event, or not. |
| 142 SetStopReason(stop_reason); | 194 SetStopReason(stop_reason); |
| 143 SetState(State::STOPPED); | 195 SetState(State::STOPPED); |
| 144 | |
| 145 if (reconnect_) { | |
| 146 // There was a previous invocation and it crashed for some reason. Try | |
| 147 // starting the container again. | |
| 148 reconnect_ = false; | |
| 149 VLOG(0) << "ARC reconnecting"; | |
| 150 if (use_delay_before_reconnecting_) { | |
| 151 // Instead of immediately trying to restart the container, give it some | |
| 152 // time to finish tearing down in case it is still in the process of | |
| 153 // stopping. | |
| 154 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 155 FROM_HERE, base::Bind(&ArcBridgeServiceImpl::PrerequisitesChanged, | |
| 156 weak_factory_.GetWeakPtr()), | |
| 157 base::TimeDelta::FromSeconds(kReconnectDelayInSeconds)); | |
| 158 } else { | |
| 159 // Restart immediately. | |
| 160 PrerequisitesChanged(); | |
| 161 } | |
| 162 } | |
| 163 } | 196 } |
| 164 | 197 |
| 165 } // namespace arc | 198 } // namespace arc |
| OLD | NEW |