Chromium Code Reviews| 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 namespace { | 25 namespace { |
|
Luis Héctor Chávez
2016/12/16 23:02:13
nit: maybe add a newline before for consistency?
hidehiko
2016/12/19 07:41:21
Done.
| |
| 26 constexpr int64_t kReconnectDelayInSeconds = 5; | 26 |
| 27 constexpr base::TimeDelta kDefaultRestartDelay = | |
| 28 base::TimeDelta::FromSeconds(5); | |
| 29 | |
| 27 } // namespace | 30 } // namespace |
| 28 | 31 |
| 29 ArcBridgeServiceImpl::ArcBridgeServiceImpl( | 32 ArcBridgeServiceImpl::ArcBridgeServiceImpl( |
| 30 const scoped_refptr<base::TaskRunner>& blocking_task_runner) | 33 const scoped_refptr<base::TaskRunner>& blocking_task_runner) |
| 31 : session_started_(false), | 34 : session_started_(false), |
| 35 restart_delay_(kDefaultRestartDelay), | |
| 32 factory_(base::Bind(ArcSession::Create, this, blocking_task_runner)), | 36 factory_(base::Bind(ArcSession::Create, this, blocking_task_runner)), |
| 33 weak_factory_(this) {} | 37 weak_factory_(this) {} |
| 34 | 38 |
| 35 ArcBridgeServiceImpl::~ArcBridgeServiceImpl() { | 39 ArcBridgeServiceImpl::~ArcBridgeServiceImpl() { |
| 36 if (arc_session_) | 40 if (arc_session_) |
| 37 arc_session_->RemoveObserver(this); | 41 arc_session_->RemoveObserver(this); |
| 38 } | 42 } |
| 39 | 43 |
| 40 void ArcBridgeServiceImpl::RequestStart() { | 44 void ArcBridgeServiceImpl::RequestStart() { |
| 41 DCHECK(CalledOnValidThread()); | 45 DCHECK(CalledOnValidThread()); |
| 42 if (session_started_) | 46 if (session_started_) |
| 43 return; | 47 return; |
| 44 VLOG(1) << "Session started"; | 48 VLOG(1) << "Session started"; |
| 45 session_started_ = true; | 49 session_started_ = true; |
| 46 PrerequisitesChanged(); | 50 PrerequisitesChanged(); |
| 47 } | 51 } |
| 48 | 52 |
| 49 void ArcBridgeServiceImpl::RequestStop() { | 53 void ArcBridgeServiceImpl::RequestStop() { |
| 50 DCHECK(CalledOnValidThread()); | 54 DCHECK(CalledOnValidThread()); |
| 51 if (!session_started_) | 55 if (!session_started_) |
| 52 return; | 56 return; |
| 53 VLOG(1) << "Session ended"; | 57 VLOG(1) << "Session ended"; |
| 54 session_started_ = false; | 58 session_started_ = false; |
| 55 PrerequisitesChanged(); | 59 PrerequisitesChanged(); |
| 56 } | 60 } |
| 57 | 61 |
| 58 void ArcBridgeServiceImpl::OnShutdown() { | 62 void ArcBridgeServiceImpl::OnShutdown() { |
| 59 DCHECK(CalledOnValidThread()); | 63 DCHECK(CalledOnValidThread()); |
| 64 | |
| 60 VLOG(1) << "OnShutdown"; | 65 VLOG(1) << "OnShutdown"; |
| 61 if (!session_started_) | |
| 62 return; | |
| 63 session_started_ = false; | 66 session_started_ = false; |
| 64 reconnect_ = false; | 67 restart_timer_.Stop(); |
| 65 if (arc_session_) | 68 if (arc_session_) |
| 66 arc_session_->OnShutdown(); | 69 arc_session_->OnShutdown(); |
| 70 // ArcSession::OnShutdown() invokes OnSessionStopped() synchronously. | |
| 71 // In the observer method, |arc_session_| should be destroyed. | |
| 72 DCHECK(!arc_session_); | |
| 67 } | 73 } |
| 68 | 74 |
| 69 void ArcBridgeServiceImpl::SetArcSessionFactoryForTesting( | 75 void ArcBridgeServiceImpl::SetArcSessionFactoryForTesting( |
| 70 const ArcSessionFactory& factory) { | 76 const ArcSessionFactory& factory) { |
| 71 DCHECK(!factory.is_null()); | 77 DCHECK(!factory.is_null()); |
| 72 factory_ = factory; | 78 factory_ = factory; |
| 73 } | 79 } |
| 74 | 80 |
| 75 void ArcBridgeServiceImpl::DisableReconnectDelayForTesting() { | 81 void ArcBridgeServiceImpl::SetRestartDelayForTesting( |
| 76 use_delay_before_reconnecting_ = false; | 82 const base::TimeDelta& restart_delay) { |
| 83 DCHECK_EQ(state(), State::STOPPED); | |
| 84 DCHECK(!arc_session_); | |
| 85 DCHECK(!restart_timer_.IsRunning()); | |
| 86 restart_delay_ = restart_delay; | |
| 77 } | 87 } |
| 78 | 88 |
| 79 void ArcBridgeServiceImpl::PrerequisitesChanged() { | 89 void ArcBridgeServiceImpl::PrerequisitesChanged() { |
|
Luis Héctor Chávez
2016/12/16 23:02:13
Now that you've removed the third caller of Prereq
Luis Héctor Chávez
2016/12/16 23:06:35
Nevermind about this, I just saw your second patch
hidehiko
2016/12/19 07:41:21
Yes. Let me work on it in the following CL.
| |
| 80 DCHECK(CalledOnValidThread()); | 90 DCHECK(CalledOnValidThread()); |
| 81 VLOG(1) << "Prerequisites changed. " | 91 VLOG(1) << "Prerequisites changed. " |
| 82 << "state=" << static_cast<uint32_t>(state()) | 92 << "state=" << static_cast<uint32_t>(state()) |
| 83 << ", session_started=" << session_started_; | 93 << ", session_started=" << session_started_; |
| 84 if (state() == State::STOPPED) { | 94 if (state() == State::STOPPED) { |
| 85 if (!session_started_) | 95 if (!session_started_) { |
| 96 // We were explicitly asked to stop, so do not restart. | |
| 97 restart_timer_.Stop(); | |
|
Luis Héctor Chávez
2016/12/16 23:02:13
How about you move this to L96-97 to RequestStop()
hidehiko
2016/12/19 07:41:21
If this is not a big problem, can I keep this in t
| |
| 86 return; | 98 return; |
| 99 } | |
| 100 DCHECK(!restart_timer_.IsRunning()); | |
|
Luis Héctor Chávez
2016/12/16 23:02:13
Both branches check for this. Move to after L93?
hidehiko
2016/12/19 07:41:21
Similar to above, can I address this in the follow
| |
| 87 VLOG(0) << "Prerequisites met, starting ARC"; | 101 VLOG(0) << "Prerequisites met, starting ARC"; |
| 88 SetStopReason(StopReason::SHUTDOWN); | 102 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 { | 103 } else { |
| 104 DCHECK(!restart_timer_.IsRunning()); | |
| 98 if (session_started_) | 105 if (session_started_) |
| 99 return; | 106 return; |
| 100 VLOG(0) << "Prerequisites stopped being met, stopping ARC"; | 107 VLOG(0) << "Prerequisites stopped being met, stopping ARC"; |
| 101 StopInstance(); | 108 StopInstance(); |
| 102 } | 109 } |
| 103 } | 110 } |
| 104 | 111 |
| 112 void ArcBridgeServiceImpl::StartArcSession() { | |
| 113 DCHECK(CalledOnValidThread()); | |
| 114 DCHECK_EQ(state(), State::STOPPED); | |
| 115 DCHECK(!arc_session_); | |
| 116 DCHECK(!restart_timer_.IsRunning()); | |
| 117 | |
| 118 VLOG(1) << "Starting ARC instance"; | |
| 119 SetStopReason(StopReason::SHUTDOWN); | |
| 120 arc_session_ = factory_.Run(); | |
| 121 arc_session_->AddObserver(this); | |
| 122 SetState(State::CONNECTING); | |
| 123 arc_session_->Start(); | |
| 124 } | |
| 125 | |
| 105 void ArcBridgeServiceImpl::StopInstance() { | 126 void ArcBridgeServiceImpl::StopInstance() { |
| 106 DCHECK(CalledOnValidThread()); | 127 DCHECK(CalledOnValidThread()); |
| 107 if (state() == State::STOPPED || state() == State::STOPPING) { | 128 DCHECK_NE(state(), State::STOPPED); |
| 129 DCHECK(!restart_timer_.IsRunning()); | |
| 130 | |
| 131 if (state() == State::STOPPING) { | |
| 108 VLOG(1) << "StopInstance() called when ARC is not running"; | 132 VLOG(1) << "StopInstance() called when ARC is not running"; |
| 109 return; | 133 return; |
| 110 } | 134 } |
| 111 | 135 |
| 112 // We were explicitly asked to stop, so do not reconnect. | |
| 113 reconnect_ = false; | |
| 114 | |
| 115 VLOG(1) << "Stopping ARC"; | 136 VLOG(1) << "Stopping ARC"; |
| 116 DCHECK(arc_session_.get()); | 137 DCHECK(arc_session_.get()); |
| 117 SetState(State::STOPPING); | 138 SetState(State::STOPPING); |
| 118 | 139 |
| 119 // Note: this can call OnStopped() internally as a callback. | 140 // Note: this can call OnStopped() internally as a callback. |
| 120 arc_session_->Stop(); | 141 arc_session_->Stop(); |
| 121 } | 142 } |
| 122 | 143 |
| 123 void ArcBridgeServiceImpl::OnSessionReady() { | 144 void ArcBridgeServiceImpl::OnSessionReady() { |
| 124 DCHECK(CalledOnValidThread()); | 145 DCHECK(CalledOnValidThread()); |
| 125 if (state() != State::CONNECTING) { | 146 if (state() != State::CONNECTING) { |
| 126 VLOG(1) << "StopInstance() called while connecting"; | 147 VLOG(1) << "StopInstance() called while connecting"; |
| 127 return; | 148 return; |
| 128 } | 149 } |
| 129 | 150 |
| 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"; | 151 VLOG(0) << "ARC ready"; |
| 134 SetState(State::READY); | 152 SetState(State::READY); |
| 135 } | 153 } |
| 136 | 154 |
| 137 void ArcBridgeServiceImpl::OnSessionStopped(StopReason stop_reason) { | 155 void ArcBridgeServiceImpl::OnSessionStopped(StopReason stop_reason) { |
| 138 DCHECK(CalledOnValidThread()); | 156 DCHECK(CalledOnValidThread()); |
| 157 DCHECK(!restart_timer_.IsRunning()); | |
| 158 | |
| 139 VLOG(0) << "ARC stopped: " << stop_reason; | 159 VLOG(0) << "ARC stopped: " << stop_reason; |
| 140 arc_session_->RemoveObserver(this); | 160 arc_session_->RemoveObserver(this); |
| 141 arc_session_.reset(); | 161 arc_session_.reset(); |
| 162 | |
| 163 // If READY, ARC instance is unexpectedly crashed so we need to restart it | |
|
Luis Héctor Chávez
2016/12/16 23:02:13
nit: "ARC instance unexpectedly crashed".
hidehiko
2016/12/19 07:41:21
Done.
| |
| 164 // automatically. If STOPPING, it is the result of consecutive RequestStop() | |
| 165 // followed by RequestStart() invocation. | |
| 166 // If CONNECTING, ARC instance has not been booted properly, so do not | |
| 167 // restart it automatically. | |
| 168 if (session_started_ && | |
|
Luis Héctor Chávez
2016/12/16 23:02:13
In the same spirit as we did reset |reconnect_|, s
hidehiko
2016/12/19 07:41:21
IIUC, unlike |reconnect_|, |session_started_| shou
Luis Héctor Chávez
2016/12/19 22:23:38
I like the proposed condition much better, since i
hidehiko
2016/12/20 13:38:02
Sure, done. Just in case, could you take another l
| |
| 169 (state() == State::READY || state() == State::STOPPING)) { | |
| 170 // There was a previous invocation and it crashed for some reason. Try | |
| 171 // starting ARC instance later again. | |
| 172 // Note that even |restart_delay_| is 0 (for testing), it needs to | |
| 173 // PostTask, because observer callback may call RequestStart()/Stop(), | |
| 174 // which can change restarting. | |
| 175 VLOG(0) << "ARC restarting"; | |
| 176 restart_timer_.Start(FROM_HERE, restart_delay_, | |
| 177 base::Bind(&ArcBridgeServiceImpl::StartArcSession, | |
| 178 weak_factory_.GetWeakPtr())); | |
| 179 } | |
| 180 | |
| 142 SetStopReason(stop_reason); | 181 SetStopReason(stop_reason); |
| 143 SetState(State::STOPPED); | 182 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 } | 183 } |
| 164 | 184 |
| 165 } // namespace arc | 185 } // namespace arc |
| OLD | NEW |