blob: 0830febe29a387ec8fe82484d6d7e1781ca72337 [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
57int UpdateEngineDaemon::OnInit() {
58 // Register the |subprocess_| singleton with this Daemon as the signal
59 // handler.
60 subprocess_.Init(this);
61
62 // We use Daemon::OnInit() and not DBusDaemon::OnInit() to gracefully wait for
63 // the D-Bus connection for up two minutes to avoid re-spawning the daemon
64 // too fast causing thrashing if dbus-daemon is not running.
65 int exit_code = Daemon::OnInit();
66 if (exit_code != EX_OK)
67 return exit_code;
68
69 dbus::Bus::Options options;
70 options.bus_type = dbus::Bus::SYSTEM;
71 bus_ = new dbus::Bus(options);
72
73 // Wait for DBus to be ready and exit if it doesn't become available after
74 // the timeout.
75 if (!WaitForDBusSystem(
76 bus_.get(),
77 base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds))) {
78 // TODO(deymo): Make it possible to run update_engine even if dbus-daemon
79 // is not running or constantly crashing.
80 LOG(ERROR) << "Failed to initialize DBus, aborting.";
81 return 1;
82 }
83
84 CHECK(bus_->SetUpAsyncOperations());
85
86 // Initialize update engine global state but continue if something fails.
87 real_system_state_.reset(new RealSystemState(bus_));
88 LOG_IF(ERROR, !real_system_state_->Initialize())
89 << "Failed to initialize system state.";
90 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
91 CHECK(update_attempter);
92
Alex Deymob7ca0962014-10-01 17:58:07 -070093 // Create the DBus service.
94 dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state_.get(), bus_));
95 update_attempter->set_dbus_adaptor(dbus_adaptor_.get());
96
97 dbus_adaptor_->RegisterAsync(base::Bind(&UpdateEngineDaemon::OnDBusRegistered,
98 base::Unretained(this)));
99 LOG(INFO) << "Waiting for DBus object to be registered.";
100 return EX_OK;
101}
102
103void UpdateEngineDaemon::OnDBusRegistered(bool succeeded) {
104 if (!succeeded) {
105 LOG(ERROR) << "Registering the UpdateEngineAdaptor";
106 QuitWithExitCode(1);
107 return;
108 }
109
110 // Take ownership of the service now that everything is initialized. We need
111 // to this now and not before to avoid exposing a well known DBus service
112 // path that doesn't have the service it is supposed to implement.
113 if (!dbus_adaptor_->RequestOwnership()) {
114 LOG(ERROR) << "Unable to take ownership of the DBus service, is there "
115 << "other update_engine daemon running?";
116 QuitWithExitCode(1);
117 return;
118 }
119
120 // Initiate update checks.
121 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
122 update_attempter->ScheduleUpdates();
123
124 // Update boot flags after 45 seconds.
125 MessageLoop::current()->PostDelayedTask(
126 FROM_HERE,
127 base::Bind(&UpdateAttempter::UpdateBootFlags,
128 base::Unretained(update_attempter)),
129 base::TimeDelta::FromSeconds(45));
130
131 // Broadcast the update engine status on startup to ensure consistent system
132 // state on crashes.
133 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
134 &UpdateAttempter::BroadcastStatus,
135 base::Unretained(update_attempter)));
136
137 // Run the UpdateEngineStarted() method on |update_attempter|.
138 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
139 &UpdateAttempter::UpdateEngineStarted,
140 base::Unretained(update_attempter)));
141
142 LOG(INFO) << "Finished initialization. Now running the loop.";
143}
144
145} // namespace chromeos_update_engine