blob: 0b13c186cd2599892705160e2ac58fff7dc3b21d [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Alex Deymob7ca0962014-10-01 17:58:07 -070016
17#include "update_engine/daemon.h"
18
19#include <sysexits.h>
20
21#include <base/bind.h>
22#include <base/location.h>
23#include <base/time/time.h>
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070024#include <brillo/message_loops/message_loop.h>
Alex Deymob7ca0962014-10-01 17:58:07 -070025
Alex Deymo39910dc2015-11-09 17:04:30 -080026#include "update_engine/common/clock.h"
Alex Deymob7ca0962014-10-01 17:58:07 -070027#include "update_engine/update_attempter.h"
28
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070029using brillo::MessageLoop;
Alex Deymob7ca0962014-10-01 17:58:07 -070030
31namespace {
32const int kDBusSystemMaxWaitSeconds = 2 * 60;
33} // namespace
34
35namespace chromeos_update_engine {
36
37namespace {
38// Wait for passed |bus| DBus to be connected by attempting to connect it up to
39// |timeout| time. Returns whether the Connect() eventually succeeded.
40bool WaitForDBusSystem(dbus::Bus* bus, base::TimeDelta timeout) {
41 Clock clock;
42 base::Time deadline = clock.GetMonotonicTime() + timeout;
43
44 while (clock.GetMonotonicTime() < deadline) {
45 if (bus->Connect())
46 return true;
47 LOG(WARNING) << "Failed to get system bus, waiting.";
48 // Wait 1 second.
49 sleep(1);
50 }
51 LOG(ERROR) << "Failed to get system bus after " << timeout.InSeconds()
52 << " seconds.";
53 return false;
54}
55} // namespace
56
Alex Deymo2b4268c2015-12-04 13:56:25 -080057UpdateEngineDaemon::~UpdateEngineDaemon() {
58 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
59 // Prevent any DBus communication from UpdateAttempter when shutting down the
60 // daemon.
61 if (update_attempter)
62 update_attempter->set_dbus_adaptor(nullptr);
63}
64
Alex Deymob7ca0962014-10-01 17:58:07 -070065int UpdateEngineDaemon::OnInit() {
66 // Register the |subprocess_| singleton with this Daemon as the signal
67 // handler.
68 subprocess_.Init(this);
69
70 // We use Daemon::OnInit() and not DBusDaemon::OnInit() to gracefully wait for
71 // the D-Bus connection for up two minutes to avoid re-spawning the daemon
72 // too fast causing thrashing if dbus-daemon is not running.
73 int exit_code = Daemon::OnInit();
74 if (exit_code != EX_OK)
75 return exit_code;
76
77 dbus::Bus::Options options;
78 options.bus_type = dbus::Bus::SYSTEM;
79 bus_ = new dbus::Bus(options);
80
81 // Wait for DBus to be ready and exit if it doesn't become available after
82 // the timeout.
83 if (!WaitForDBusSystem(
84 bus_.get(),
85 base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds))) {
86 // TODO(deymo): Make it possible to run update_engine even if dbus-daemon
87 // is not running or constantly crashing.
88 LOG(ERROR) << "Failed to initialize DBus, aborting.";
89 return 1;
90 }
91
92 CHECK(bus_->SetUpAsyncOperations());
93
94 // Initialize update engine global state but continue if something fails.
95 real_system_state_.reset(new RealSystemState(bus_));
96 LOG_IF(ERROR, !real_system_state_->Initialize())
97 << "Failed to initialize system state.";
98 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
99 CHECK(update_attempter);
100
Alex Deymob7ca0962014-10-01 17:58:07 -0700101 // Create the DBus service.
102 dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state_.get(), bus_));
103 update_attempter->set_dbus_adaptor(dbus_adaptor_.get());
104
105 dbus_adaptor_->RegisterAsync(base::Bind(&UpdateEngineDaemon::OnDBusRegistered,
106 base::Unretained(this)));
107 LOG(INFO) << "Waiting for DBus object to be registered.";
108 return EX_OK;
109}
110
111void UpdateEngineDaemon::OnDBusRegistered(bool succeeded) {
112 if (!succeeded) {
113 LOG(ERROR) << "Registering the UpdateEngineAdaptor";
114 QuitWithExitCode(1);
115 return;
116 }
117
118 // Take ownership of the service now that everything is initialized. We need
119 // to this now and not before to avoid exposing a well known DBus service
120 // path that doesn't have the service it is supposed to implement.
121 if (!dbus_adaptor_->RequestOwnership()) {
122 LOG(ERROR) << "Unable to take ownership of the DBus service, is there "
123 << "other update_engine daemon running?";
124 QuitWithExitCode(1);
125 return;
126 }
127
128 // Initiate update checks.
129 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
130 update_attempter->ScheduleUpdates();
131
132 // Update boot flags after 45 seconds.
133 MessageLoop::current()->PostDelayedTask(
134 FROM_HERE,
135 base::Bind(&UpdateAttempter::UpdateBootFlags,
136 base::Unretained(update_attempter)),
137 base::TimeDelta::FromSeconds(45));
138
139 // Broadcast the update engine status on startup to ensure consistent system
140 // state on crashes.
141 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
142 &UpdateAttempter::BroadcastStatus,
143 base::Unretained(update_attempter)));
144
145 // Run the UpdateEngineStarted() method on |update_attempter|.
146 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
147 &UpdateAttempter::UpdateEngineStarted,
148 base::Unretained(update_attempter)));
149
150 LOG(INFO) << "Finished initialization. Now running the loop.";
151}
152
153} // namespace chromeos_update_engine