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 |