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

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

Powered by Google App Engine
This is Rietveld 408576698