blob: bc221b53d8af78162292c770c5b9c95badfa6c18 [file] [log] [blame]
Alex Deymob7ca0962014-10-01 17:58:07 -07001// Copyright 2015 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/daemon.h"
6
7#include <sysexits.h>
8
9#include <base/bind.h>
10#include <base/location.h>
11#include <base/time/time.h>
12#include <chromeos/message_loops/message_loop.h>
13
14#include "update_engine/clock.h"
15#include "update_engine/update_attempter.h"
16
17using chromeos::MessageLoop;
18
19namespace {
20const int kDBusSystemMaxWaitSeconds = 2 * 60;
21} // namespace
22
23namespace chromeos_update_engine {
24
25namespace {
26// Wait for passed |bus| DBus to be connected by attempting to connect it up to
27// |timeout| time. Returns whether the Connect() eventually succeeded.
28bool WaitForDBusSystem(dbus::Bus* bus, base::TimeDelta timeout) {
29 Clock clock;
30 base::Time deadline = clock.GetMonotonicTime() + timeout;
31
32 while (clock.GetMonotonicTime() < deadline) {
33 if (bus->Connect())
34 return true;
35 LOG(WARNING) << "Failed to get system bus, waiting.";
36 // Wait 1 second.
37 sleep(1);
38 }
39 LOG(ERROR) << "Failed to get system bus after " << timeout.InSeconds()
40 << " seconds.";
41 return false;
42}
43} // namespace
44
45int UpdateEngineDaemon::OnInit() {
46 // Register the |subprocess_| singleton with this Daemon as the signal
47 // handler.
48 subprocess_.Init(this);
49
50 // We use Daemon::OnInit() and not DBusDaemon::OnInit() to gracefully wait for
51 // the D-Bus connection for up two minutes to avoid re-spawning the daemon
52 // too fast causing thrashing if dbus-daemon is not running.
53 int exit_code = Daemon::OnInit();
54 if (exit_code != EX_OK)
55 return exit_code;
56
57 dbus::Bus::Options options;
58 options.bus_type = dbus::Bus::SYSTEM;
59 bus_ = new dbus::Bus(options);
60
61 // Wait for DBus to be ready and exit if it doesn't become available after
62 // the timeout.
63 if (!WaitForDBusSystem(
64 bus_.get(),
65 base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds))) {
66 // TODO(deymo): Make it possible to run update_engine even if dbus-daemon
67 // is not running or constantly crashing.
68 LOG(ERROR) << "Failed to initialize DBus, aborting.";
69 return 1;
70 }
71
72 CHECK(bus_->SetUpAsyncOperations());
73
74 // Initialize update engine global state but continue if something fails.
75 real_system_state_.reset(new RealSystemState(bus_));
76 LOG_IF(ERROR, !real_system_state_->Initialize())
77 << "Failed to initialize system state.";
78 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
79 CHECK(update_attempter);
80
81 // Sets static members for the certificate checker.
82 CertificateChecker::set_system_state(real_system_state_.get());
83 CertificateChecker::set_openssl_wrapper(&openssl_wrapper_);
84
85 // Create the DBus service.
86 dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state_.get(), bus_));
87 update_attempter->set_dbus_adaptor(dbus_adaptor_.get());
88
89 dbus_adaptor_->RegisterAsync(base::Bind(&UpdateEngineDaemon::OnDBusRegistered,
90 base::Unretained(this)));
91 LOG(INFO) << "Waiting for DBus object to be registered.";
92 return EX_OK;
93}
94
95void UpdateEngineDaemon::OnDBusRegistered(bool succeeded) {
96 if (!succeeded) {
97 LOG(ERROR) << "Registering the UpdateEngineAdaptor";
98 QuitWithExitCode(1);
99 return;
100 }
101
102 // Take ownership of the service now that everything is initialized. We need
103 // to this now and not before to avoid exposing a well known DBus service
104 // path that doesn't have the service it is supposed to implement.
105 if (!dbus_adaptor_->RequestOwnership()) {
106 LOG(ERROR) << "Unable to take ownership of the DBus service, is there "
107 << "other update_engine daemon running?";
108 QuitWithExitCode(1);
109 return;
110 }
111
112 // Initiate update checks.
113 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
114 update_attempter->ScheduleUpdates();
115
116 // Update boot flags after 45 seconds.
117 MessageLoop::current()->PostDelayedTask(
118 FROM_HERE,
119 base::Bind(&UpdateAttempter::UpdateBootFlags,
120 base::Unretained(update_attempter)),
121 base::TimeDelta::FromSeconds(45));
122
123 // Broadcast the update engine status on startup to ensure consistent system
124 // state on crashes.
125 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
126 &UpdateAttempter::BroadcastStatus,
127 base::Unretained(update_attempter)));
128
129 // Run the UpdateEngineStarted() method on |update_attempter|.
130 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
131 &UpdateAttempter::UpdateEngineStarted,
132 base::Unretained(update_attempter)));
133
134 LOG(INFO) << "Finished initialization. Now running the loop.";
135}
136
137} // namespace chromeos_update_engine