Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(836)

Side by Side Diff: components/arc/arc_bridge_bootstrap.cc

Issue 2397863003: Move free disk space check to session_manager. (Closed)
Patch Set: Address comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chromeos/dbus/session_manager_client.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <poll.h> 9 #include <poll.h>
10 #include <unistd.h> 10 #include <unistd.h>
(...skipping 23 matching lines...) Expand all
34 #include "mojo/edk/embedder/platform_channel_pair.h" 34 #include "mojo/edk/embedder/platform_channel_pair.h"
35 #include "mojo/edk/embedder/platform_channel_utils_posix.h" 35 #include "mojo/edk/embedder/platform_channel_utils_posix.h"
36 #include "mojo/edk/embedder/platform_handle_vector.h" 36 #include "mojo/edk/embedder/platform_handle_vector.h"
37 #include "mojo/edk/embedder/scoped_platform_handle.h" 37 #include "mojo/edk/embedder/scoped_platform_handle.h"
38 #include "mojo/public/cpp/bindings/binding.h" 38 #include "mojo/public/cpp/bindings/binding.h"
39 39
40 namespace arc { 40 namespace arc {
41 41
42 namespace { 42 namespace {
43 43
44 using StartArcInstanceResult =
45 chromeos::SessionManagerClient::StartArcInstanceResult;
46
44 const base::FilePath::CharType kArcBridgeSocketPath[] = 47 const base::FilePath::CharType kArcBridgeSocketPath[] =
45 FILE_PATH_LITERAL("/var/run/chrome/arc_bridge.sock"); 48 FILE_PATH_LITERAL("/var/run/chrome/arc_bridge.sock");
46 49
47 const char kArcBridgeSocketGroup[] = "arc-bridge"; 50 const char kArcBridgeSocketGroup[] = "arc-bridge";
48 51
49 const base::FilePath::CharType kDiskCheckPath[] = "/home";
50
51 const int64_t kCriticalDiskFreeBytes = 64 << 20; // 64MB
52
53 // This is called when StopArcInstance D-Bus method completes. Since we have the 52 // This is called when StopArcInstance D-Bus method completes. Since we have the
54 // ArcInstanceStopped() callback and are notified if StartArcInstance fails, we 53 // ArcInstanceStopped() callback and are notified if StartArcInstance fails, we
55 // don't need to do anything when StopArcInstance completes. 54 // don't need to do anything when StopArcInstance completes.
56 void DoNothingInstanceStopped(bool) {} 55 void DoNothingInstanceStopped(bool) {}
57 56
58 chromeos::SessionManagerClient* GetSessionManagerClient() { 57 chromeos::SessionManagerClient* GetSessionManagerClient() {
59 // If the DBusThreadManager or the SessionManagerClient aren't available, 58 // If the DBusThreadManager or the SessionManagerClient aren't available,
60 // there isn't much we can do. This should only happen when running tests. 59 // there isn't much we can do. This should only happen when running tests.
61 if (!chromeos::DBusThreadManager::IsInitialized() || 60 if (!chromeos::DBusThreadManager::IsInitialized() ||
62 !chromeos::DBusThreadManager::Get() || 61 !chromeos::DBusThreadManager::Get() ||
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 // TODO(hidehiko): Refactor more to make this class unittest-able, for at least 107 // TODO(hidehiko): Refactor more to make this class unittest-able, for at least
109 // state-machine part. 108 // state-machine part.
110 class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap, 109 class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
111 public chromeos::SessionManagerClient::Observer { 110 public chromeos::SessionManagerClient::Observer {
112 public: 111 public:
113 // The possible states of the bootstrap connection. In the normal flow, 112 // The possible states of the bootstrap connection. In the normal flow,
114 // the state changes in the following sequence: 113 // the state changes in the following sequence:
115 // 114 //
116 // NOT_STARTED 115 // NOT_STARTED
117 // Start() -> 116 // Start() ->
118 // CHECKING_DISK_SPACE
119 // OnDiskSpaceChecked() ->
120 // CREATING_SOCKET 117 // CREATING_SOCKET
121 // CreateSocket() -> OnSocketCreated() -> 118 // CreateSocket() -> OnSocketCreated() ->
122 // STARTING_INSTANCE 119 // STARTING_INSTANCE
123 // -> OnInstanceStarted() -> 120 // -> OnInstanceStarted() ->
124 // CONNECTING_MOJO 121 // CONNECTING_MOJO
125 // ConnectMojo() -> OnMojoConnected() -> 122 // ConnectMojo() -> OnMojoConnected() ->
126 // RUNNING 123 // RUNNING
127 // 124 //
128 // At any state, Stop() can be called. It does not immediately stop the 125 // At any state, Stop() can be called. It does not immediately stop the
129 // instance, but will eventually stop it. 126 // instance, but will eventually stop it.
130 // The actual stop will be notified via Observer::OnStopped(). 127 // The actual stop will be notified via Observer::OnStopped().
131 // 128 //
132 // When Stop() is called, it makes various behavior based on the current 129 // When Stop() is called, it makes various behavior based on the current
133 // phase. 130 // phase.
134 // 131 //
135 // NOT_STARTED: 132 // NOT_STARTED:
136 // Do nothing. Immediately transition to the STOPPED state. 133 // Do nothing. Immediately transition to the STOPPED state.
137 // CHECKING_DISK_SPACE, CREATING_SOCKET: 134 // CREATING_SOCKET:
138 // The main task of those phases runs on WorkerPool thread. So, Stop() 135 // The main task of the phase runs on WorkerPool thread. So, Stop() just
139 // just sets the flag and return. On the main task completion, a callback 136 // sets the flag and return. On the main task completion, a callback
140 // will run on the main (practically UI) thread, and the flag is checked 137 // will run on the main (practically UI) thread, and the flag is checked
141 // at the beginning of them. This should work under the assumption that 138 // at the beginning of them. This should work under the assumption that
142 // the main tasks do not block indefinitely. 139 // the main tasks do not block indefinitely.
143 // STARTING_INSTANCE: 140 // STARTING_INSTANCE:
144 // The ARC instance is starting via SessionManager. So, similar to 141 // The ARC instance is starting via SessionManager. So, similar to
145 // CHECKING_DISK_SPACE/CREATING_SOCKET cases, Stop() just sets the flag 142 // CREATING_SOCKET case, Stop() just sets the flag and return. In its
146 // and return. In its callback, it checks if ARC instance is successfully 143 // callback, it checks if ARC instance is successfully started or not.
147 // started or not. In case of success, a request to stop the ARC instance 144 // In case of success, a request to stop the ARC instance is sent to
148 // is sent to SessionManager. Its completion will be notified via 145 // SessionManager. Its completion will be notified via ArcInstanceStopped.
149 // ArcInstanceStopped. Otherwise, it just turns into STOPPED state. 146 // Otherwise, it just turns into STOPPED state.
150 // CONNECTING_MOJO: 147 // CONNECTING_MOJO:
151 // The main task runs on WorkerPool thread, but it is blocking call. 148 // The main task runs on WorkerPool thread, but it is blocking call.
152 // So, Stop() sends a request to cancel the blocking by closing the pipe 149 // So, Stop() sends a request to cancel the blocking by closing the pipe
153 // whose read side is also polled. Then, in its callback, similar to 150 // whose read side is also polled. Then, in its callback, similar to
154 // STARTING_INSTANCE, a request to stop the ARC instance is sent to 151 // STARTING_INSTANCE, a request to stop the ARC instance is sent to
155 // SessionManager, and ArcInstanceStopped handles remaining procedure. 152 // SessionManager, and ArcInstanceStopped handles remaining procedure.
156 // RUNNING: 153 // RUNNING:
157 // There is no more callback which runs on normal flow, so Stop() requests 154 // There is no more callback which runs on normal flow, so Stop() requests
158 // to stop the ARC instance via SessionManager. 155 // to stop the ARC instance via SessionManager.
159 // 156 //
(...skipping 19 matching lines...) Expand all
179 // Specifically, in STOPPED state, there may be inflight operations or 176 // Specifically, in STOPPED state, there may be inflight operations or
180 // pending callbacks. Though, what they do is just do-nothing conceptually 177 // pending callbacks. Though, what they do is just do-nothing conceptually
181 // and they can be safely ignored. 178 // and they can be safely ignored.
182 // 179 //
183 // Note: Order of constants below matters. Please make sure to sort them 180 // Note: Order of constants below matters. Please make sure to sort them
184 // in chronological order. 181 // in chronological order.
185 enum class State { 182 enum class State {
186 // ARC is not yet started. 183 // ARC is not yet started.
187 NOT_STARTED, 184 NOT_STARTED,
188 185
189 // Checking the disk space.
190 CHECKING_DISK_SPACE,
191
192 // An UNIX socket is being created. 186 // An UNIX socket is being created.
193 CREATING_SOCKET, 187 CREATING_SOCKET,
194 188
195 // The request to start the instance has been sent. 189 // The request to start the instance has been sent.
196 STARTING_INSTANCE, 190 STARTING_INSTANCE,
197 191
198 // The instance has started. Waiting for it to connect to the IPC bridge. 192 // The instance has started. Waiting for it to connect to the IPC bridge.
199 CONNECTING_MOJO, 193 CONNECTING_MOJO,
200 194
201 // The instance is fully set up. 195 // The instance is fully set up.
202 RUNNING, 196 RUNNING,
203 197
204 // ARC is terminated. 198 // ARC is terminated.
205 STOPPED, 199 STOPPED,
206 }; 200 };
207 201
208 ArcBridgeBootstrapImpl(); 202 ArcBridgeBootstrapImpl();
209 ~ArcBridgeBootstrapImpl() override; 203 ~ArcBridgeBootstrapImpl() override;
210 204
211 // ArcBridgeBootstrap: 205 // ArcBridgeBootstrap:
212 void Start() override; 206 void Start() override;
213 void Stop() override; 207 void Stop() override;
214 208
215 private: 209 private:
216 // Called after getting the device free disk space.
217 void OnFreeDiskSpaceObtained(int64_t disk_free_bytes);
218
219 // Creates the UNIX socket on the bootstrap thread and then processes its 210 // Creates the UNIX socket on the bootstrap thread and then processes its
220 // file descriptor. 211 // file descriptor.
221 static base::ScopedFD CreateSocket(); 212 static base::ScopedFD CreateSocket();
222 void OnSocketCreated(base::ScopedFD fd); 213 void OnSocketCreated(base::ScopedFD fd);
223 214
224 // DBus callback for StartArcInstance(). 215 // DBus callback for StartArcInstance().
225 void OnInstanceStarted(base::ScopedFD socket_fd, bool success); 216 void OnInstanceStarted(base::ScopedFD socket_fd,
217 StartArcInstanceResult result);
226 218
227 // Synchronously accepts a connection on |socket_fd| and then processes the 219 // Synchronously accepts a connection on |socket_fd| and then processes the
228 // connected socket's file descriptor. 220 // connected socket's file descriptor.
229 static base::ScopedFD ConnectMojo(base::ScopedFD socket_fd, 221 static base::ScopedFD ConnectMojo(base::ScopedFD socket_fd,
230 base::ScopedFD cancel_fd); 222 base::ScopedFD cancel_fd);
231 void OnMojoConnected(base::ScopedFD fd); 223 void OnMojoConnected(base::ScopedFD fd);
232 224
233 // Request to stop ARC instance via DBus. 225 // Request to stop ARC instance via DBus.
234 void StopArcInstance(); 226 void StopArcInstance();
235 227
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 chromeos::SessionManagerClient* client = GetSessionManagerClient(); 268 chromeos::SessionManagerClient* client = GetSessionManagerClient();
277 if (client == nullptr) 269 if (client == nullptr)
278 return; 270 return;
279 client->RemoveObserver(this); 271 client->RemoveObserver(this);
280 } 272 }
281 273
282 void ArcBridgeBootstrapImpl::Start() { 274 void ArcBridgeBootstrapImpl::Start() {
283 DCHECK(thread_checker_.CalledOnValidThread()); 275 DCHECK(thread_checker_.CalledOnValidThread());
284 DCHECK_EQ(state_, State::NOT_STARTED); 276 DCHECK_EQ(state_, State::NOT_STARTED);
285 VLOG(2) << "Starting ARC session."; 277 VLOG(2) << "Starting ARC session.";
286 VLOG(2) << "Checking disk space..."; 278 VLOG(2) << "Creating socket...";
287 state_ = State::CHECKING_DISK_SPACE;
288 279
289 // TODO(crbug.com/628124): Move disk space checking logic to session_manager.
290 base::PostTaskAndReplyWithResult(
291 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
292 base::Bind(&base::SysInfo::AmountOfFreeDiskSpace,
293 base::FilePath(kDiskCheckPath)),
294 base::Bind(&ArcBridgeBootstrapImpl::OnFreeDiskSpaceObtained,
295 weak_factory_.GetWeakPtr()));
296 }
297
298 void ArcBridgeBootstrapImpl::OnFreeDiskSpaceObtained(int64_t disk_free_bytes) {
299 DCHECK(thread_checker_.CalledOnValidThread());
300 DCHECK_EQ(state_, State::CHECKING_DISK_SPACE);
301
302 if (stop_requested_) {
303 VLOG(1) << "Stop() called while checking disk space";
304 OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
305 return;
306 }
307
308 if (disk_free_bytes < 0) {
309 LOG(ERROR) << "ARC: Failed to get free disk space";
310 OnStopped(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
311 return;
312 }
313 if (disk_free_bytes < kCriticalDiskFreeBytes) {
314 LOG(ERROR) << "ARC: The device is too low on disk space to start ARC";
315 OnStopped(ArcBridgeService::StopReason::LOW_DISK_SPACE);
316 return;
317 }
318
319 VLOG(2) << "Disk space check is done. Creating socket...";
320 state_ = State::CREATING_SOCKET; 280 state_ = State::CREATING_SOCKET;
321 base::PostTaskAndReplyWithResult( 281 base::PostTaskAndReplyWithResult(
322 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, 282 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
323 base::Bind(&ArcBridgeBootstrapImpl::CreateSocket), 283 base::Bind(&ArcBridgeBootstrapImpl::CreateSocket),
324 base::Bind(&ArcBridgeBootstrapImpl::OnSocketCreated, 284 base::Bind(&ArcBridgeBootstrapImpl::OnSocketCreated,
325 weak_factory_.GetWeakPtr())); 285 weak_factory_.GetWeakPtr()));
326 } 286 }
327 287
328 // static 288 // static
329 base::ScopedFD ArcBridgeBootstrapImpl::CreateSocket() { 289 base::ScopedFD ArcBridgeBootstrapImpl::CreateSocket() {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 chromeos::SessionManagerClient* session_manager_client = 352 chromeos::SessionManagerClient* session_manager_client =
393 chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); 353 chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
394 session_manager_client->StartArcInstance( 354 session_manager_client->StartArcInstance(
395 cryptohome_id, 355 cryptohome_id,
396 disable_boot_completed_broadcast, 356 disable_boot_completed_broadcast,
397 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted, 357 base::Bind(&ArcBridgeBootstrapImpl::OnInstanceStarted,
398 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd))); 358 weak_factory_.GetWeakPtr(), base::Passed(&socket_fd)));
399 } 359 }
400 360
401 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd, 361 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd,
402 bool success) { 362 StartArcInstanceResult result) {
403 DCHECK(thread_checker_.CalledOnValidThread()); 363 DCHECK(thread_checker_.CalledOnValidThread());
404 if (state_ == State::STOPPED) { 364 if (state_ == State::STOPPED) {
405 // This is the case that error is notified via DBus before the 365 // This is the case that error is notified via DBus before the
406 // OnInstanceStarted() callback is invoked. The stopping procedure has 366 // OnInstanceStarted() callback is invoked. The stopping procedure has
407 // been run, so do nothing. 367 // been run, so do nothing.
408 return; 368 return;
409 } 369 }
410 370
411 DCHECK_EQ(state_, State::STARTING_INSTANCE); 371 DCHECK_EQ(state_, State::STARTING_INSTANCE);
412 372
413 if (stop_requested_) { 373 if (stop_requested_) {
414 if (success) { 374 if (result == StartArcInstanceResult::SUCCESS) {
415 // The ARC instance has started to run. Request to stop. 375 // The ARC instance has started to run. Request to stop.
416 StopArcInstance(); 376 StopArcInstance();
417 return; 377 return;
418 } 378 }
419 OnStopped(ArcBridgeService::StopReason::SHUTDOWN); 379 OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
420 return; 380 return;
421 } 381 }
422 382
423 if (!success) { 383 if (result != StartArcInstanceResult::SUCCESS) {
424 LOG(ERROR) << "Failed to start ARC instance"; 384 LOG(ERROR) << "Failed to start ARC instance";
425 OnStopped(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE); 385 OnStopped(result == StartArcInstanceResult::LOW_FREE_DISK_SPACE
386 ? ArcBridgeService::StopReason::LOW_DISK_SPACE
387 : ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE);
426 return; 388 return;
427 } 389 }
428 390
429 VLOG(2) << "ARC instance is successfully started. Connecting Mojo..."; 391 VLOG(2) << "ARC instance is successfully started. Connecting Mojo...";
430 state_ = State::CONNECTING_MOJO; 392 state_ = State::CONNECTING_MOJO;
431 393
432 // Prepare a pipe so that AcceptInstanceConnection can be interrupted on 394 // Prepare a pipe so that AcceptInstanceConnection can be interrupted on
433 // Stop(). 395 // Stop().
434 base::ScopedFD cancel_fd; 396 base::ScopedFD cancel_fd;
435 if (!CreatePipe(&cancel_fd, &accept_cancel_pipe_)) { 397 if (!CreatePipe(&cancel_fd, &accept_cancel_pipe_)) {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 if (stop_requested_) 495 if (stop_requested_)
534 return; 496 return;
535 497
536 stop_requested_ = true; 498 stop_requested_ = true;
537 arc_bridge_host_.reset(); 499 arc_bridge_host_.reset();
538 switch (state_) { 500 switch (state_) {
539 case State::NOT_STARTED: 501 case State::NOT_STARTED:
540 OnStopped(ArcBridgeService::StopReason::SHUTDOWN); 502 OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
541 return; 503 return;
542 504
543 case State::CHECKING_DISK_SPACE:
544 case State::CREATING_SOCKET: 505 case State::CREATING_SOCKET:
545 case State::STARTING_INSTANCE: 506 case State::STARTING_INSTANCE:
546 // Before starting the ARC instance, we do nothing here. 507 // Before starting the ARC instance, we do nothing here.
547 // At some point, a callback will be invoked on UI thread, 508 // At some point, a callback will be invoked on UI thread,
548 // and stopping procedure will be run there. 509 // and stopping procedure will be run there.
549 // On Chrome shutdown, it is not the case because the message loop is 510 // On Chrome shutdown, it is not the case because the message loop is
550 // already stopped here. Practically, it is not a problem because; 511 // already stopped here. Practically, it is not a problem because;
551 // - On disk space checking or on socket creating, it is ok to simply 512 // - On socket creating, it is ok to simply ignore such cases,
552 // ignore such cases, because we no-longer continue the bootstrap 513 // because we no-longer continue the bootstrap procedure.
553 // procedure.
554 // - On starting instance, the container instance can be leaked. 514 // - On starting instance, the container instance can be leaked.
555 // Practically it is not problematic because the session manager will 515 // Practically it is not problematic because the session manager will
556 // clean it up. 516 // clean it up.
557 return; 517 return;
558 518
559 case State::CONNECTING_MOJO: 519 case State::CONNECTING_MOJO:
560 // Mojo connection is being waited on a WorkerPool thread. 520 // Mojo connection is being waited on a WorkerPool thread.
561 // Request to cancel it. Following stopping procedure will run 521 // Request to cancel it. Following stopping procedure will run
562 // in its callback. 522 // in its callback.
563 DCHECK(accept_cancel_pipe_.get()); 523 DCHECK(accept_cancel_pipe_.get());
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 void ArcBridgeBootstrap::RemoveObserver(Observer* observer) { 597 void ArcBridgeBootstrap::RemoveObserver(Observer* observer) {
638 observer_list_.RemoveObserver(observer); 598 observer_list_.RemoveObserver(observer);
639 } 599 }
640 600
641 // static 601 // static
642 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() { 602 std::unique_ptr<ArcBridgeBootstrap> ArcBridgeBootstrap::Create() {
643 return base::MakeUnique<ArcBridgeBootstrapImpl>(); 603 return base::MakeUnique<ArcBridgeBootstrapImpl>();
644 } 604 }
645 605
646 } // namespace arc 606 } // namespace arc
OLDNEW
« no previous file with comments | « chromeos/dbus/session_manager_client.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698