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