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 |