AU: DBus support.
A few changes to support dbus in the Update Engine daemon:
- SConstruct: build marshaller for the dbus signal.
- Update Attempter: respond to dbus calls and broadcast status on dbus
signal.
- Update Engine Client: flag to listen for status updates.
- Also, cleanup outdated code in Omaha Response Handler.
BUG=None
TEST=attached unittests/on device tests
Review URL: http://codereview.chromium.org/2037002
diff --git a/update_attempter.cc b/update_attempter.cc
index ad3bd9e..ebfcd1d 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -3,10 +3,18 @@
// found in the LICENSE file.
#include "update_engine/update_attempter.h"
+
+// From 'man clock_gettime': feature test macro: _POSIX_C_SOURCE >= 199309L
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199309L
+#endif // _POSIX_C_SOURCE
+#include <time.h>
+
#include <tr1/memory>
#include <string>
#include <vector>
#include <glib.h>
+#include "update_engine/dbus_service.h"
#include "update_engine/download_action.h"
#include "update_engine/filesystem_copier_action.h"
#include "update_engine/libcurl_http_fetcher.h"
@@ -22,6 +30,59 @@
namespace chromeos_update_engine {
+namespace {
+// Returns true on success.
+bool GetCPUClockTime(struct timespec* out) {
+ return clock_gettime(CLOCK_REALTIME, out) == 0;
+}
+// Returns stop - start.
+struct timespec CPUClockTimeElapsed(const struct timespec& start,
+ const struct timespec& stop) {
+ CHECK(start.tv_sec >= 0);
+ CHECK(stop.tv_sec >= 0);
+ CHECK(start.tv_nsec >= 0);
+ CHECK(stop.tv_nsec >= 0);
+
+ const int64_t kOneBillion = 1000000000L;
+ const int64_t start64 = start.tv_sec * kOneBillion + start.tv_nsec;
+ const int64_t stop64 = stop.tv_sec * kOneBillion + stop.tv_nsec;
+
+ const int64_t result64 = stop64 - start64;
+
+ struct timespec ret;
+ ret.tv_sec = result64 / kOneBillion;
+ ret.tv_nsec = result64 % kOneBillion;
+
+ return ret;
+}
+bool CPUClockTimeGreaterThanHalfSecond(const struct timespec& spec) {
+ if (spec.tv_sec >= 1)
+ return true;
+ return (spec.tv_nsec > 500000000);
+}
+}
+
+const char* UpdateStatusToString(UpdateStatus status) {
+ switch (status) {
+ case UPDATE_STATUS_IDLE:
+ return "UPDATE_STATUS_IDLE";
+ case UPDATE_STATUS_CHECKING_FOR_UPDATE:
+ return "UPDATE_STATUS_CHECKING_FOR_UPDATE";
+ case UPDATE_STATUS_UPDATE_AVAILABLE:
+ return "UPDATE_STATUS_UPDATE_AVAILABLE";
+ case UPDATE_STATUS_DOWNLOADING:
+ return "UPDATE_STATUS_DOWNLOADING";
+ case UPDATE_STATUS_VERIFYING:
+ return "UPDATE_STATUS_VERIFYING";
+ case UPDATE_STATUS_FINALIZING:
+ return "UPDATE_STATUS_FINALIZING";
+ case UPDATE_STATUS_UPDATED_NEED_REBOOT:
+ return "UPDATE_STATUS_UPDATED_NEED_REBOOT";
+ default:
+ return "unknown status";
+ }
+}
+
void UpdateAttempter::Update(bool force_full_update) {
full_update_ = force_full_update;
CHECK(!processor_.IsRunning());
@@ -46,7 +107,8 @@
new SetBootableFlagAction);
shared_ptr<PostinstallRunnerAction> postinstall_runner_action_postcommit(
new PostinstallRunnerAction(false));
-
+
+ download_action->set_delegate(this);
response_handler_action_ = response_handler_action;
actions_.push_back(shared_ptr<AbstractAction>(request_prep_action));
@@ -87,22 +149,63 @@
BondActions(set_bootable_flag_action.get(),
postinstall_runner_action_postcommit.get());
+ SetStatusAndNotify(UPDATE_STATUS_CHECKING_FOR_UPDATE);
processor_.StartProcessing();
}
-// Delegate method:
+void UpdateAttempter::CheckForUpdate() {
+ if (status_ != UPDATE_STATUS_IDLE) {
+ LOG(INFO) << "Check for update requested, but status is "
+ << UpdateStatusToString(status_) << ", so not checking.";
+ return;
+ }
+ Update(false);
+}
+
+// Delegate methods:
void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
bool success) {
CHECK(response_handler_action_);
- if (response_handler_action_->GotNoUpdateResponse()) {
- // All done.
- g_main_loop_quit(loop_);
- return;
- }
- if (!success) {
+ LOG(INFO) << "Processing Done.";
+ if (success) {
+ SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
+ } else {
LOG(INFO) << "Update failed.";
+ SetStatusAndNotify(UPDATE_STATUS_IDLE);
}
- g_main_loop_quit(loop_);
+}
+
+void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) {
+ download_progress_ = 0.0;
+ SetStatusAndNotify(UPDATE_STATUS_IDLE);
+}
+
+// Called whenever an action has finished processing, either successfully
+// or otherwise.
+void UpdateAttempter::ActionCompleted(ActionProcessor* processor,
+ AbstractAction* action,
+ bool success) {
+ // Reset download progress regardless of whether or not the download action
+ // succeeded.
+ const string type = action->Type();
+ if (type == DownloadAction::StaticType())
+ download_progress_ = 0.0;
+ if (!success)
+ return;
+ // Find out which action completed.
+ if (type == OmahaResponseHandlerAction::StaticType()) {
+ SetStatusAndNotify(UPDATE_STATUS_DOWNLOADING);
+ OmahaResponseHandlerAction* omaha_response_handler_action =
+ dynamic_cast<OmahaResponseHandlerAction*>(action);
+ CHECK(omaha_response_handler_action);
+ const InstallPlan& plan = omaha_response_handler_action->install_plan();
+ last_checked_time_ = time(NULL);
+ // TODO(adlr): put version in InstallPlan
+ new_version_ = "0.0.0.0";
+ new_size_ = plan.size;
+ } else if (type == DownloadAction::StaticType()) {
+ SetStatusAndNotify(UPDATE_STATUS_FINALIZING);
+ }
}
// Stop updating. An attempt will be made to record status to the disk
@@ -118,19 +221,49 @@
NOTIMPLEMENTED();
}
+void UpdateAttempter::BytesReceived(uint64_t bytes_received, uint64_t total) {
+ if (status_ != UPDATE_STATUS_DOWNLOADING) {
+ LOG(ERROR) << "BytesReceived called while not downloading.";
+ return;
+ }
+ download_progress_ = static_cast<double>(bytes_received) /
+ static_cast<double>(total);
+ // We self throttle here
+ timespec now;
+ now.tv_sec = 0;
+ now.tv_nsec = 0;
+ if (GetCPUClockTime(&now) &&
+ CPUClockTimeGreaterThanHalfSecond(
+ CPUClockTimeElapsed(last_notify_time_, now))) {
+ SetStatusAndNotify(UPDATE_STATUS_DOWNLOADING);
+ }
+}
+
bool UpdateAttempter::GetStatus(int64_t* last_checked_time,
double* progress,
std::string* current_operation,
std::string* new_version,
int64_t* new_size) {
- // TODO(adlr): Return actual status.
- *last_checked_time = 123;
- *progress = 0.2223;
- *current_operation = "DOWNLOADING";
- *new_version = "0.2.3.8";
- *new_size = 10002;
+ *last_checked_time = last_checked_time_;
+ *progress = download_progress_;
+ *current_operation = UpdateStatusToString(status_);
+ *new_version = new_version_;
+ *new_size = new_size_;
return true;
}
+void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) {
+ status_ = status;
+ if (!dbus_service_)
+ return;
+ GetCPUClockTime(&last_notify_time_);
+ update_engine_service_emit_status_update(
+ dbus_service_,
+ last_checked_time_,
+ download_progress_,
+ UpdateStatusToString(status_),
+ new_version_.c_str(),
+ new_size_);
+}
} // namespace chromeos_update_engine