update_engine: Migrate UE DBus service to chrome DBus bindings.
chromeos-dbus-bindings now generates the adaptor interface that
update_engine exposes over DBus. This interface is implemented in
dbus_service.{h,cc}, which now has a UpdateEngineService class
encapsulating all the service methods implementation.
This allows to write unit test for those methods, which are included
in this CL for all the non-trivial methods.
This CL now uses chrome's DBus bindings for the update_engine serive,
but the proxy interaction is still done using dbus-glib. The main loop
in the main.cc file is now replaced with the chromeos::Dameon, which
uses a chromeos::BaseMessageLoop instead of a GlibMessageLoop. This
causes the asynchronous interactions in the proxy side to not work,
which will be fixed in the next CL.
CQ-DEPEND=CL:290990,CL:291092,CL:293334
BUG=chromium:419827
TEST=Added unittest for all dbus_service methods. deployed and tested manually that update_engine dbus interface works.
Change-Id: I6a6d142b2ac1a61a4c3abcb927665b26114abe5c
Reviewed-on: https://chromium-review.googlesource.com/225324
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Reviewed-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
Trybot-Ready: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
diff --git a/daemon.cc b/daemon.cc
new file mode 100644
index 0000000..bc221b5
--- /dev/null
+++ b/daemon.cc
@@ -0,0 +1,137 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/daemon.h"
+
+#include <sysexits.h>
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/time/time.h>
+#include <chromeos/message_loops/message_loop.h>
+
+#include "update_engine/clock.h"
+#include "update_engine/update_attempter.h"
+
+using chromeos::MessageLoop;
+
+namespace {
+const int kDBusSystemMaxWaitSeconds = 2 * 60;
+} // namespace
+
+namespace chromeos_update_engine {
+
+namespace {
+// Wait for passed |bus| DBus to be connected by attempting to connect it up to
+// |timeout| time. Returns whether the Connect() eventually succeeded.
+bool WaitForDBusSystem(dbus::Bus* bus, base::TimeDelta timeout) {
+ Clock clock;
+ base::Time deadline = clock.GetMonotonicTime() + timeout;
+
+ while (clock.GetMonotonicTime() < deadline) {
+ if (bus->Connect())
+ return true;
+ LOG(WARNING) << "Failed to get system bus, waiting.";
+ // Wait 1 second.
+ sleep(1);
+ }
+ LOG(ERROR) << "Failed to get system bus after " << timeout.InSeconds()
+ << " seconds.";
+ return false;
+}
+} // namespace
+
+int UpdateEngineDaemon::OnInit() {
+ // Register the |subprocess_| singleton with this Daemon as the signal
+ // handler.
+ subprocess_.Init(this);
+
+ // We use Daemon::OnInit() and not DBusDaemon::OnInit() to gracefully wait for
+ // the D-Bus connection for up two minutes to avoid re-spawning the daemon
+ // too fast causing thrashing if dbus-daemon is not running.
+ int exit_code = Daemon::OnInit();
+ if (exit_code != EX_OK)
+ return exit_code;
+
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ bus_ = new dbus::Bus(options);
+
+ // Wait for DBus to be ready and exit if it doesn't become available after
+ // the timeout.
+ if (!WaitForDBusSystem(
+ bus_.get(),
+ base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds))) {
+ // TODO(deymo): Make it possible to run update_engine even if dbus-daemon
+ // is not running or constantly crashing.
+ LOG(ERROR) << "Failed to initialize DBus, aborting.";
+ return 1;
+ }
+
+ CHECK(bus_->SetUpAsyncOperations());
+
+ // Initialize update engine global state but continue if something fails.
+ real_system_state_.reset(new RealSystemState(bus_));
+ LOG_IF(ERROR, !real_system_state_->Initialize())
+ << "Failed to initialize system state.";
+ UpdateAttempter* update_attempter = real_system_state_->update_attempter();
+ CHECK(update_attempter);
+
+ // Sets static members for the certificate checker.
+ CertificateChecker::set_system_state(real_system_state_.get());
+ CertificateChecker::set_openssl_wrapper(&openssl_wrapper_);
+
+ // Create the DBus service.
+ dbus_adaptor_.reset(new UpdateEngineAdaptor(real_system_state_.get(), bus_));
+ update_attempter->set_dbus_adaptor(dbus_adaptor_.get());
+
+ dbus_adaptor_->RegisterAsync(base::Bind(&UpdateEngineDaemon::OnDBusRegistered,
+ base::Unretained(this)));
+ LOG(INFO) << "Waiting for DBus object to be registered.";
+ return EX_OK;
+}
+
+void UpdateEngineDaemon::OnDBusRegistered(bool succeeded) {
+ if (!succeeded) {
+ LOG(ERROR) << "Registering the UpdateEngineAdaptor";
+ QuitWithExitCode(1);
+ return;
+ }
+
+ // Take ownership of the service now that everything is initialized. We need
+ // to this now and not before to avoid exposing a well known DBus service
+ // path that doesn't have the service it is supposed to implement.
+ if (!dbus_adaptor_->RequestOwnership()) {
+ LOG(ERROR) << "Unable to take ownership of the DBus service, is there "
+ << "other update_engine daemon running?";
+ QuitWithExitCode(1);
+ return;
+ }
+
+ // Initiate update checks.
+ UpdateAttempter* update_attempter = real_system_state_->update_attempter();
+ update_attempter->ScheduleUpdates();
+
+ // Update boot flags after 45 seconds.
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&UpdateAttempter::UpdateBootFlags,
+ base::Unretained(update_attempter)),
+ base::TimeDelta::FromSeconds(45));
+
+ // Broadcast the update engine status on startup to ensure consistent system
+ // state on crashes.
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &UpdateAttempter::BroadcastStatus,
+ base::Unretained(update_attempter)));
+
+ // Run the UpdateEngineStarted() method on |update_attempter|.
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &UpdateAttempter::UpdateEngineStarted,
+ base::Unretained(update_attempter)));
+
+ LOG(INFO) << "Finished initialization. Now running the loop.";
+}
+
+} // namespace chromeos_update_engine
diff --git a/daemon.h b/daemon.h
new file mode 100644
index 0000000..4a7fe18
--- /dev/null
+++ b/daemon.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UPDATE_ENGINE_DAEMON_H_
+#define UPDATE_ENGINE_DAEMON_H_
+
+#include <memory>
+#include <string>
+
+#include <chromeos/daemons/dbus_daemon.h>
+
+#include "update_engine/certificate_checker.h"
+#include "update_engine/dbus_service.h"
+#include "update_engine/real_system_state.h"
+#include "update_engine/subprocess.h"
+
+namespace chromeos_update_engine {
+
+class UpdateEngineDaemon : public chromeos::DBusDaemon {
+ public:
+ UpdateEngineDaemon() = default;
+
+ protected:
+ int OnInit() override;
+
+ private:
+ // Run from the main loop when the |dbus_adaptor_| object is registered. At
+ // this point we can request ownership of the DBus service name and continue
+ // initialization.
+ void OnDBusRegistered(bool succeeded);
+
+ // The Subprocess singleton class requires a chromeos::MessageLoop in the
+ // current thread, so we need to initialize it from this class instead of
+ // the main() function.
+ Subprocess subprocess_;
+
+ std::unique_ptr<RealSystemState> real_system_state_;
+ OpenSSLWrapper openssl_wrapper_;
+ std::unique_ptr<UpdateEngineAdaptor> dbus_adaptor_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateEngineDaemon);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_DAEMON_H_
diff --git a/dbus_constants.h b/dbus_constants.h
index d51e6fd..f8494ff 100644
--- a/dbus_constants.h
+++ b/dbus_constants.h
@@ -13,6 +13,10 @@
static const char* const kUpdateEngineServiceInterface =
"org.chromium.UpdateEngineInterface";
+// Generic UpdateEngine D-Bus error.
+static const char* const kUpdateEngineServiceErrorFailed =
+ "org.chromium.UpdateEngine.Error.Failed";
+
// Flags used in the AttemptUpdateWithFlags() D-Bus method.
typedef enum {
kAttemptUpdateFlagNonInteractive = (1<<0)
diff --git a/dbus_service.cc b/dbus_service.cc
index d77ea31..7c9d0c2 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -7,8 +7,11 @@
#include <set>
#include <string>
+#include <base/location.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
+#include <chromeos/bind_lambda.h>
+#include <chromeos/message_loops/message_loop.h>
#include <chromeos/strings/string_utils.h>
#include <policy/device_policy.h>
@@ -23,400 +26,232 @@
#include "update_engine/utils.h"
using base::StringPrintf;
+using chromeos::ErrorPtr;
using chromeos::string_utils::ToString;
using chromeos_update_engine::AttemptUpdateFlags;
using chromeos_update_engine::kAttemptUpdateFlagNonInteractive;
using std::set;
using std::string;
-#define UPDATE_ENGINE_SERVICE_ERROR update_engine_service_error_quark ()
-#define UPDATE_ENGINE_SERVICE_TYPE_ERROR \
- (update_engine_service_error_get_type())
+namespace {
+// Log and set the error on the passed ErrorPtr.
+void LogAndSetError(ErrorPtr *error,
+ const tracked_objects::Location& location,
+ const string& reason) {
+ chromeos::Error::AddTo(
+ error, location,
+ chromeos::errors::dbus::kDomain,
+ chromeos_update_engine::kUpdateEngineServiceErrorFailed, reason);
+ LOG(ERROR) << "Sending DBus Failure: " << location.ToString() << ": "
+ << reason;
+}
+} // namespace
-enum UpdateEngineServiceError {
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- UPDATE_ENGINE_SERVICE_NUM_ERRORS
-};
+namespace chromeos_update_engine {
-static GQuark update_engine_service_error_quark(void) {
- static GQuark ret = 0;
+UpdateEngineService::UpdateEngineService(SystemState* system_state)
+ : system_state_(system_state) {}
- if (ret == 0)
- ret = g_quark_from_static_string("update_engine_service_error");
+// org::chromium::UpdateEngineInterfaceInterface methods implementation.
- return ret;
+bool UpdateEngineService::AttemptUpdate(ErrorPtr* error,
+ const string& in_app_version,
+ const string& in_omaha_url) {
+ return AttemptUpdateWithFlags(
+ error, in_app_version, in_omaha_url, 0 /* no flags */);
}
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-static GType update_engine_service_error_get_type(void) {
- static GType etype = 0;
-
- if (etype == 0) {
- static const GEnumValue values[] = {
- ENUM_ENTRY(UPDATE_ENGINE_SERVICE_ERROR_FAILED, "Failed"),
- { 0, 0, 0 }
- };
- G_STATIC_ASSERT(UPDATE_ENGINE_SERVICE_NUM_ERRORS ==
- G_N_ELEMENTS(values) - 1);
- etype = g_enum_register_static("UpdateEngineServiceError", values);
- }
-
- return etype;
-}
-
-G_DEFINE_TYPE(UpdateEngineService, update_engine_service, G_TYPE_OBJECT)
-
-static void update_engine_service_finalize(GObject* object) {
- G_OBJECT_CLASS(update_engine_service_parent_class)->finalize(object);
-}
-
-static void log_and_set_response_error(GError** error,
- UpdateEngineServiceError error_code,
- const string& reason) {
- LOG(ERROR) << "Sending DBus Failure: " << reason;
- g_set_error_literal(error, UPDATE_ENGINE_SERVICE_ERROR,
- error_code, reason.c_str());
-}
-
-static guint status_update_signal = 0;
-
-static void update_engine_service_class_init(UpdateEngineServiceClass* klass) {
- GObjectClass *object_class;
- object_class = G_OBJECT_CLASS(klass);
- object_class->finalize = update_engine_service_finalize;
-
- status_update_signal = g_signal_new(
- "status_update",
- G_OBJECT_CLASS_TYPE(klass),
- G_SIGNAL_RUN_LAST,
- 0, // 0 == no class method associated
- nullptr, // Accumulator
- nullptr, // Accumulator data
- nullptr, // Marshaller
- G_TYPE_NONE, // Return type
- 5, // param count:
- G_TYPE_INT64,
- G_TYPE_DOUBLE,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_INT64);
-}
-
-static void update_engine_service_init(UpdateEngineService* object) {
- dbus_g_error_domain_register(UPDATE_ENGINE_SERVICE_ERROR,
- "org.chromium.UpdateEngine.Error",
- UPDATE_ENGINE_SERVICE_TYPE_ERROR);
-}
-
-UpdateEngineService* update_engine_service_new(void) {
- return reinterpret_cast<UpdateEngineService*>(
- g_object_new(UPDATE_ENGINE_TYPE_SERVICE, nullptr));
-}
-
-gboolean update_engine_service_attempt_update(UpdateEngineService* self,
- gchar* app_version,
- gchar* omaha_url,
- GError **error) {
- return update_engine_service_attempt_update_with_flags(self,
- app_version,
- omaha_url,
- 0, // No flags set.
- error);
-}
-
-gboolean update_engine_service_attempt_update_with_flags(
- UpdateEngineService* self,
- gchar* app_version,
- gchar* omaha_url,
- gint flags_as_int,
- GError **error) {
- string app_version_string, omaha_url_string;
- AttemptUpdateFlags flags = static_cast<AttemptUpdateFlags>(flags_as_int);
+bool UpdateEngineService::AttemptUpdateWithFlags(ErrorPtr* /* error */,
+ const string& in_app_version,
+ const string& in_omaha_url,
+ int32_t in_flags_as_int) {
+ AttemptUpdateFlags flags = static_cast<AttemptUpdateFlags>(in_flags_as_int);
bool interactive = !(flags & kAttemptUpdateFlagNonInteractive);
- if (app_version)
- app_version_string = app_version;
- if (omaha_url)
- omaha_url_string = omaha_url;
-
- LOG(INFO) << "Attempt update: app_version=\"" << app_version_string << "\" "
- << "omaha_url=\"" << omaha_url_string << "\" "
+ LOG(INFO) << "Attempt update: app_version=\"" << in_app_version << "\" "
+ << "omaha_url=\"" << in_omaha_url << "\" "
<< "flags=0x" << std::hex << flags << " "
<< "interactive=" << (interactive? "yes" : "no");
- self->system_state_->update_attempter()->CheckForUpdate(app_version_string,
- omaha_url_string,
- interactive);
- return TRUE;
+ system_state_->update_attempter()->CheckForUpdate(
+ in_app_version, in_omaha_url, interactive);
+ return true;
}
-gboolean update_engine_service_attempt_rollback(UpdateEngineService* self,
- gboolean powerwash,
- GError **error) {
+bool UpdateEngineService::AttemptRollback(ErrorPtr* error,
+ bool in_powerwash) {
LOG(INFO) << "Attempting rollback to non-active partitions.";
- if (!self->system_state_->update_attempter()->Rollback(powerwash)) {
+ if (!system_state_->update_attempter()->Rollback(in_powerwash)) {
// TODO(dgarrett): Give a more specific error code/reason.
- log_and_set_response_error(error,
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Rollback attempt failed.");
- return FALSE;
+ LogAndSetError(error, FROM_HERE, "Rollback attempt failed.");
+ return false;
}
-
- return TRUE;
+ return true;
}
-gboolean update_engine_service_can_rollback(UpdateEngineService* self,
- gboolean* out_can_rollback,
- GError **error) {
- bool can_rollback = self->system_state_->update_attempter()->CanRollback();
+bool UpdateEngineService::CanRollback(ErrorPtr* /* error */,
+ bool* out_can_rollback) {
+ bool can_rollback = system_state_->update_attempter()->CanRollback();
LOG(INFO) << "Checking to see if we can rollback . Result: " << can_rollback;
*out_can_rollback = can_rollback;
- return TRUE;
+ return true;
}
-gboolean update_engine_service_get_rollback_partition(
- UpdateEngineService* self,
- gchar** out_rollback_partition_name,
- GError **error) {
- auto name = self->system_state_->update_attempter()->GetRollbackPartition();
- LOG(INFO) << "Getting rollback partition name. Result: " << name;
- *out_rollback_partition_name = g_strdup(name.c_str());
- return TRUE;
-}
-
-gboolean update_engine_service_get_kernel_devices(UpdateEngineService* self,
- gchar** out_kernel_devices,
- GError **error) {
- auto devices = self->system_state_->update_attempter()->GetKernelDevices();
- string info;
- for (const auto& device : devices) {
- base::StringAppendF(&info, "%d:%s\n",
- device.second ? 1 : 0, device.first.c_str());
- }
- LOG(INFO) << "Available kernel devices: " << info;
- *out_kernel_devices = g_strdup(info.c_str());
- return TRUE;
-}
-
-
-gboolean update_engine_service_reset_status(UpdateEngineService* self,
- GError **error) {
- if (!self->system_state_->update_attempter()->ResetStatus()) {
+bool UpdateEngineService::ResetStatus(ErrorPtr* error) {
+ if (!system_state_->update_attempter()->ResetStatus()) {
// TODO(dgarrett): Give a more specific error code/reason.
- log_and_set_response_error(error,
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "ResetStatus failed.");
- return FALSE;
+ LogAndSetError(error, FROM_HERE, "ResetStatus failed.");
+ return false;
}
-
- return TRUE;
+ return true;
}
-gboolean update_engine_service_get_status(UpdateEngineService* self,
- int64_t* last_checked_time,
- double* progress,
- gchar** current_operation,
- gchar** new_version,
- int64_t* new_size,
- GError **error) {
- string current_op;
- string new_version_str;
-
- CHECK(self->system_state_->update_attempter()->GetStatus(last_checked_time,
- progress,
- ¤t_op,
- &new_version_str,
- new_size));
- *current_operation = g_strdup(current_op.c_str());
- *new_version = g_strdup(new_version_str.c_str());
-
- if (!*current_operation) {
- log_and_set_response_error(error,
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Unable to find current_operation.");
- return FALSE;
+bool UpdateEngineService::GetStatus(ErrorPtr* error,
+ int64_t* out_last_checked_time,
+ double* out_progress,
+ string* out_current_operation,
+ string* out_new_version,
+ int64_t* out_new_size) {
+ if (!system_state_->update_attempter()->GetStatus(out_last_checked_time,
+ out_progress,
+ out_current_operation,
+ out_new_version,
+ out_new_size)) {
+ LogAndSetError(error, FROM_HERE, "GetStatus failed.");
+ return false;
}
-
- if (!*new_version) {
- log_and_set_response_error(error,
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Unable to find vew_version.");
- return FALSE;
- }
-
- return TRUE;
+ return true;
}
-gboolean update_engine_service_reboot_if_needed(UpdateEngineService* self,
- GError **error) {
- if (!self->system_state_->update_attempter()->RebootIfNeeded()) {
+bool UpdateEngineService::RebootIfNeeded(ErrorPtr* error) {
+ if (!system_state_->update_attempter()->RebootIfNeeded()) {
// TODO(dgarrett): Give a more specific error code/reason.
- log_and_set_response_error(error,
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Reboot not needed, or attempt failed.");
- return FALSE;
+ LogAndSetError(error, FROM_HERE, "Reboot not needed, or attempt failed.");
+ return false;
}
- return TRUE;
+ return true;
}
-gboolean update_engine_service_set_channel(UpdateEngineService* self,
- gchar* target_channel,
- gboolean is_powerwash_allowed,
- GError **error) {
- if (!target_channel) {
- log_and_set_response_error(error,
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Target channel to set not specified.");
- return FALSE;
- }
-
- const policy::DevicePolicy* device_policy =
- self->system_state_->device_policy();
+bool UpdateEngineService::SetChannel(ErrorPtr* error,
+ const string& in_target_channel,
+ bool in_is_powerwash_allowed) {
+ const policy::DevicePolicy* device_policy = system_state_->device_policy();
// The device_policy is loaded in a lazy way before an update check. Load it
// now from the libchromeos cache if it wasn't already loaded.
if (!device_policy) {
- chromeos_update_engine::UpdateAttempter* update_attempter =
- self->system_state_->update_attempter();
+ UpdateAttempter* update_attempter = system_state_->update_attempter();
if (update_attempter) {
update_attempter->RefreshDevicePolicy();
- device_policy = self->system_state_->device_policy();
+ device_policy = system_state_->device_policy();
}
}
bool delegated = false;
if (device_policy &&
device_policy->GetReleaseChannelDelegated(&delegated) && !delegated) {
- log_and_set_response_error(
- error, UPDATE_ENGINE_SERVICE_ERROR_FAILED,
+ LogAndSetError(
+ error, FROM_HERE,
"Cannot set target channel explicitly when channel "
"policy/settings is not delegated");
- return FALSE;
+ return false;
}
- LOG(INFO) << "Setting destination channel to: " << target_channel;
- if (!self->system_state_->request_params()->SetTargetChannel(
- target_channel, is_powerwash_allowed)) {
+ LOG(INFO) << "Setting destination channel to: " << in_target_channel;
+ if (!system_state_->request_params()->SetTargetChannel(
+ in_target_channel, in_is_powerwash_allowed)) {
// TODO(dgarrett): Give a more specific error code/reason.
- log_and_set_response_error(error,
- UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Setting channel failed.");
- return FALSE;
+ LogAndSetError(error, FROM_HERE, "Setting channel failed.");
+ return false;
}
-
- return TRUE;
+ return true;
}
-gboolean update_engine_service_get_channel(UpdateEngineService* self,
- gboolean get_current_channel,
- gchar** channel,
- GError **error) {
- chromeos_update_engine::OmahaRequestParams* rp =
- self->system_state_->request_params();
-
- string channel_str = get_current_channel ?
- rp->current_channel() : rp->target_channel();
-
- *channel = g_strdup(channel_str.c_str());
- return TRUE;
+bool UpdateEngineService::GetChannel(ErrorPtr* /* error */,
+ bool in_get_current_channel,
+ string* out_channel) {
+ OmahaRequestParams* rp = system_state_->request_params();
+ *out_channel = (in_get_current_channel ?
+ rp->current_channel() : rp->target_channel());
+ return true;
}
-gboolean update_engine_service_set_p2p_update_permission(
- UpdateEngineService* self,
- gboolean enabled,
- GError **error) {
- chromeos_update_engine::PrefsInterface* prefs = self->system_state_->prefs();
+bool UpdateEngineService::SetP2PUpdatePermission(ErrorPtr* error,
+ bool in_enabled) {
+ PrefsInterface* prefs = system_state_->prefs();
- if (!prefs->SetBoolean(chromeos_update_engine::kPrefsP2PEnabled, enabled)) {
- log_and_set_response_error(
- error, UPDATE_ENGINE_SERVICE_ERROR_FAILED,
+ if (!prefs->SetBoolean(kPrefsP2PEnabled, in_enabled)) {
+ LogAndSetError(
+ error, FROM_HERE,
StringPrintf("Error setting the update via p2p permission to %s.",
- ToString(enabled).c_str()));
- return FALSE;
+ ToString(in_enabled).c_str()));
+ return false;
}
-
- return TRUE;
+ return true;
}
-gboolean update_engine_service_get_p2p_update_permission(
- UpdateEngineService* self,
- gboolean* enabled,
- GError **error) {
- chromeos_update_engine::PrefsInterface* prefs = self->system_state_->prefs();
+bool UpdateEngineService::GetP2PUpdatePermission(ErrorPtr* error,
+ bool* out_enabled) {
+ PrefsInterface* prefs = system_state_->prefs();
bool p2p_pref = false; // Default if no setting is present.
- if (prefs->Exists(chromeos_update_engine::kPrefsP2PEnabled) &&
- !prefs->GetBoolean(chromeos_update_engine::kPrefsP2PEnabled, &p2p_pref)) {
- log_and_set_response_error(error, UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Error getting the P2PEnabled setting.");
- return FALSE;
+ if (prefs->Exists(kPrefsP2PEnabled) &&
+ !prefs->GetBoolean(kPrefsP2PEnabled, &p2p_pref)) {
+ LogAndSetError(error, FROM_HERE, "Error getting the P2PEnabled setting.");
+ return false;
}
- *enabled = p2p_pref;
- return TRUE;
+ *out_enabled = p2p_pref;
+ return true;
}
-gboolean update_engine_service_set_update_over_cellular_permission(
- UpdateEngineService* self,
- gboolean allowed,
- GError **error) {
+bool UpdateEngineService::SetUpdateOverCellularPermission(ErrorPtr* error,
+ bool in_allowed) {
set<string> allowed_types;
- const policy::DevicePolicy* device_policy =
- self->system_state_->device_policy();
+ const policy::DevicePolicy* device_policy = system_state_->device_policy();
// The device_policy is loaded in a lazy way before an update check. Load it
// now from the libchromeos cache if it wasn't already loaded.
if (!device_policy) {
- chromeos_update_engine::UpdateAttempter* update_attempter =
- self->system_state_->update_attempter();
+ UpdateAttempter* update_attempter = system_state_->update_attempter();
if (update_attempter) {
update_attempter->RefreshDevicePolicy();
- device_policy = self->system_state_->device_policy();
+ device_policy = system_state_->device_policy();
}
}
// Check if this setting is allowed by the device policy.
if (device_policy &&
device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
- log_and_set_response_error(
- error, UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "Ignoring the update over cellular setting since there's "
- "a device policy enforcing this setting.");
- return FALSE;
+ LogAndSetError(error, FROM_HERE,
+ "Ignoring the update over cellular setting since there's "
+ "a device policy enforcing this setting.");
+ return false;
}
// If the policy wasn't loaded yet, then it is still OK to change the local
// setting because the policy will be checked again during the update check.
- chromeos_update_engine::PrefsInterface* prefs = self->system_state_->prefs();
+ PrefsInterface* prefs = system_state_->prefs();
- if (!prefs->SetBoolean(
- chromeos_update_engine::kPrefsUpdateOverCellularPermission,
- allowed)) {
- log_and_set_response_error(
- error, UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- string("Error setting the update over cellular to ") +
- (allowed ? "true" : "false"));
- return FALSE;
+ if (!prefs->SetBoolean(kPrefsUpdateOverCellularPermission, in_allowed)) {
+ LogAndSetError(error, FROM_HERE,
+ string("Error setting the update over cellular to ") +
+ (in_allowed ? "true" : "false"));
+ return false;
}
-
- return TRUE;
+ return true;
}
-gboolean update_engine_service_get_update_over_cellular_permission(
- UpdateEngineService* self,
- gboolean* allowed,
- GError **error) {
- chromeos_update_engine::ConnectionManagerInterface* cm =
- self->system_state_->connection_manager();
+bool UpdateEngineService::GetUpdateOverCellularPermission(ErrorPtr* /* error */,
+ bool* out_allowed) {
+ ConnectionManagerInterface* cm = system_state_->connection_manager();
// The device_policy is loaded in a lazy way before an update check and is
// used to determine if an update is allowed over cellular. Load the device
// policy now from the libchromeos cache if it wasn't already loaded.
- if (!self->system_state_->device_policy()) {
- chromeos_update_engine::UpdateAttempter* update_attempter =
- self->system_state_->update_attempter();
+ if (!system_state_->device_policy()) {
+ UpdateAttempter* update_attempter = system_state_->update_attempter();
if (update_attempter)
update_attempter->RefreshDevicePolicy();
}
@@ -424,53 +259,70 @@
// Return the current setting based on the same logic used while checking for
// updates. A log message could be printed as the result of this test.
LOG(INFO) << "Checking if updates over cellular networks are allowed:";
- *allowed = cm->IsUpdateAllowedOver(
+ *out_allowed = cm->IsUpdateAllowedOver(
chromeos_update_engine::NetworkConnectionType::kCellular,
chromeos_update_engine::NetworkTethering::kUnknown);
-
- return TRUE;
+ return true;
}
-gboolean update_engine_service_get_duration_since_update(
- UpdateEngineService* self,
- gint64* out_usec_wallclock,
- GError **error) {
-
+bool UpdateEngineService::GetDurationSinceUpdate(ErrorPtr* error,
+ int64_t* out_usec_wallclock) {
base::Time time;
- if (!self->system_state_->update_attempter()->GetBootTimeAtUpdate(&time)) {
- log_and_set_response_error(error, UPDATE_ENGINE_SERVICE_ERROR_FAILED,
- "No pending update.");
- return FALSE;
+ if (!system_state_->update_attempter()->GetBootTimeAtUpdate(&time)) {
+ LogAndSetError(error, FROM_HERE, "No pending update.");
+ return false;
}
- chromeos_update_engine::ClockInterface *clock = self->system_state_->clock();
+ ClockInterface* clock = system_state_->clock();
*out_usec_wallclock = (clock->GetBootTime() - time).InMicroseconds();
- return TRUE;
+ return true;
}
-gboolean update_engine_service_emit_status_update(
- UpdateEngineService* self,
- gint64 last_checked_time,
- gdouble progress,
- const gchar* current_operation,
- const gchar* new_version,
- gint64 new_size) {
- g_signal_emit(self,
- status_update_signal,
- 0,
- last_checked_time,
- progress,
- current_operation,
- new_version,
- new_size);
- return TRUE;
+bool UpdateEngineService::GetPrevVersion(ErrorPtr* /* error */,
+ string* out_prev_version) {
+ *out_prev_version = system_state_->update_attempter()->GetPrevVersion();
+ return true;
}
-gboolean update_engine_service_get_prev_version(
- UpdateEngineService* self,
- gchar** prev_version,
- GError **error) {
- string ver = self->system_state_->update_attempter()->GetPrevVersion();
- *prev_version = g_strdup(ver.c_str());
- return TRUE;
+bool UpdateEngineService::GetKernelDevices(ErrorPtr* /* error */,
+ string* out_kernel_devices) {
+ auto devices = system_state_->update_attempter()->GetKernelDevices();
+ string info;
+ for (const auto& device : devices) {
+ base::StringAppendF(&info, "%d:%s\n",
+ device.second ? 1 : 0, device.first.c_str());
+ }
+ LOG(INFO) << "Available kernel devices: " << info;
+ *out_kernel_devices = info;
+ return true;
}
+
+bool UpdateEngineService::GetRollbackPartition(
+ ErrorPtr* /* error */,
+ string* out_rollback_partition_name) {
+ string name = system_state_->update_attempter()->GetRollbackPartition();
+ LOG(INFO) << "Getting rollback partition name. Result: " << name;
+ *out_rollback_partition_name = name;
+ return true;
+}
+
+
+UpdateEngineAdaptor::UpdateEngineAdaptor(SystemState* system_state,
+ const scoped_refptr<dbus::Bus>& bus)
+ : org::chromium::UpdateEngineInterfaceAdaptor(&dbus_service_),
+ bus_(bus),
+ dbus_service_(system_state),
+ dbus_object_(nullptr, bus, dbus::ObjectPath(kUpdateEngineServicePath)) {}
+
+void UpdateEngineAdaptor::RegisterAsync(
+ const base::Callback<void(bool)>& completion_callback) {
+ RegisterWithDBusObject(&dbus_object_);
+ dbus_object_.RegisterAsync(completion_callback);
+}
+
+bool UpdateEngineAdaptor::RequestOwnership() {
+ return bus_->RequestOwnershipAndBlock(kUpdateEngineServiceName,
+ dbus::Bus::REQUIRE_PRIMARY);
+}
+
+} // namespace chromeos_update_engine
diff --git a/dbus_service.h b/dbus_service.h
index d61e3b5..6429240 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -7,171 +7,153 @@
#include <inttypes.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <glib-object.h>
+#include <string>
+
+#include <base/memory/ref_counted.h>
+#include <chromeos/errors/error.h>
#include "update_engine/update_attempter.h"
-// Type macros:
-#define UPDATE_ENGINE_TYPE_SERVICE (update_engine_service_get_type())
-#define UPDATE_ENGINE_SERVICE(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), UPDATE_ENGINE_TYPE_SERVICE, \
- UpdateEngineService))
-#define UPDATE_ENGINE_IS_SERVICE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), UPDATE_ENGINE_TYPE_SERVICE))
-#define UPDATE_ENGINE_SERVICE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), UPDATE_ENGINE_TYPE_SERVICE, \
- UpdateEngineService))
-#define UPDATE_ENGINE_IS_SERVICE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), UPDATE_ENGINE_TYPE_SERVICE))
-#define UPDATE_ENGINE_SERVICE_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), UPDATE_ENGINE_TYPE_SERVICE, \
- UpdateEngineService))
+#include "update_engine/dbus_adaptor/org.chromium.UpdateEngineInterface.h"
-G_BEGIN_DECLS
+namespace chromeos {
+namespace dbus {
+class Bus;
+} // namespace dbus
+} // namespace chromeos
-struct UpdateEngineService {
- GObject parent_instance;
+namespace chromeos_update_engine {
- chromeos_update_engine::SystemState* system_state_;
+class UpdateEngineService
+ : public org::chromium::UpdateEngineInterfaceInterface {
+ public:
+ explicit UpdateEngineService(SystemState* system_state);
+ virtual ~UpdateEngineService() = default;
+
+ // Implementation of org::chromium::UpdateEngineInterfaceInterface.
+ bool AttemptUpdate(chromeos::ErrorPtr* error,
+ const std::string& in_app_version,
+ const std::string& in_omaha_url) override;
+
+ bool AttemptUpdateWithFlags(chromeos::ErrorPtr* error,
+ const std::string& in_app_version,
+ const std::string& in_omaha_url,
+ int32_t in_flags_as_int) override;
+
+ bool AttemptRollback(chromeos::ErrorPtr* error, bool in_powerwash) override;
+
+ // Checks if the system rollback is available by verifying if the secondary
+ // system partition is valid and bootable.
+ bool CanRollback(chromeos::ErrorPtr* error, bool* out_can_rollback) override;
+
+ // Resets the status of the update_engine to idle, ignoring any applied
+ // update. This is used for development only.
+ bool ResetStatus(chromeos::ErrorPtr* error) override;
+
+ // Returns the current status of the Update Engine. If an update is in
+ // progress, the number of operations, size to download and overall progress
+ // is reported.
+ bool GetStatus(chromeos::ErrorPtr* error,
+ int64_t* out_last_checked_time,
+ double* out_progress,
+ std::string* out_current_operation,
+ std::string* out_new_version,
+ int64_t* out_new_size) override;
+
+ // Reboots the device if an update is applied and a reboot is required.
+ bool RebootIfNeeded(chromeos::ErrorPtr* error) override;
+
+ // Changes the current channel of the device to the target channel. If the
+ // target channel is a less stable channel than the current channel, then the
+ // channel change happens immediately (at the next update check). If the
+ // target channel is a more stable channel, then if is_powerwash_allowed is
+ // set to true, then also the change happens immediately but with a powerwash
+ // if required. Otherwise, the change takes effect eventually (when the
+ // version on the target channel goes above the version number of what the
+ // device currently has).
+ bool SetChannel(chromeos::ErrorPtr* error,
+ const std::string& in_target_channel,
+ bool in_is_powerwash_allowed) override;
+
+ // If get_current_channel is set to true, populates |channel| with the name of
+ // the channel that the device is currently on. Otherwise, it populates it
+ // with the name of the channel the device is supposed to be (in case of a
+ // pending channel change).
+ bool GetChannel(chromeos::ErrorPtr* error,
+ bool in_get_current_channel,
+ std::string* out_channel) override;
+
+ // Enables or disables the sharing and consuming updates over P2P feature
+ // according to the |enabled| argument passed.
+ bool SetP2PUpdatePermission(chromeos::ErrorPtr* error,
+ bool in_enabled) override;
+
+ // Returns the current value for the P2P enabled setting. This involves both
+ // sharing and consuming updates over P2P.
+ bool GetP2PUpdatePermission(chromeos::ErrorPtr* error,
+ bool* out_enabled) override;
+
+ // If there's no device policy installed, sets the update over cellular
+ // networks permission to the |allowed| value. Otherwise, this method returns
+ // with an error since this setting is overridden by the applied policy.
+ bool SetUpdateOverCellularPermission(chromeos::ErrorPtr* error,
+ bool in_allowed) override;
+
+ // Returns the current value of the update over cellular network setting,
+ // either forced by the device policy if the device is enrolled or the current
+ // user preference otherwise.
+ bool GetUpdateOverCellularPermission(chromeos::ErrorPtr* error,
+ bool* out_allowed) override;
+
+ // Returns the duration since the last successful update, as the
+ // duration on the wallclock. Returns an error if the device has not
+ // updated.
+ bool GetDurationSinceUpdate(chromeos::ErrorPtr* error,
+ int64_t* out_usec_wallclock) override;
+
+ // Returns the version string of OS that was used before the last reboot
+ // into an updated version. This is available only when rebooting into an
+ // update from previous version, otherwise an empty string is returned.
+ bool GetPrevVersion(chromeos::ErrorPtr* error,
+ std::string* out_prev_version) override;
+
+ // Returns a list of available kernel partitions and whether each of them
+ // can be booted from or not.
+ bool GetKernelDevices(chromeos::ErrorPtr* error,
+ std::string* out_kernel_devices) override;
+
+ // Returns the name of kernel partition that can be rolled back into.
+ bool GetRollbackPartition(chromeos::ErrorPtr* error,
+ std::string* out_rollback_partition_name) override;
+
+ private:
+ SystemState* system_state_;
};
-struct UpdateEngineServiceClass {
- GObjectClass parent_class;
+// The UpdateEngineAdaptor class runs the UpdateEngineInterface in the fixed
+// object path, without an ObjectManager notifying the interfaces, since it is
+// all static and clients don't expect it to be implemented.
+class UpdateEngineAdaptor : public org::chromium::UpdateEngineInterfaceAdaptor {
+ public:
+ UpdateEngineAdaptor(SystemState* system_state,
+ const scoped_refptr<dbus::Bus>& bus);
+ ~UpdateEngineAdaptor() = default;
+
+ // Register the DBus object with the update engine service asynchronously.
+ // Calls |copmletion_callback| when done passing a boolean indicating if the
+ // registration succeeded.
+ void RegisterAsync(const base::Callback<void(bool)>& completion_callback);
+
+ // Takes ownership of the well-known DBus name and returns whether it
+ // succeeded.
+ bool RequestOwnership();
+
+ private:
+ scoped_refptr<dbus::Bus> bus_;
+ UpdateEngineService dbus_service_;
+ chromeos::dbus_utils::DBusObject dbus_object_;
};
-UpdateEngineService* update_engine_service_new(void);
-GType update_engine_service_get_type(void);
-
-// Methods
-
-gboolean update_engine_service_attempt_update(UpdateEngineService* self,
- gchar* app_version,
- gchar* omaha_url,
- GError **error);
-
-gboolean update_engine_service_attempt_update_with_flags(
- UpdateEngineService* self,
- gchar* app_version,
- gchar* omaha_url,
- gint flags_as_int,
- GError **error);
-
-gboolean update_engine_service_attempt_rollback(UpdateEngineService* self,
- gboolean powerwash,
- GError **error);
-
-// Checks if the system rollback is available by verifying if the secondary
-// system partition is valid and bootable.
-gboolean update_engine_service_can_rollback(
- UpdateEngineService* self,
- gboolean* out_can_rollback,
- GError **error);
-
-// Returns the name of kernel partition that can be rolled back into.
-gboolean update_engine_service_get_rollback_partition(
- UpdateEngineService* self,
- gchar** out_rollback_partition_name,
- GError **error);
-
-// Returns a list of available kernel partitions and whether each of them
-// can be booted from or not.
-gboolean update_engine_service_get_kernel_devices(UpdateEngineService* self,
- gchar** out_kernel_devices,
- GError **error);
-
-gboolean update_engine_service_reset_status(UpdateEngineService* self,
- GError **error);
-
-gboolean update_engine_service_get_status(UpdateEngineService* self,
- int64_t* last_checked_time,
- double* progress,
- gchar** current_operation,
- gchar** new_version,
- int64_t* new_size,
- GError **error);
-
-gboolean update_engine_service_reboot_if_needed(UpdateEngineService* self,
- GError **error);
-
-// Changes the current channel of the device to the target channel. If the
-// target channel is a less stable channel than the current channel, then the
-// channel change happens immediately (at the next update check). If the
-// target channel is a more stable channel, then if is_powerwash_allowed is set
-// to true, then also the change happens immediately but with a powerwash if
-// required. Otherwise, the change takes effect eventually (when the version on
-// the target channel goes above the version number of what the device
-// currently has).
-gboolean update_engine_service_set_channel(UpdateEngineService* self,
- gchar* target_channel,
- gboolean is_powerwash_allowed,
- GError **error);
-
-// If get_current_channel is set to true, populates |channel| with the name of
-// the channel that the device is currently on. Otherwise, it populates it with
-// the name of the channel the device is supposed to be (in case of a pending
-// channel change).
-gboolean update_engine_service_get_channel(UpdateEngineService* self,
- gboolean get_current_channel,
- gchar** channel,
- GError **error);
-
-// Enables or disables the sharing and consuming updates over P2P feature
-// according to the |enabled| argument passed.
-gboolean update_engine_service_set_p2p_update_permission(
- UpdateEngineService* self,
- gboolean enabled,
- GError **error);
-
-// Returns in |enabled| the current value for the P2P enabled setting. This
-// involves both sharing and consuming updates over P2P.
-gboolean update_engine_service_get_p2p_update_permission(
- UpdateEngineService* self,
- gboolean* enabled,
- GError **error);
-
-// If there's no device policy installed, sets the update over cellular networks
-// permission to the |allowed| value. Otherwise, this method returns with an
-// error since this setting is overridden by the applied policy.
-gboolean update_engine_service_set_update_over_cellular_permission(
- UpdateEngineService* self,
- gboolean allowed,
- GError **error);
-
-// Returns the current value of the update over cellular network setting, either
-// forced by the device policy if the device is enrolled or the current user
-// preference otherwise.
-gboolean update_engine_service_get_update_over_cellular_permission(
- UpdateEngineService* self,
- gboolean* allowed,
- GError **error);
-
-// Returns the duration since the last successful update, as the
-// duration on the wallclock. Returns an error if the device has not
-// updated.
-gboolean update_engine_service_get_duration_since_update(
- UpdateEngineService* self,
- gint64* out_usec_wallclock,
- GError **error);
-
-gboolean update_engine_service_emit_status_update(
- UpdateEngineService* self,
- gint64 last_checked_time,
- gdouble progress,
- const gchar* current_operation,
- const gchar* new_version,
- gint64 new_size);
-
-// Returns the version string of OS that was used before the last reboot
-// into an updated version. This is available only when rebooting into an
-// update from previous version, otherwise an empty string is returned.
-gboolean update_engine_service_get_prev_version(
- UpdateEngineService* self,
- gchar** prev_version,
- GError **error);
-
-G_END_DECLS
+} // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_DBUS_SERVICE_H_
diff --git a/dbus_service_unittest.cc b/dbus_service_unittest.cc
new file mode 100644
index 0000000..441f89d
--- /dev/null
+++ b/dbus_service_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "update_engine/dbus_service.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include <chromeos/errors/error.h>
+#include <policy/libpolicy.h>
+#include <policy/mock_device_policy.h>
+
+#include "update_engine/dbus_constants.h"
+#include "update_engine/fake_system_state.h"
+
+using std::string;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::_;
+
+using chromeos::errors::dbus::kDomain;
+
+namespace chromeos_update_engine {
+
+class UpdateEngineServiceTest : public ::testing::Test {
+ protected:
+ UpdateEngineServiceTest()
+ : mock_update_attempter_(fake_system_state_.mock_update_attempter()),
+ dbus_service_(&fake_system_state_) {}
+
+ void SetUp() override {
+ fake_system_state_.set_device_policy(nullptr);
+ }
+
+ // Fake/mock infrastructure.
+ FakeSystemState fake_system_state_;
+ policy::MockDevicePolicy mock_device_policy_;
+
+ // Shortcut for fake_system_state_.mock_update_attempter().
+ MockUpdateAttempter* mock_update_attempter_;
+
+ chromeos::ErrorPtr error_;
+ UpdateEngineService dbus_service_;
+};
+
+TEST_F(UpdateEngineServiceTest, AttemptUpdate) {
+ // Simple test to ensure that the default is an interactive check.
+ EXPECT_CALL(*mock_update_attempter_,
+ CheckForUpdate("app_ver", "url", true /* interactive */));
+ EXPECT_TRUE(dbus_service_.AttemptUpdate(&error_, "app_ver", "url"));
+ EXPECT_EQ(nullptr, error_);
+}
+
+TEST_F(UpdateEngineServiceTest, AttemptUpdateWithFlags) {
+ EXPECT_CALL(*mock_update_attempter_, CheckForUpdate(
+ "app_ver", "url", false /* interactive */));
+ // The update is non-interactive when we pass the non-interactive flag.
+ EXPECT_TRUE(dbus_service_.AttemptUpdateWithFlags(
+ &error_, "app_ver", "url", kAttemptUpdateFlagNonInteractive));
+ EXPECT_EQ(nullptr, error_);
+}
+
+// SetChannel is allowed when there's no device policy (the device is not
+// enterprise enrolled).
+TEST_F(UpdateEngineServiceTest, SetChannelWithNoPolicy) {
+ EXPECT_CALL(*mock_update_attempter_, RefreshDevicePolicy());
+ // If SetTargetChannel is called it means the policy check passed.
+ EXPECT_CALL(*fake_system_state_.mock_request_params(),
+ SetTargetChannel("stable-channel", true))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(dbus_service_.SetChannel(&error_, "stable-channel", true));
+ ASSERT_EQ(nullptr, error_);
+}
+
+// When the policy is present, the delegated value should be checked.
+TEST_F(UpdateEngineServiceTest, SetChannelWithDelegatedPolicy) {
+ policy::MockDevicePolicy mock_device_policy;
+ fake_system_state_.set_device_policy(&mock_device_policy);
+ EXPECT_CALL(mock_device_policy, GetReleaseChannelDelegated(_))
+ .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
+ EXPECT_CALL(*fake_system_state_.mock_request_params(),
+ SetTargetChannel("beta-channel", true))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(dbus_service_.SetChannel(&error_, "beta-channel", true));
+ ASSERT_EQ(nullptr, error_);
+}
+
+// When passing an invalid value (SetTargetChannel fails) an error should be
+// raised.
+TEST_F(UpdateEngineServiceTest, SetChannelWithInvalidChannel) {
+ EXPECT_CALL(*mock_update_attempter_, RefreshDevicePolicy());
+ EXPECT_CALL(*fake_system_state_.mock_request_params(),
+ SetTargetChannel("foo-channel", true)).WillOnce(Return(false));
+
+ EXPECT_FALSE(dbus_service_.SetChannel(&error_, "foo-channel", true));
+ ASSERT_NE(nullptr, error_);
+ EXPECT_TRUE(error_->HasError(kDomain, kUpdateEngineServiceErrorFailed));
+}
+
+TEST_F(UpdateEngineServiceTest, GetChannel) {
+ fake_system_state_.mock_request_params()->set_current_channel("current");
+ fake_system_state_.mock_request_params()->set_target_channel("target");
+ string channel;
+ EXPECT_TRUE(dbus_service_.GetChannel(
+ &error_, true /* get_current_channel */, &channel));
+ EXPECT_EQ(nullptr, error_);
+ EXPECT_EQ("current", channel);
+
+ EXPECT_TRUE(dbus_service_.GetChannel(
+ &error_, false /* get_current_channel */, &channel));
+ EXPECT_EQ(nullptr, error_);
+ EXPECT_EQ("target", channel);
+}
+
+TEST_F(UpdateEngineServiceTest, ResetStatusSucceeds) {
+ EXPECT_CALL(*mock_update_attempter_, ResetStatus()).WillOnce(Return(true));
+ EXPECT_TRUE(dbus_service_.ResetStatus(&error_));
+ EXPECT_EQ(nullptr, error_);
+}
+
+TEST_F(UpdateEngineServiceTest, ResetStatusFails) {
+ EXPECT_CALL(*mock_update_attempter_, ResetStatus()).WillOnce(Return(false));
+ EXPECT_FALSE(dbus_service_.ResetStatus(&error_));
+ ASSERT_NE(nullptr, error_);
+ EXPECT_TRUE(error_->HasError(kDomain, kUpdateEngineServiceErrorFailed));
+}
+
+} // namespace chromeos_update_engine
diff --git a/main.cc b/main.cc
index cf06f2a..4fe0c84 100644
--- a/main.cc
+++ b/main.cc
@@ -5,101 +5,30 @@
#include <unistd.h>
#include <string>
-#include <vector>
#include <base/at_exit.h>
#include <base/command_line.h>
#include <base/files/file_util.h>
-#include <base/location.h>
#include <base/logging.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
-#include <base/time/time.h>
#include <chromeos/flag_helper.h>
-#include <chromeos/message_loops/glib_message_loop.h>
+#include <chromeos/message_loops/base_message_loop.h>
#include <glib.h>
#include <metrics/metrics_library.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include "update_engine/certificate_checker.h"
-#include "update_engine/dbus_constants.h"
-#include "update_engine/dbus_service.h"
-#include "update_engine/dbus_wrapper_interface.h"
+#include "update_engine/daemon.h"
#include "update_engine/glib_utils.h"
-#include "update_engine/real_system_state.h"
-#include "update_engine/subprocess.h"
#include "update_engine/terminator.h"
-#include "update_engine/update_attempter.h"
-extern "C" {
-#include "update_engine/org.chromium.UpdateEngineInterface.dbusserver.h"
-}
#include "update_engine/utils.h"
using std::string;
-using std::vector;
-
-namespace {
-const int kDBusSystemMaxWaitSeconds = 2 * 60;
-} // namespace
namespace chromeos_update_engine {
-
namespace {
-// 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;
-
- bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
- LOG_IF(FATAL, !bus) << "Failed to get bus: "
- << utils::GetAndFreeGError(&error);
- proxy = dbus_g_proxy_new_for_name(bus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS);
- guint32 request_name_ret;
- if (!org_freedesktop_DBus_request_name(proxy,
- kUpdateEngineServiceName,
- 0,
- &request_name_ret,
- &error)) {
- LOG(FATAL) << "Failed to get name: " << utils::GetAndFreeGError(&error);
- }
- if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_warning("Got result code %u from requesting name", request_name_ret);
- LOG(FATAL) << "Got result code " << request_name_ret
- << " from requesting name, but expected "
- << DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
- }
- dbus_g_connection_register_g_object(bus,
- "/org/chromium/UpdateEngine",
- G_OBJECT(service));
-}
-
void SetupLogSymlink(const string& symlink_path, const string& log_path) {
// TODO(petkov): To ensure a smooth transition between non-timestamped and
// timestamped logs, move an existing log to start the first timestamped
@@ -168,7 +97,6 @@
::g_type_init();
dbus_threads_init_default();
- base::AtExitManager exit_manager; // Required for base/rand_util.h.
chromeos_update_engine::Terminator::Init();
chromeos::FlagHelper::Init(argc, argv, "Chromium OS Update Engine");
chromeos_update_engine::SetupLogging(FLAGS_logtostderr);
@@ -183,74 +111,10 @@
// Done _after_ log file creation.
umask(S_IXUSR | S_IRWXG | S_IRWXO);
- // Create the single Glib main loop. Code accessing directly the glib main
- // loop (such as calling g_timeout_add() or similar functions) will still work
- // since the backend for the message loop is still the Glib main loop.
- // TODO(deymo): Replace this |loop| with one based on libevent once no other
- // code here uses glib directly.
- chromeos::GlibMessageLoop loop;
- loop.SetAsCurrent();
+ chromeos_update_engine::UpdateEngineDaemon update_engine_daemon;
+ int exit_code = update_engine_daemon.Run();
- // The Subprocess class requires a chromeos::MessageLoop setup.
- chromeos_update_engine::Subprocess subprocess;
- subprocess.Init();
-
- // 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.";
- chromeos_update_engine::UpdateAttempter *update_attempter =
- real_system_state.update_attempter();
- CHECK(update_attempter);
-
- // Sets static members for the certificate checker.
- chromeos_update_engine::CertificateChecker::set_system_state(
- &real_system_state);
- chromeos_update_engine::OpenSSLWrapper openssl_wrapper;
- chromeos_update_engine::CertificateChecker::set_openssl_wrapper(
- &openssl_wrapper);
-
- // Create the dbus service object:
- dbus_g_object_type_install_info(UPDATE_ENGINE_TYPE_SERVICE,
- &dbus_glib_update_engine_service_object_info);
- UpdateEngineService* service = update_engine_service_new();
- service->system_state_ = &real_system_state;
- update_attempter->set_dbus_service(service);
- chromeos_update_engine::SetupDBusService(service);
-
- // Initiate update checks.
- update_attempter->ScheduleUpdates();
-
- // Update boot flags after 45 seconds.
- loop.PostDelayedTask(
- FROM_HERE,
- base::Bind(&chromeos_update_engine::UpdateAttempter::UpdateBootFlags,
- base::Unretained(update_attempter)),
- base::TimeDelta::FromSeconds(45));
-
- // Broadcast the update engine status on startup to ensure consistent system
- // state on crashes.
- loop.PostTask(FROM_HERE, base::Bind(
- &chromeos_update_engine::UpdateAttempter::BroadcastStatus,
- base::Unretained(update_attempter)));
-
- // Run the UpdateEngineStarted() method on |update_attempter|.
- loop.PostTask(FROM_HERE, base::Bind(
- &chromeos_update_engine::UpdateAttempter::UpdateEngineStarted,
- base::Unretained(update_attempter)));
-
- // Run the main loop until exit time:
- loop.Run();
-
- // Cleanup:
- update_attempter->set_dbus_service(nullptr);
- g_object_unref(G_OBJECT(service));
-
- loop.ReleaseFromCurrent();
- LOG(INFO) << "Chrome OS Update Engine terminating";
- return 0;
+ LOG(INFO) << "Chrome OS Update Engine terminating with exit code "
+ << exit_code;
+ return exit_code;
}
diff --git a/p2p_manager_unittest.cc b/p2p_manager_unittest.cc
index ec93bc6..3b1f1c0 100644
--- a/p2p_manager_unittest.cc
+++ b/p2p_manager_unittest.cc
@@ -18,6 +18,7 @@
#include <base/callback.h>
#include <base/files/file_util.h>
#include <base/strings/stringprintf.h>
+#include <chromeos/asynchronous_signal_handler.h>
#include <chromeos/message_loops/glib_message_loop.h>
#include <chromeos/message_loops/message_loop.h>
#include <chromeos/message_loops/message_loop_utils.h>
@@ -57,7 +58,8 @@
// Derived from testing::Test.
void SetUp() override {
loop_.SetAsCurrent();
- subprocess_.Init();
+ async_signal_handler_.Init();
+ subprocess_.Init(&async_signal_handler_);
test_conf_ = new FakeP2PManagerConfiguration();
// Allocate and install a mock policy implementation in the fake Update
@@ -76,6 +78,7 @@
// interact with the p2p-client tool, so we need to run a GlibMessageLoop
// here.
chromeos::GlibMessageLoop loop_;
+ chromeos::AsynchronousSignalHandler async_signal_handler_;
Subprocess subprocess_;
// The P2PManager::Configuration instance used for testing.
diff --git a/postinstall_runner_action_unittest.cc b/postinstall_runner_action_unittest.cc
index ff64128..5131239 100644
--- a/postinstall_runner_action_unittest.cc
+++ b/postinstall_runner_action_unittest.cc
@@ -37,7 +37,8 @@
protected:
void SetUp() override {
loop_.SetAsCurrent();
- subprocess_.Init();
+ async_signal_handler_.Init();
+ subprocess_.Init(&async_signal_handler_);
}
// DoTest with various combinations of do_losetup, err_code and
@@ -48,6 +49,7 @@
static const char* kImageMountPointTemplate;
chromeos::GlibMessageLoop loop_;
+ chromeos::AsynchronousSignalHandler async_signal_handler_;
Subprocess subprocess_;
};
diff --git a/subprocess.cc b/subprocess.cc
index 6282b2c..fa7e4cb 100644
--- a/subprocess.cc
+++ b/subprocess.cc
@@ -80,14 +80,14 @@
} // namespace
-void Subprocess::Init() {
+void Subprocess::Init(
+ chromeos::AsynchronousSignalHandlerInterface* async_signal_handler) {
if (subprocess_singleton_ == this)
return;
CHECK(subprocess_singleton_ == nullptr);
subprocess_singleton_ = this;
- async_signal_handler_.Init();
- process_reaper_.Register(&async_signal_handler_);
+ process_reaper_.Register(async_signal_handler);
}
Subprocess::~Subprocess() {
diff --git a/subprocess.h b/subprocess.h
index c26ea60..775b95f 100644
--- a/subprocess.h
+++ b/subprocess.h
@@ -15,7 +15,7 @@
#include <base/callback.h>
#include <base/logging.h>
#include <base/macros.h>
-#include <chromeos/asynchronous_signal_handler.h>
+#include <chromeos/asynchronous_signal_handler_interface.h>
#include <chromeos/message_loops/message_loop.h>
#include <chromeos/process.h>
#include <chromeos/process_reaper.h>
@@ -49,7 +49,7 @@
~Subprocess();
// Initialize and register the Subprocess singleton.
- void Init();
+ void Init(chromeos::AsynchronousSignalHandlerInterface* async_signal_handler);
// Launches a process in the background and calls the passed |callback| when
// the process exits.
@@ -119,7 +119,6 @@
std::map<pid_t, std::unique_ptr<SubprocessRecord>> subprocess_records_;
// Used to watch for child processes.
- chromeos::AsynchronousSignalHandler async_signal_handler_;
chromeos::ProcessReaper process_reaper_;
DISALLOW_COPY_AND_ASSIGN(Subprocess);
diff --git a/subprocess_unittest.cc b/subprocess_unittest.cc
index 2660456..3933f25 100644
--- a/subprocess_unittest.cc
+++ b/subprocess_unittest.cc
@@ -43,12 +43,14 @@
protected:
void SetUp() override {
loop_.SetAsCurrent();
- subprocess_.Init();
+ async_signal_handler_.Init();
+ subprocess_.Init(&async_signal_handler_);
}
// TODO(deymo): Replace this with a FakeMessageLoop. Subprocess uses glib to
// asynchronously spawn a process, so we need to run a GlibMessageLoop here.
chromeos::GlibMessageLoop loop_;
+ chromeos::AsynchronousSignalHandler async_signal_handler_;
Subprocess subprocess_;
};
diff --git a/update_attempter.cc b/update_attempter.cc
index 3afe2ac..762a7e5 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -1243,12 +1243,10 @@
}
void UpdateAttempter::BroadcastStatus() {
- if (!dbus_service_) {
+ if (!dbus_adaptor_)
return;
- }
last_notify_time_ = TimeTicks::Now();
- update_engine_service_emit_status_update(
- dbus_service_,
+ dbus_adaptor_->SendStatusUpdateSignal(
last_checked_time_,
download_progress_,
UpdateStatusToString(status_),
diff --git a/update_attempter.h b/update_attempter.h
index 48d344f..ea32fe4 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -28,7 +28,6 @@
#include "update_engine/update_manager/update_manager.h"
class MetricsLibraryInterface;
-struct UpdateEngineService;
namespace policy {
class PolicyProvider;
@@ -36,6 +35,7 @@
namespace chromeos_update_engine {
+class UpdateEngineAdaptor;
class DBusWrapperInterface;
enum UpdateStatus {
@@ -119,8 +119,8 @@
int http_response_code() const { return http_response_code_; }
void set_http_response_code(int code) { http_response_code_ = code; }
- void set_dbus_service(struct UpdateEngineService* dbus_service) {
- dbus_service_ = dbus_service;
+ void set_dbus_adaptor(UpdateEngineAdaptor* dbus_adaptor) {
+ dbus_adaptor_ = dbus_adaptor;
}
// This is the internal entry point for going through an
@@ -400,7 +400,7 @@
// If non-null, this UpdateAttempter will send status updates over this
// dbus service.
- UpdateEngineService* dbus_service_ = nullptr;
+ UpdateEngineAdaptor* dbus_adaptor_ = nullptr;
// Pointer to the OmahaResponseHandlerAction in the actions_ vector.
std::shared_ptr<OmahaResponseHandlerAction> response_handler_action_;
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 07ba451..941f2b2 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -116,7 +116,7 @@
void SetUp() override {
CHECK(utils::MakeTempDirectory("UpdateAttempterTest-XXXXXX", &test_dir_));
- EXPECT_EQ(nullptr, attempter_.dbus_service_);
+ EXPECT_EQ(nullptr, attempter_.dbus_adaptor_);
EXPECT_NE(nullptr, attempter_.system_state_);
EXPECT_EQ(0, attempter_.http_response_code_);
EXPECT_EQ(utils::kCpuSharesNormal, attempter_.shares_);
diff --git a/update_engine.gyp b/update_engine.gyp
index f377500..1ddb4d9 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -59,19 +59,17 @@
],
'includes': ['../common-mk/protoc.gypi'],
},
- # D-Bus glib bindings.
+ # Chrome D-Bus bindings.
{
- 'target_name': 'update_engine-dbus-server',
+ 'target_name': 'update_engine-dbus-adaptor',
'type': 'none',
'variables': {
- 'dbus_glib_type': 'server',
- 'dbus_glib_out_dir': 'include/update_engine',
- 'dbus_glib_prefix': 'update_engine_service',
+ 'dbus_adaptors_out_dir': 'include/update_engine/dbus_adaptor',
},
'sources': [
'dbus_bindings/org.chromium.UpdateEngineInterface.xml',
],
- 'includes': ['../common-mk/dbus_glib.gypi'],
+ 'includes': ['../common-mk/generate-dbus-adaptors.gypi'],
},
# The main static_library with all the code.
{
@@ -125,6 +123,7 @@
'clock.cc',
'connection_manager.cc',
'constants.cc',
+ 'daemon.cc',
'dbus_service.cc',
'delta_performer.cc',
'download_action.cc',
@@ -191,7 +190,7 @@
'type': 'executable',
'dependencies': [
'libupdate_engine',
- 'update_engine-dbus-server',
+ 'update_engine-dbus-adaptor',
],
'sources': [
'main.cc',
@@ -369,6 +368,7 @@
'certificate_checker_unittest.cc',
'chrome_browser_proxy_resolver_unittest.cc',
'connection_manager_unittest.cc',
+ 'dbus_service_unittest.cc',
'delta_performer_unittest.cc',
'download_action_unittest.cc',
'extent_writer_unittest.cc',