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(AbortReason 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 |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) { | 236 void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) { |
230 DCHECK(thread_checker_.CalledOnValidThread()); | 237 DCHECK(thread_checker_.CalledOnValidThread()); |
231 if (state_ != State::SOCKET_CREATING) { | 238 if (state_ != State::SOCKET_CREATING) { |
232 VLOG(1) << "Stop() called while connecting"; | 239 VLOG(1) << "Stop() called while connecting"; |
233 return; | 240 return; |
234 } | 241 } |
235 SetState(State::STARTING); | 242 SetState(State::STARTING); |
236 | 243 |
237 if (!socket_fd.is_valid()) { | 244 if (!socket_fd.is_valid()) { |
238 LOG(ERROR) << "ARC: Error creating socket"; | 245 LOG(ERROR) << "ARC: Error creating socket"; |
239 Stop(); | 246 AbortBoot(AbortReason::GENERIC_BOOT_FAILURE); |
240 return; | 247 return; |
241 } | 248 } |
242 | 249 |
243 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); | 250 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); |
244 DCHECK(user_manager->GetPrimaryUser()); | 251 DCHECK(user_manager->GetPrimaryUser()); |
245 const cryptohome::Identification cryptohome_id( | 252 const cryptohome::Identification cryptohome_id( |
246 user_manager->GetPrimaryUser()->GetAccountId()); | 253 user_manager->GetPrimaryUser()->GetAccountId()); |
247 | 254 |
248 chromeos::SessionManagerClient* session_manager_client = | 255 chromeos::SessionManagerClient* session_manager_client = |
249 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); | 256 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); |
250 session_manager_client->StartArcInstance( | 257 session_manager_client->StartArcInstance( |
251 cryptohome_id, | 258 cryptohome_id, |
252 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted, | 259 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted, |
253 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); | 260 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); |
254 } | 261 } |
255 | 262 |
256 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, | 263 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, |
257 bool success) { | 264 bool success) { |
258 DCHECK(thread_checker_.CalledOnValidThread()); | 265 DCHECK(thread_checker_.CalledOnValidThread()); |
259 if (!success) { | 266 if (!success) { |
260 LOG(ERROR) << "Failed to start ARC instance"; | 267 LOG(ERROR) << "Failed to start ARC instance"; |
261 // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal | 268 // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal |
262 // to stop the failed instance. | 269 // to stop the failed instance. |
263 SetState(State::SOCKET_CREATING); | 270 SetState(State::SOCKET_CREATING); |
264 Stop(); | 271 AbortBoot(AbortReason::GENERIC_BOOT_FAILURE); |
265 return; | 272 return; |
266 } | 273 } |
267 if (state_ != State::STARTING) { | 274 if (state_ != State::STARTING) { |
268 VLOG(1) << "Stop() called when ARC is not running"; | 275 VLOG(1) << "Stop() called when ARC is not running"; |
269 return; | 276 return; |
270 } | 277 } |
271 SetState(State::STARTED); | 278 SetState(State::STARTED); |
272 | 279 |
273 base::PostTaskAndReplyWithResult( | 280 base::PostTaskAndReplyWithResult( |
274 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, | 281 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 } | 318 } |
312 | 319 |
313 void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) { | 320 void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) { |
314 DCHECK(thread_checker_.CalledOnValidThread()); | 321 DCHECK(thread_checker_.CalledOnValidThread()); |
315 if (state_ != State::STARTED) { | 322 if (state_ != State::STARTED) { |
316 VLOG(1) << "Stop() called when ARC is not running"; | 323 VLOG(1) << "Stop() called when ARC is not running"; |
317 return; | 324 return; |
318 } | 325 } |
319 if (!fd.is_valid()) { | 326 if (!fd.is_valid()) { |
320 LOG(ERROR) << "Invalid handle"; | 327 LOG(ERROR) << "Invalid handle"; |
| 328 AbortBoot(AbortReason::GENERIC_BOOT_FAILURE); |
321 return; | 329 return; |
322 } | 330 } |
323 mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe( | 331 mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe( |
324 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release()))); | 332 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release()))); |
325 if (!server_pipe.is_valid()) { | 333 if (!server_pipe.is_valid()) { |
326 LOG(ERROR) << "Invalid pipe"; | 334 LOG(ERROR) << "Invalid pipe"; |
| 335 AbortBoot(AbortReason::GENERIC_BOOT_FAILURE); |
327 return; | 336 return; |
328 } | 337 } |
329 SetState(State::READY); | 338 SetState(State::READY); |
330 mojom::ArcBridgeInstancePtr instance; | 339 mojom::ArcBridgeInstancePtr instance; |
331 instance.Bind(mojo::InterfacePtrInfo<mojom::ArcBridgeInstance>( | 340 instance.Bind(mojo::InterfacePtrInfo<mojom::ArcBridgeInstance>( |
332 std::move(server_pipe), 0u)); | 341 std::move(server_pipe), 0u)); |
333 delegate_->OnConnectionEstablished(std::move(instance)); | 342 delegate_->OnConnectionEstablished(std::move(instance)); |
334 } | 343 } |
335 | 344 |
336 void ArcBridgeBootstrapImpl::Stop() { | 345 void ArcBridgeBootstrapImpl::Stop() { |
337 DCHECK(thread_checker_.CalledOnValidThread()); | 346 DCHECK(thread_checker_.CalledOnValidThread()); |
338 if (state_ == State::STOPPED || state_ == State::STOPPING) { | 347 if (state_ == State::STOPPED || state_ == State::STOPPING) { |
339 VLOG(1) << "Stop() called when ARC is not running"; | 348 VLOG(1) << "Stop() called when ARC is not running"; |
340 return; | 349 return; |
341 } | 350 } |
342 if (state_ == State::SOCKET_CREATING) { | 351 if (state_ < State::STARTING) { |
343 // This was stopped before the D-Bus command to start the instance. Skip | 352 // This was stopped before the D-Bus command to start the instance. Skip |
344 // the D-Bus command to stop it. | 353 // the D-Bus command to stop it. |
345 SetState(State::STOPPING); | 354 SetState(State::STOPPED); |
346 ArcInstanceStopped(true); | |
347 return; | 355 return; |
348 } | 356 } |
349 SetState(State::STOPPING); | 357 SetState(State::STOPPING); |
350 // Notification will arrive through ArcInstanceStopped(). | 358 // Notification will arrive through ArcInstanceStopped(). |
351 chromeos::SessionManagerClient* session_manager_client = | 359 chromeos::SessionManagerClient* session_manager_client = |
352 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); | 360 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); |
353 session_manager_client->StopArcInstance( | 361 session_manager_client->StopArcInstance( |
354 base::Bind(&DoNothingInstanceStopped)); | 362 base::Bind(&DoNothingInstanceStopped)); |
355 } | 363 } |
356 | 364 |
| 365 void ArcBridgeBootstrapImpl::AbortBoot(AbortReason reason) { |
| 366 DCHECK(thread_checker_.CalledOnValidThread()); |
| 367 DCHECK(delegate_); |
| 368 delegate_->OnAborting(reason); |
| 369 Stop(); |
| 370 } |
| 371 |
357 void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) { | 372 void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) { |
358 DCHECK(thread_checker_.CalledOnValidThread()); | 373 DCHECK(thread_checker_.CalledOnValidThread()); |
359 if (!clean) | 374 if (!clean) { |
360 LOG(ERROR) << "ARC instance crashed"; | 375 LOG(ERROR) << "ARC instance crashed"; |
361 DCHECK(delegate_); | 376 DCHECK(delegate_); |
| 377 delegate_->OnAborting(AbortReason::CRASH); |
| 378 } |
362 SetState(State::STOPPED); | 379 SetState(State::STOPPED); |
363 delegate_->OnStopped(); | |
364 } | 380 } |
365 | 381 |
366 void ArcBridgeBootstrapImpl::SetState(State state) { | 382 void ArcBridgeBootstrapImpl::SetState(State state) { |
367 DCHECK(thread_checker_.CalledOnValidThread()); | 383 DCHECK(thread_checker_.CalledOnValidThread()); |
368 // DCHECK on enum classes not supported. | 384 // DCHECK on enum classes not supported. |
369 DCHECK(state_ != state); | 385 DCHECK(state_ != state); |
370 state_ = state; | 386 state_ = state; |
371 VLOG(2) << "State: " << static_cast<uint32_t>(state_); | 387 VLOG(2) << "State: " << static_cast<uint32_t>(state_); |
| 388 if (state_ == State::STOPPED) { |
| 389 DCHECK(delegate_); |
| 390 delegate_->OnStopped(); |
| 391 } |
372 } | 392 } |
373 | 393 |
374 } // namespace | 394 } // namespace |
375 | 395 |
376 // static | 396 // static |
377 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() { | 397 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() { |
378 return base::WrapUnique(new ArcBridgeBootstrapImpl()); | 398 return base::WrapUnique(new ArcBridgeBootstrapImpl()); |
379 } | 399 } |
380 | 400 |
381 } // namespace arc | 401 } // namespace arc |
OLD | NEW |