| 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 |