Index: src/platform/update_engine/update_attempter.cc |
diff --git a/src/platform/update_engine/update_attempter.cc b/src/platform/update_engine/update_attempter.cc |
index ad3bd9eaab8eca6d55767c38673b3e4793b0e30f..8df263bcc98f15af71d7980cf921c37305014f22 100644 |
--- a/src/platform/update_engine/update_attempter.cc |
+++ b/src/platform/update_engine/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 @@ using std::vector; |
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 kOneBillion = 1000000000L; |
Daniel Erat
2010/05/10 19:11:42
nit: int64_t :-)
|
+ int64 start64 = start.tv_sec * kOneBillion + start.tv_nsec; |
+ int64 stop64 = stop.tv_sec * kOneBillion + stop.tv_nsec; |
+ |
+ int64 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 @@ void UpdateAttempter::Update(bool force_full_update) { |
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 @@ void UpdateAttempter::Update(bool force_full_update) { |
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); |
+ } |
+} |
+ |
+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); |
} |
- g_main_loop_quit(loop_); |
} |
// Stop updating. An attempt will be made to record status to the disk |
@@ -118,19 +221,49 @@ void UpdateAttempter::ResumeUpdating() { |
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 |