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_bootstrap.h" | 5 #include "components/arc/arc_bridge_bootstrap.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <grp.h> | 8 #include <grp.h> |
9 #include <unistd.h> | 9 #include <unistd.h> |
10 | 10 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 // STOPPED | 66 // STOPPED |
67 // Start() -> | 67 // Start() -> |
68 // SOCKET_CREATING | 68 // SOCKET_CREATING |
69 // CreateSocket() -> OnSocketCreated() -> | 69 // CreateSocket() -> OnSocketCreated() -> |
70 // STARTING | 70 // STARTING |
71 // StartArcInstance() -> OnInstanceStarted() -> | 71 // StartArcInstance() -> OnInstanceStarted() -> |
72 // STARTED | 72 // STARTED |
73 // AcceptInstanceConnection() -> OnInstanceConnected() -> | 73 // AcceptInstanceConnection() -> OnInstanceConnected() -> |
74 // READY | 74 // READY |
75 // | 75 // |
76 // When Stop() is called from any state, either because an operation | 76 // When Stop() or AbortBoot() is called from any state, either because an |
77 // resulted in an error or because the user is logging out: | 77 // operation resulted in an error or because the user is logging out: |
78 // | 78 // |
79 // (any) | 79 // (any) |
80 // Stop() -> | 80 // Stop()/AbortBoot() -> |
81 // STOPPING | 81 // STOPPING |
82 // StopInstance() -> | 82 // StopInstance() -> |
83 // STOPPED | 83 // STOPPED |
84 // | 84 // |
85 // When the instance crashes while it was ready, it will be stopped: | 85 // When the instance crashes while it was ready, it will be stopped: |
86 // READY -> STOPPING -> STOPPED | 86 // READY -> STOPPING -> STOPPED |
87 // and then restarted: | 87 // and then restarted: |
88 // STOPPED -> SOCKET_CREATING -> ... -> READY). | 88 // STOPPED -> SOCKET_CREATING -> ... -> READY). |
| 89 // |
| 90 // Note: Order of constants below matters. Please make sure to sort them |
| 91 // in chronological order. |
89 enum class State { | 92 enum class State { |
90 // ARC is not currently running. | 93 // ARC is not currently running. |
91 STOPPED, | 94 STOPPED, |
92 | 95 |
93 // An UNIX socket is being created. | 96 // An UNIX socket is being created. |
94 SOCKET_CREATING, | 97 SOCKET_CREATING, |
95 | 98 |
96 // The request to start the instance has been sent. | 99 // The request to start the instance has been sent. |
97 STARTING, | 100 STARTING, |
98 | 101 |
99 // The instance has started. Waiting for it to connect to the IPC bridge. | 102 // The instance has started. Waiting for it to connect to the IPC bridge. |
100 STARTED, | 103 STARTED, |
101 | 104 |
102 // The instance is fully connected. | 105 // The instance is fully connected. |
103 READY, | 106 READY, |
104 | 107 |
105 // The request to shut down the instance has been sent. | 108 // The request to shut down the instance has been sent. |
106 STOPPING, | 109 STOPPING, |
107 }; | 110 }; |
108 | 111 |
109 ArcBridgeBootstrapImpl(); | 112 ArcBridgeBootstrapImpl(); |
110 ~ArcBridgeBootstrapImpl() override; | 113 ~ArcBridgeBootstrapImpl() override; |
111 | 114 |
112 // ArcBridgeBootstrap: | 115 // ArcBridgeBootstrap: |
113 void Start() override; | 116 void Start() override; |
114 void Stop() override; | 117 void Stop() override; |
115 | 118 |
116 private: | 119 private: |
| 120 // Aborts ARC instance boot. This is called from various state-machine |
| 121 // functions when they encounter an error during boot. |
| 122 void AbortBoot(ArcBridgeService::StopReason reason); |
| 123 |
117 // Creates the UNIX socket on the bootstrap thread and then processes its | 124 // Creates the UNIX socket on the bootstrap thread and then processes its |
118 // file descriptor. | 125 // file descriptor. |
119 static base::ScopedFD CreateSocket(); | 126 static base::ScopedFD CreateSocket(); |
120 void OnSocketCreated(base::ScopedFD fd); | 127 void OnSocketCreated(base::ScopedFD fd); |
121 | 128 |
122 // Synchronously accepts a connection on |socket_fd| and then processes the | 129 // Synchronously accepts a connection on |socket_fd| and then processes the |
123 // connected socket's file descriptor. | 130 // connected socket's file descriptor. |
124 static base::ScopedFD AcceptInstanceConnection(base::ScopedFD socket_fd); | 131 static base::ScopedFD AcceptInstanceConnection(base::ScopedFD socket_fd); |
125 void OnInstanceConnected(base::ScopedFD fd); | 132 void OnInstanceConnected(base::ScopedFD fd); |
126 | 133 |
127 void SetState(State state); | 134 void SetState(State state); |
128 | 135 |
129 // DBus callbacks. | 136 // DBus callbacks. |
130 void OnInstanceStarted(base::ScopedFD socket_fd, bool success); | 137 void OnInstanceStarted(base::ScopedFD socket_fd, bool success); |
131 | 138 |
132 // chromeos::SessionManagerClient::Observer: | 139 // chromeos::SessionManagerClient::Observer: |
133 void ArcInstanceStopped(bool clean) override; | 140 void ArcInstanceStopped(bool clean) override; |
134 | 141 |
135 // The state of the bootstrap connection. | 142 // The state of the bootstrap connection. |
136 State state_ = State::STOPPED; | 143 State state_ = State::STOPPED; |
137 | 144 |
| 145 // The reason the ARC instance is stopped. |
| 146 ArcBridgeService::StopReason stop_reason_ = |
| 147 ArcBridgeService::StopReason::SHUTDOWN; |
| 148 |
138 base::ThreadChecker thread_checker_; | 149 base::ThreadChecker thread_checker_; |
139 | 150 |
140 // WeakPtrFactory to use callbacks. | 151 // WeakPtrFactory to use callbacks. |
141 base::WeakPtrFactory<ArcBridgeBootstrapImpl> weak_factory_; | 152 base::WeakPtrFactory<ArcBridgeBootstrapImpl> weak_factory_; |
142 | 153 |
143 private: | 154 private: |
144 DISALLOW_COPY_AND_ASSIGN(ArcBridgeBootstrapImpl); | 155 DISALLOW_COPY_AND_ASSIGN(ArcBridgeBootstrapImpl); |
145 }; | 156 }; |
146 | 157 |
147 ArcBridgeBootstrapImpl::ArcBridgeBootstrapImpl() | 158 ArcBridgeBootstrapImpl::ArcBridgeBootstrapImpl() |
(...skipping 13 matching lines...) Expand all Loading... |
161 client->RemoveObserver(this); | 172 client->RemoveObserver(this); |
162 } | 173 } |
163 | 174 |
164 void ArcBridgeBootstrapImpl::Start() { | 175 void ArcBridgeBootstrapImpl::Start() { |
165 DCHECK(thread_checker_.CalledOnValidThread()); | 176 DCHECK(thread_checker_.CalledOnValidThread()); |
166 DCHECK(delegate_); | 177 DCHECK(delegate_); |
167 if (state_ != State::STOPPED) { | 178 if (state_ != State::STOPPED) { |
168 VLOG(1) << "Start() called when instance is not stopped"; | 179 VLOG(1) << "Start() called when instance is not stopped"; |
169 return; | 180 return; |
170 } | 181 } |
| 182 stop_reason_ = ArcBridgeService::StopReason::SHUTDOWN; |
171 SetState(State::SOCKET_CREATING); | 183 SetState(State::SOCKET_CREATING); |
172 base::PostTaskAndReplyWithResult( | 184 base::PostTaskAndReplyWithResult( |
173 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, | 185 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, |
174 base::Bind(&ArcBridgeBootstrapImpl::CreateSocket), | 186 base::Bind(&ArcBridgeBootstrapImpl::CreateSocket), |
175 base::Bind(&ArcBridgeBootstrapImpl::OnSocketCreated, | 187 base::Bind(&ArcBridgeBootstrapImpl::OnSocketCreated, |
176 weak_factory_.GetWeakPtr())); | 188 weak_factory_.GetWeakPtr())); |
177 } | 189 } |
178 | 190 |
179 // static | 191 // static |
180 base::ScopedFD ArcBridgeBootstrapImpl::CreateSocket() { | 192 base::ScopedFD ArcBridgeBootstrapImpl::CreateSocket() { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) { | 241 void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) { |
230 DCHECK(thread_checker_.CalledOnValidThread()); | 242 DCHECK(thread_checker_.CalledOnValidThread()); |
231 if (state_ != State::SOCKET_CREATING) { | 243 if (state_ != State::SOCKET_CREATING) { |
232 VLOG(1) << "Stop() called while connecting"; | 244 VLOG(1) << "Stop() called while connecting"; |
233 return; | 245 return; |
234 } | 246 } |
235 SetState(State::STARTING); | 247 SetState(State::STARTING); |
236 | 248 |
237 if (!socket_fd.is_valid()) { | 249 if (!socket_fd.is_valid()) { |
238 LOG(ERROR) << "ARC: Error creating socket"; | 250 LOG(ERROR) << "ARC: Error creating socket"; |
239 Stop(); | 251 AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE); |
240 return; | 252 return; |
241 } | 253 } |
242 | 254 |
243 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); | 255 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); |
244 DCHECK(user_manager->GetPrimaryUser()); | 256 DCHECK(user_manager->GetPrimaryUser()); |
245 const cryptohome::Identification cryptohome_id( | 257 const cryptohome::Identification cryptohome_id( |
246 user_manager->GetPrimaryUser()->GetAccountId()); | 258 user_manager->GetPrimaryUser()->GetAccountId()); |
247 | 259 |
248 chromeos::SessionManagerClient* session_manager_client = | 260 chromeos::SessionManagerClient* session_manager_client = |
249 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); | 261 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); |
250 session_manager_client->StartArcInstance( | 262 session_manager_client->StartArcInstance( |
251 cryptohome_id, | 263 cryptohome_id, |
252 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted, | 264 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted, |
253 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); | 265 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); |
254 } | 266 } |
255 | 267 |
256 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, | 268 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, |
257 bool success) { | 269 bool success) { |
258 DCHECK(thread_checker_.CalledOnValidThread()); | 270 DCHECK(thread_checker_.CalledOnValidThread()); |
259 if (!success) { | 271 if (!success) { |
260 LOG(ERROR) << "Failed to start ARC instance"; | 272 LOG(ERROR) << "Failed to start ARC instance"; |
261 // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal | 273 // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal |
262 // to stop the failed instance. | 274 // to stop the failed instance. |
263 SetState(State::SOCKET_CREATING); | 275 SetState(State::SOCKET_CREATING); |
264 Stop(); | 276 AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE); |
265 return; | 277 return; |
266 } | 278 } |
267 if (state_ != State::STARTING) { | 279 if (state_ != State::STARTING) { |
268 VLOG(1) << "Stop() called when ARC is not running"; | 280 VLOG(1) << "Stop() called when ARC is not running"; |
269 return; | 281 return; |
270 } | 282 } |
271 SetState(State::STARTED); | 283 SetState(State::STARTED); |
272 | 284 |
273 base::PostTaskAndReplyWithResult( | 285 base::PostTaskAndReplyWithResult( |
274 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, | 286 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 } | 323 } |
312 | 324 |
313 void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) { | 325 void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) { |
314 DCHECK(thread_checker_.CalledOnValidThread()); | 326 DCHECK(thread_checker_.CalledOnValidThread()); |
315 if (state_ != State::STARTED) { | 327 if (state_ != State::STARTED) { |
316 VLOG(1) << "Stop() called when ARC is not running"; | 328 VLOG(1) << "Stop() called when ARC is not running"; |
317 return; | 329 return; |
318 } | 330 } |
319 if (!fd.is_valid()) { | 331 if (!fd.is_valid()) { |
320 LOG(ERROR) << "Invalid handle"; | 332 LOG(ERROR) << "Invalid handle"; |
| 333 AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE); |
321 return; | 334 return; |
322 } | 335 } |
323 mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe( | 336 mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe( |
324 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release()))); | 337 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release()))); |
325 if (!server_pipe.is_valid()) { | 338 if (!server_pipe.is_valid()) { |
326 LOG(ERROR) << "Invalid pipe"; | 339 LOG(ERROR) << "Invalid pipe"; |
| 340 AbortBoot(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE); |
327 return; | 341 return; |
328 } | 342 } |
329 SetState(State::READY); | 343 SetState(State::READY); |
330 mojom::ArcBridgeInstancePtr instance; | 344 mojom::ArcBridgeInstancePtr instance; |
331 instance.Bind(mojo::InterfacePtrInfo<mojom::ArcBridgeInstance>( | 345 instance.Bind(mojo::InterfacePtrInfo<mojom::ArcBridgeInstance>( |
332 std::move(server_pipe), 0u)); | 346 std::move(server_pipe), 0u)); |
333 delegate_->OnConnectionEstablished(std::move(instance)); | 347 delegate_->OnConnectionEstablished(std::move(instance)); |
334 } | 348 } |
335 | 349 |
336 void ArcBridgeBootstrapImpl::Stop() { | 350 void ArcBridgeBootstrapImpl::Stop() { |
337 DCHECK(thread_checker_.CalledOnValidThread()); | 351 DCHECK(thread_checker_.CalledOnValidThread()); |
338 if (state_ == State::STOPPED || state_ == State::STOPPING) { | 352 if (state_ == State::STOPPED || state_ == State::STOPPING) { |
339 VLOG(1) << "Stop() called when ARC is not running"; | 353 VLOG(1) << "Stop() called when ARC is not running"; |
340 return; | 354 return; |
341 } | 355 } |
342 if (state_ == State::SOCKET_CREATING) { | 356 if (state_ < State::STARTING) { |
343 // This was stopped before the D-Bus command to start the instance. Skip | 357 // This was stopped before the D-Bus command to start the instance. Skip |
344 // the D-Bus command to stop it. | 358 // the D-Bus command to stop it. |
345 SetState(State::STOPPING); | 359 SetState(State::STOPPED); |
346 ArcInstanceStopped(true); | |
347 return; | 360 return; |
348 } | 361 } |
349 SetState(State::STOPPING); | 362 SetState(State::STOPPING); |
350 // Notification will arrive through ArcInstanceStopped(). | 363 // Notification will arrive through ArcInstanceStopped(). |
351 chromeos::SessionManagerClient* session_manager_client = | 364 chromeos::SessionManagerClient* session_manager_client = |
352 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); | 365 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); |
353 session_manager_client->StopArcInstance( | 366 session_manager_client->StopArcInstance( |
354 base::Bind(&DoNothingInstanceStopped)); | 367 base::Bind(&DoNothingInstanceStopped)); |
355 } | 368 } |
356 | 369 |
| 370 void ArcBridgeBootstrapImpl::AbortBoot(ArcBridgeService::StopReason reason) { |
| 371 DCHECK(thread_checker_.CalledOnValidThread()); |
| 372 DCHECK(reason != ArcBridgeService::StopReason::SHUTDOWN); |
| 373 // In case of multiple errors, report the first one. |
| 374 if (stop_reason_ == ArcBridgeService::StopReason::SHUTDOWN) { |
| 375 stop_reason_ = reason; |
| 376 } |
| 377 Stop(); |
| 378 } |
| 379 |
357 void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) { | 380 void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) { |
358 DCHECK(thread_checker_.CalledOnValidThread()); | 381 DCHECK(thread_checker_.CalledOnValidThread()); |
359 if (!clean) | 382 if (!clean) { |
360 LOG(ERROR) << "ARC instance crashed"; | 383 LOG(ERROR) << "ARC instance crashed"; |
361 DCHECK(delegate_); | 384 // In case of multiple errors, report the first one. |
| 385 if (stop_reason_ == ArcBridgeService::StopReason::SHUTDOWN) { |
| 386 stop_reason_ = ArcBridgeService::StopReason::CRASH; |
| 387 } |
| 388 } |
362 SetState(State::STOPPED); | 389 SetState(State::STOPPED); |
363 delegate_->OnStopped(); | |
364 } | 390 } |
365 | 391 |
366 void ArcBridgeBootstrapImpl::SetState(State state) { | 392 void ArcBridgeBootstrapImpl::SetState(State state) { |
367 DCHECK(thread_checker_.CalledOnValidThread()); | 393 DCHECK(thread_checker_.CalledOnValidThread()); |
368 // DCHECK on enum classes not supported. | 394 // DCHECK on enum classes not supported. |
369 DCHECK(state_ != state); | 395 DCHECK(state_ != state); |
370 state_ = state; | 396 state_ = state; |
371 VLOG(2) << "State: " << static_cast<uint32_t>(state_); | 397 VLOG(2) << "State: " << static_cast<uint32_t>(state_); |
| 398 if (state_ == State::STOPPED) { |
| 399 DCHECK(delegate_); |
| 400 delegate_->OnStopped(stop_reason_); |
| 401 } |
372 } | 402 } |
373 | 403 |
374 } // namespace | 404 } // namespace |
375 | 405 |
376 // static | 406 // static |
377 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() { | 407 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() { |
378 return base::WrapUnique(new ArcBridgeBootstrapImpl()); | 408 return base::WrapUnique(new ArcBridgeBootstrapImpl()); |
379 } | 409 } |
380 | 410 |
381 } // namespace arc | 411 } // namespace arc |
OLD | NEW |