| 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(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 StopReason stop_reason_ = StopReason::NO_ERROR; |
| 147 |
| 138 base::ThreadChecker thread_checker_; | 148 base::ThreadChecker thread_checker_; |
| 139 | 149 |
| 140 // WeakPtrFactory to use callbacks. | 150 // WeakPtrFactory to use callbacks. |
| 141 base::WeakPtrFactory<ArcBridgeBootstrapImpl> weak_factory_; | 151 base::WeakPtrFactory<ArcBridgeBootstrapImpl> weak_factory_; |
| 142 | 152 |
| 143 private: | 153 private: |
| 144 DISALLOW_COPY_AND_ASSIGN(ArcBridgeBootstrapImpl); | 154 DISALLOW_COPY_AND_ASSIGN(ArcBridgeBootstrapImpl); |
| 145 }; | 155 }; |
| 146 | 156 |
| 147 ArcBridgeBootstrapImpl::ArcBridgeBootstrapImpl() | 157 ArcBridgeBootstrapImpl::ArcBridgeBootstrapImpl() |
| (...skipping 13 matching lines...) Expand all Loading... |
| 161 client->RemoveObserver(this); | 171 client->RemoveObserver(this); |
| 162 } | 172 } |
| 163 | 173 |
| 164 void ArcBridgeBootstrapImpl::Start() { | 174 void ArcBridgeBootstrapImpl::Start() { |
| 165 DCHECK(thread_checker_.CalledOnValidThread()); | 175 DCHECK(thread_checker_.CalledOnValidThread()); |
| 166 DCHECK(delegate_); | 176 DCHECK(delegate_); |
| 167 if (state_ != State::STOPPED) { | 177 if (state_ != State::STOPPED) { |
| 168 VLOG(1) << "Start() called when instance is not stopped"; | 178 VLOG(1) << "Start() called when instance is not stopped"; |
| 169 return; | 179 return; |
| 170 } | 180 } |
| 181 stop_reason_ = StopReason::NO_ERROR; |
| 171 SetState(State::SOCKET_CREATING); | 182 SetState(State::SOCKET_CREATING); |
| 172 base::PostTaskAndReplyWithResult( | 183 base::PostTaskAndReplyWithResult( |
| 173 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, | 184 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, |
| 174 base::Bind(&ArcBridgeBootstrapImpl::CreateSocket), | 185 base::Bind(&ArcBridgeBootstrapImpl::CreateSocket), |
| 175 base::Bind(&ArcBridgeBootstrapImpl::OnSocketCreated, | 186 base::Bind(&ArcBridgeBootstrapImpl::OnSocketCreated, |
| 176 weak_factory_.GetWeakPtr())); | 187 weak_factory_.GetWeakPtr())); |
| 177 } | 188 } |
| 178 | 189 |
| 179 // static | 190 // static |
| 180 base::ScopedFD ArcBridgeBootstrapImpl::CreateSocket() { | 191 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) { | 240 void ArcBridgeBootstrapImpl::OnSocketCreated(base::ScopedFD socket_fd) { |
| 230 DCHECK(thread_checker_.CalledOnValidThread()); | 241 DCHECK(thread_checker_.CalledOnValidThread()); |
| 231 if (state_ != State::SOCKET_CREATING) { | 242 if (state_ != State::SOCKET_CREATING) { |
| 232 VLOG(1) << "Stop() called while connecting"; | 243 VLOG(1) << "Stop() called while connecting"; |
| 233 return; | 244 return; |
| 234 } | 245 } |
| 235 SetState(State::STARTING); | 246 SetState(State::STARTING); |
| 236 | 247 |
| 237 if (!socket_fd.is_valid()) { | 248 if (!socket_fd.is_valid()) { |
| 238 LOG(ERROR) << "ARC: Error creating socket"; | 249 LOG(ERROR) << "ARC: Error creating socket"; |
| 239 Stop(); | 250 AbortBoot(StopReason::GENERIC_BOOT_FAILURE); |
| 240 return; | 251 return; |
| 241 } | 252 } |
| 242 | 253 |
| 243 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); | 254 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); |
| 244 DCHECK(user_manager->GetPrimaryUser()); | 255 DCHECK(user_manager->GetPrimaryUser()); |
| 245 const cryptohome::Identification cryptohome_id( | 256 const cryptohome::Identification cryptohome_id( |
| 246 user_manager->GetPrimaryUser()->GetAccountId()); | 257 user_manager->GetPrimaryUser()->GetAccountId()); |
| 247 | 258 |
| 248 chromeos::SessionManagerClient* session_manager_client = | 259 chromeos::SessionManagerClient* session_manager_client = |
| 249 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); | 260 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); |
| 250 session_manager_client->StartArcInstance( | 261 session_manager_client->StartArcInstance( |
| 251 cryptohome_id, | 262 cryptohome_id, |
| 252 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted, | 263 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted, |
| 253 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); | 264 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); |
| 254 } | 265 } |
| 255 | 266 |
| 256 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, | 267 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, |
| 257 bool success) { | 268 bool success) { |
| 258 DCHECK(thread_checker_.CalledOnValidThread()); | 269 DCHECK(thread_checker_.CalledOnValidThread()); |
| 259 if (!success) { | 270 if (!success) { |
| 260 LOG(ERROR) << "Failed to start ARC instance"; | 271 LOG(ERROR) << "Failed to start ARC instance"; |
| 261 // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal | 272 // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal |
| 262 // to stop the failed instance. | 273 // to stop the failed instance. |
| 263 SetState(State::SOCKET_CREATING); | 274 SetState(State::SOCKET_CREATING); |
| 264 Stop(); | 275 AbortBoot(StopReason::GENERIC_BOOT_FAILURE); |
| 265 return; | 276 return; |
| 266 } | 277 } |
| 267 if (state_ != State::STARTING) { | 278 if (state_ != State::STARTING) { |
| 268 VLOG(1) << "Stop() called when ARC is not running"; | 279 VLOG(1) << "Stop() called when ARC is not running"; |
| 269 return; | 280 return; |
| 270 } | 281 } |
| 271 SetState(State::STARTED); | 282 SetState(State::STARTED); |
| 272 | 283 |
| 273 base::PostTaskAndReplyWithResult( | 284 base::PostTaskAndReplyWithResult( |
| 274 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, | 285 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 } | 322 } |
| 312 | 323 |
| 313 void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) { | 324 void ArcBridgeBootstrapImpl::OnInstanceConnected(base::ScopedFD fd) { |
| 314 DCHECK(thread_checker_.CalledOnValidThread()); | 325 DCHECK(thread_checker_.CalledOnValidThread()); |
| 315 if (state_ != State::STARTED) { | 326 if (state_ != State::STARTED) { |
| 316 VLOG(1) << "Stop() called when ARC is not running"; | 327 VLOG(1) << "Stop() called when ARC is not running"; |
| 317 return; | 328 return; |
| 318 } | 329 } |
| 319 if (!fd.is_valid()) { | 330 if (!fd.is_valid()) { |
| 320 LOG(ERROR) << "Invalid handle"; | 331 LOG(ERROR) << "Invalid handle"; |
| 332 AbortBoot(StopReason::GENERIC_BOOT_FAILURE); |
| 321 return; | 333 return; |
| 322 } | 334 } |
| 323 mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe( | 335 mojo::ScopedMessagePipeHandle server_pipe = mojo::edk::CreateMessagePipe( |
| 324 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release()))); | 336 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(fd.release()))); |
| 325 if (!server_pipe.is_valid()) { | 337 if (!server_pipe.is_valid()) { |
| 326 LOG(ERROR) << "Invalid pipe"; | 338 LOG(ERROR) << "Invalid pipe"; |
| 339 AbortBoot(StopReason::GENERIC_BOOT_FAILURE); |
| 327 return; | 340 return; |
| 328 } | 341 } |
| 329 SetState(State::READY); | 342 SetState(State::READY); |
| 330 mojom::ArcBridgeInstancePtr instance; | 343 mojom::ArcBridgeInstancePtr instance; |
| 331 instance.Bind(mojo::InterfacePtrInfo<mojom::ArcBridgeInstance>( | 344 instance.Bind(mojo::InterfacePtrInfo<mojom::ArcBridgeInstance>( |
| 332 std::move(server_pipe), 0u)); | 345 std::move(server_pipe), 0u)); |
| 333 delegate_->OnConnectionEstablished(std::move(instance)); | 346 delegate_->OnConnectionEstablished(std::move(instance)); |
| 334 } | 347 } |
| 335 | 348 |
| 336 void ArcBridgeBootstrapImpl::Stop() { | 349 void ArcBridgeBootstrapImpl::Stop() { |
| 337 DCHECK(thread_checker_.CalledOnValidThread()); | 350 DCHECK(thread_checker_.CalledOnValidThread()); |
| 338 if (state_ == State::STOPPED || state_ == State::STOPPING) { | 351 if (state_ == State::STOPPED || state_ == State::STOPPING) { |
| 339 VLOG(1) << "Stop() called when ARC is not running"; | 352 VLOG(1) << "Stop() called when ARC is not running"; |
| 340 return; | 353 return; |
| 341 } | 354 } |
| 342 if (state_ == State::SOCKET_CREATING) { | 355 if (state_ < State::STARTING) { |
| 343 // This was stopped before the D-Bus command to start the instance. Skip | 356 // This was stopped before the D-Bus command to start the instance. Skip |
| 344 // the D-Bus command to stop it. | 357 // the D-Bus command to stop it. |
| 345 SetState(State::STOPPING); | 358 SetState(State::STOPPED); |
| 346 ArcInstanceStopped(true); | |
| 347 return; | 359 return; |
| 348 } | 360 } |
| 349 SetState(State::STOPPING); | 361 SetState(State::STOPPING); |
| 350 // Notification will arrive through ArcInstanceStopped(). | 362 // Notification will arrive through ArcInstanceStopped(). |
| 351 chromeos::SessionManagerClient* session_manager_client = | 363 chromeos::SessionManagerClient* session_manager_client = |
| 352 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); | 364 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); |
| 353 session_manager_client->StopArcInstance( | 365 session_manager_client->StopArcInstance( |
| 354 base::Bind(&DoNothingInstanceStopped)); | 366 base::Bind(&DoNothingInstanceStopped)); |
| 355 } | 367 } |
| 356 | 368 |
| 369 void ArcBridgeBootstrapImpl::AbortBoot(StopReason reason) { |
| 370 DCHECK(thread_checker_.CalledOnValidThread()); |
| 371 DCHECK(reason != StopReason::NO_ERROR); |
| 372 // In case of multiple errors, report the first one. |
| 373 if (stop_reason_ == StopReason::NO_ERROR) { |
| 374 stop_reason_ = reason; |
| 375 } |
| 376 Stop(); |
| 377 } |
| 378 |
| 357 void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) { | 379 void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) { |
| 358 DCHECK(thread_checker_.CalledOnValidThread()); | 380 DCHECK(thread_checker_.CalledOnValidThread()); |
| 359 if (!clean) | 381 if (!clean) { |
| 360 LOG(ERROR) << "ARC instance crashed"; | 382 LOG(ERROR) << "ARC instance crashed"; |
| 361 DCHECK(delegate_); | 383 // In case of multiple errors, report the first one. |
| 384 if (stop_reason_ == StopReason::NO_ERROR) { |
| 385 stop_reason_ = StopReason::CRASH; |
| 386 } |
| 387 } |
| 362 SetState(State::STOPPED); | 388 SetState(State::STOPPED); |
| 363 delegate_->OnStopped(); | |
| 364 } | 389 } |
| 365 | 390 |
| 366 void ArcBridgeBootstrapImpl::SetState(State state) { | 391 void ArcBridgeBootstrapImpl::SetState(State state) { |
| 367 DCHECK(thread_checker_.CalledOnValidThread()); | 392 DCHECK(thread_checker_.CalledOnValidThread()); |
| 368 // DCHECK on enum classes not supported. | 393 // DCHECK on enum classes not supported. |
| 369 DCHECK(state_ != state); | 394 DCHECK(state_ != state); |
| 370 state_ = state; | 395 state_ = state; |
| 371 VLOG(2) << "State: " << static_cast<uint32_t>(state_); | 396 VLOG(2) << "State: " << static_cast<uint32_t>(state_); |
| 397 if (state_ == State::STOPPED) { |
| 398 DCHECK(delegate_); |
| 399 delegate_->OnStopped(stop_reason_); |
| 400 } |
| 372 } | 401 } |
| 373 | 402 |
| 374 } // namespace | 403 } // namespace |
| 375 | 404 |
| 376 // static | 405 // static |
| 377 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() { | 406 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() { |
| 378 return base::WrapUnique(new ArcBridgeBootstrapImpl()); | 407 return base::WrapUnique(new ArcBridgeBootstrapImpl()); |
| 379 } | 408 } |
| 380 | 409 |
| 381 } // namespace arc | 410 } // namespace arc |
| OLD | NEW |