update_engine: Wait for dbus connection to be available.
In the general case, update_engine won't be launched until dbus-daemon
is ready. Nevertheless, if dbus-daemon crashes for some reason,
update_engine will crash and restart again and again because it can't
get the DBus system bus. This will generate many crash reports in a
short period of time.
This patch waits up to 10 seconds to get the DBus system bus, and then
crashes if it couldn't get it by then.
BUG=chromium:417142
TEST=launch update_engine without dbus-daemon and saw it retry and crash.
TEST=launch update_engine in the normal case, it doesn't retry..
Change-Id: I99714cec87f99eeef385fc6e8787334fbc029044
Reviewed-on: https://chromium-review.googlesource.com/219690
Reviewed-by: David Zeuthen <[email protected]>
Commit-Queue: Alex Deymo <[email protected]>
Tested-by: Alex Deymo <[email protected]>
diff --git a/main.cc b/main.cc
index 7b92efa..3242c3d 100644
--- a/main.cc
+++ b/main.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <unistd.h>
+
#include <string>
#include <vector>
@@ -11,6 +13,7 @@
#include <base/logging.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
+#include <base/time/time.h>
#include <gflags/gflags.h>
#include <glib.h>
#include <metrics/metrics_library.h>
@@ -39,6 +42,10 @@
using std::string;
using std::vector;
+namespace {
+const int kDBusSystemMaxWaitSeconds = 2 * 60;
+} // namespace
+
namespace chromeos_update_engine {
gboolean UpdateBootFlags(void* arg) {
@@ -58,7 +65,29 @@
namespace {
-void SetupDbusService(UpdateEngineService* service) {
+// Wait for DBus to be ready by attempting to get the system bus up to
+// |timeout| time. Returns whether it succeeded to get the bus.
+bool WaitForDBusSystem(base::TimeDelta timeout) {
+ GError *error = nullptr;
+ DBusGConnection *bus = nullptr;
+ Clock clock;
+ base::Time deadline = clock.GetMonotonicTime() + timeout;
+
+ while (clock.GetMonotonicTime() < deadline) {
+ bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (bus)
+ return true;
+ LOG(WARNING) << "Failed to get system bus, waiting: "
+ << utils::GetAndFreeGError(&error);
+ // Wait 1 second.
+ sleep(1);
+ }
+ LOG(ERROR) << "Failed to get system bus after " << timeout.InSeconds()
+ << " seconds.";
+ return false;
+}
+
+void SetupDBusService(UpdateEngineService* service) {
DBusGConnection *bus;
DBusGProxy *proxy;
GError *error = nullptr;
@@ -171,6 +200,11 @@
// Create the single GMainLoop
GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
+ // Wait up to 2 minutes for DBus to be ready.
+ LOG_IF(FATAL, !chromeos_update_engine::WaitForDBusSystem(
+ base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds)))
+ << "Failed to initialize DBus, aborting.";
+
chromeos_update_engine::RealSystemState real_system_state;
LOG_IF(ERROR, !real_system_state.Initialize())
<< "Failed to initialize system state.";
@@ -191,7 +225,7 @@
UpdateEngineService* service = update_engine_service_new();
service->system_state_ = &real_system_state;
update_attempter->set_dbus_service(service);
- chromeos_update_engine::SetupDbusService(service);
+ chromeos_update_engine::SetupDBusService(service);
// Initiate update checks.
update_attempter->ScheduleUpdates();