blob: 1e39c8b3cd3580677b02dbe3389d6a2f79473ec3 [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 Vakulenkoe119e6a2016-01-06 17:13:11 -080024#if USE_WEAVE
25#include <binderwrapper/binder_wrapper.h>
26#endif // USE_WEAVE
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070027#include <brillo/message_loops/message_loop.h>
Alex Deymob7ca0962014-10-01 17:58:07 -070028
Alex Deymo39910dc2015-11-09 17:04:30 -080029#include "update_engine/common/clock.h"
Alex Deymob7ca0962014-10-01 17:58:07 -070030#include "update_engine/update_attempter.h"
31
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070032using brillo::MessageLoop;
Alex Deymob7ca0962014-10-01 17:58:07 -070033
34namespace {
35const int kDBusSystemMaxWaitSeconds = 2 * 60;
36} // namespace
37
38namespace chromeos_update_engine {
39
40namespace {
41// Wait for passed |bus| DBus to be connected by attempting to connect it up to
42// |timeout| time. Returns whether the Connect() eventually succeeded.
43bool WaitForDBusSystem(dbus::Bus* bus, base::TimeDelta timeout) {
44 Clock clock;
45 base::Time deadline = clock.GetMonotonicTime() + timeout;
46
47 while (clock.GetMonotonicTime() < deadline) {
48 if (bus->Connect())
49 return true;
50 LOG(WARNING) << "Failed to get system bus, waiting.";
51 // Wait 1 second.
52 sleep(1);
53 }
54 LOG(ERROR) << "Failed to get system bus after " << timeout.InSeconds()
55 << " seconds.";
56 return false;
57}
58} // namespace
59
Alex Deymo2b4268c2015-12-04 13:56:25 -080060UpdateEngineDaemon::~UpdateEngineDaemon() {
61 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
62 // Prevent any DBus communication from UpdateAttempter when shutting down the
63 // daemon.
64 if (update_attempter)
65 update_attempter->set_dbus_adaptor(nullptr);
66}
67
Alex Deymob7ca0962014-10-01 17:58:07 -070068int UpdateEngineDaemon::OnInit() {
69 // Register the |subprocess_| singleton with this Daemon as the signal
70 // handler.
71 subprocess_.Init(this);
72
73 // We use Daemon::OnInit() and not DBusDaemon::OnInit() to gracefully wait for
74 // the D-Bus connection for up two minutes to avoid re-spawning the daemon
75 // too fast causing thrashing if dbus-daemon is not running.
76 int exit_code = Daemon::OnInit();
77 if (exit_code != EX_OK)
78 return exit_code;
79
Alex Vakulenkoe119e6a2016-01-06 17:13:11 -080080#if USE_WEAVE
81 android::BinderWrapper::Create();
82 binder_watcher_.Init();
83#endif // USE_WEAVE
84
Alex Deymob7ca0962014-10-01 17:58:07 -070085 dbus::Bus::Options options;
86 options.bus_type = dbus::Bus::SYSTEM;
87 bus_ = new dbus::Bus(options);
88
89 // Wait for DBus to be ready and exit if it doesn't become available after
90 // the timeout.
91 if (!WaitForDBusSystem(
92 bus_.get(),
93 base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds))) {
94 // TODO(deymo): Make it possible to run update_engine even if dbus-daemon
95 // is not running or constantly crashing.
96 LOG(ERROR) << "Failed to initialize DBus, aborting.";
97 return 1;
98 }
99
100 CHECK(bus_->SetUpAsyncOperations());
101
102 // Initialize update engine global state but continue if something fails.
103 real_system_state_.reset(new RealSystemState(bus_));
104 LOG_IF(ERROR, !real_system_state_->Initialize())
105 << "Failed to initialize system state.";
106 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
107 CHECK(update_attempter);
108
Alex Deymob7ca0962014-10-01 17:58:07 -0700109 // Create the DBus service.
110 dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state_.get(), bus_));
111 update_attempter->set_dbus_adaptor(dbus_adaptor_.get());
112
113 dbus_adaptor_->RegisterAsync(base::Bind(&UpdateEngineDaemon::OnDBusRegistered,
114 base::Unretained(this)));
115 LOG(INFO) << "Waiting for DBus object to be registered.";
116 return EX_OK;
117}
118
119void UpdateEngineDaemon::OnDBusRegistered(bool succeeded) {
120 if (!succeeded) {
121 LOG(ERROR) << "Registering the UpdateEngineAdaptor";
122 QuitWithExitCode(1);
123 return;
124 }
125
126 // Take ownership of the service now that everything is initialized. We need
127 // to this now and not before to avoid exposing a well known DBus service
128 // path that doesn't have the service it is supposed to implement.
129 if (!dbus_adaptor_->RequestOwnership()) {
130 LOG(ERROR) << "Unable to take ownership of the DBus service, is there "
131 << "other update_engine daemon running?";
132 QuitWithExitCode(1);
133 return;
134 }
135
136 // Initiate update checks.
137 UpdateAttempter* update_attempter = real_system_state_->update_attempter();
138 update_attempter->ScheduleUpdates();
139
140 // Update boot flags after 45 seconds.
141 MessageLoop::current()->PostDelayedTask(
142 FROM_HERE,
143 base::Bind(&UpdateAttempter::UpdateBootFlags,
144 base::Unretained(update_attempter)),
145 base::TimeDelta::FromSeconds(45));
146
147 // Broadcast the update engine status on startup to ensure consistent system
148 // state on crashes.
149 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
150 &UpdateAttempter::BroadcastStatus,
151 base::Unretained(update_attempter)));
152
153 // Run the UpdateEngineStarted() method on |update_attempter|.
154 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
155 &UpdateAttempter::UpdateEngineStarted,
156 base::Unretained(update_attempter)));
157
158 LOG(INFO) << "Finished initialization. Now running the loop.";
159}
160
161} // namespace chromeos_update_engine