blob: a1568a923d266cd64bae69e890351eec93616568 [file] [log] [blame]
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -07001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/update_attempter.h"
Andrew de los Reyes63b96d72010-05-10 13:08:54 -07006
7// From 'man clock_gettime': feature test macro: _POSIX_C_SOURCE >= 199309L
8#ifndef _POSIX_C_SOURCE
9#define _POSIX_C_SOURCE 199309L
10#endif // _POSIX_C_SOURCE
11#include <time.h>
12
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070013#include <tr1/memory>
14#include <string>
15#include <vector>
Darin Petkov9d65b7b2010-07-20 09:13:01 -070016
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070017#include <glib.h>
Darin Petkov1023a602010-08-30 13:47:51 -070018#include <metrics/metrics_library.h>
Darin Petkov9d65b7b2010-07-20 09:13:01 -070019
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070020#include "update_engine/dbus_service.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070021#include "update_engine/download_action.h"
22#include "update_engine/filesystem_copier_action.h"
23#include "update_engine/libcurl_http_fetcher.h"
Darin Petkov6a5b3222010-07-13 14:55:28 -070024#include "update_engine/omaha_request_action.h"
Darin Petkova4a8a8c2010-07-15 22:21:12 -070025#include "update_engine/omaha_request_params.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070026#include "update_engine/omaha_response_handler_action.h"
27#include "update_engine/postinstall_runner_action.h"
28#include "update_engine/set_bootable_flag_action.h"
Darin Petkov1023a602010-08-30 13:47:51 -070029#include "update_engine/update_check_scheduler.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070030
Darin Petkovaf183052010-08-23 12:07:13 -070031using base::TimeDelta;
32using base::TimeTicks;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070033using std::tr1::shared_ptr;
34using std::string;
35using std::vector;
36
37namespace chromeos_update_engine {
38
Andrew de los Reyes6b78e292010-05-10 15:54:39 -070039const char* kUpdateCompletedMarker = "/tmp/update_engine_autoupdate_completed";
40
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070041const char* UpdateStatusToString(UpdateStatus status) {
42 switch (status) {
43 case UPDATE_STATUS_IDLE:
44 return "UPDATE_STATUS_IDLE";
45 case UPDATE_STATUS_CHECKING_FOR_UPDATE:
46 return "UPDATE_STATUS_CHECKING_FOR_UPDATE";
47 case UPDATE_STATUS_UPDATE_AVAILABLE:
48 return "UPDATE_STATUS_UPDATE_AVAILABLE";
49 case UPDATE_STATUS_DOWNLOADING:
50 return "UPDATE_STATUS_DOWNLOADING";
51 case UPDATE_STATUS_VERIFYING:
52 return "UPDATE_STATUS_VERIFYING";
53 case UPDATE_STATUS_FINALIZING:
54 return "UPDATE_STATUS_FINALIZING";
55 case UPDATE_STATUS_UPDATED_NEED_REBOOT:
56 return "UPDATE_STATUS_UPDATED_NEED_REBOOT";
Darin Petkov09f96c32010-07-20 09:24:57 -070057 case UPDATE_STATUS_REPORTING_ERROR_EVENT:
58 return "UPDATE_STATUS_REPORTING_ERROR_EVENT";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070059 default:
60 return "unknown status";
61 }
62}
63
Darin Petkov777dbfa2010-07-20 15:03:37 -070064// Turns a generic kActionCodeError to a generic error code specific
65// to |action| (e.g., kActionCodeFilesystemCopierError). If |code| is
66// not kActionCodeError, or the action is not matched, returns |code|
67// unchanged.
68ActionExitCode GetErrorCodeForAction(AbstractAction* action,
69 ActionExitCode code) {
70 if (code != kActionCodeError)
71 return code;
72
73 const string type = action->Type();
74 if (type == OmahaRequestAction::StaticType())
75 return kActionCodeOmahaRequestError;
76 if (type == OmahaResponseHandlerAction::StaticType())
77 return kActionCodeOmahaResponseHandlerError;
78 if (type == FilesystemCopierAction::StaticType())
79 return kActionCodeFilesystemCopierError;
80 if (type == PostinstallRunnerAction::StaticType())
81 return kActionCodePostinstallRunnerError;
82 if (type == SetBootableFlagAction::StaticType())
83 return kActionCodeSetBootableFlagError;
84
85 return code;
86}
87
Darin Petkovc6c135c2010-08-11 13:36:18 -070088UpdateAttempter::UpdateAttempter(PrefsInterface* prefs,
89 MetricsLibraryInterface* metrics_lib)
Darin Petkovf42cc1c2010-09-01 09:03:02 -070090 : processor_(new ActionProcessor()),
91 dbus_service_(NULL),
Darin Petkovc6c135c2010-08-11 13:36:18 -070092 prefs_(prefs),
93 metrics_lib_(metrics_lib),
Darin Petkov1023a602010-08-30 13:47:51 -070094 update_check_scheduler_(NULL),
95 http_response_code_(0),
Darin Petkovc6c135c2010-08-11 13:36:18 -070096 priority_(utils::kProcessPriorityNormal),
97 manage_priority_source_(NULL),
Darin Petkov9d911fa2010-08-19 09:36:08 -070098 download_active_(false),
Darin Petkovc6c135c2010-08-11 13:36:18 -070099 status_(UPDATE_STATUS_IDLE),
100 download_progress_(0.0),
101 last_checked_time_(0),
102 new_version_("0.0.0.0"),
103 new_size_(0) {
Darin Petkovc6c135c2010-08-11 13:36:18 -0700104 if (utils::FileExists(kUpdateCompletedMarker))
105 status_ = UPDATE_STATUS_UPDATED_NEED_REBOOT;
106}
107
108UpdateAttempter::~UpdateAttempter() {
109 CleanupPriorityManagement();
110}
111
Darin Petkov5a7f5652010-07-22 21:40:09 -0700112void UpdateAttempter::Update(const std::string& app_version,
113 const std::string& omaha_url) {
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700114 if (status_ == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
115 LOG(INFO) << "Not updating b/c we already updated and we're waiting for "
116 << "reboot";
117 return;
118 }
119 if (status_ != UPDATE_STATUS_IDLE) {
120 // Update in progress. Do nothing
121 return;
122 }
Darin Petkov1023a602010-08-30 13:47:51 -0700123 http_response_code_ = 0;
Darin Petkov5a7f5652010-07-22 21:40:09 -0700124 if (!omaha_request_params_.Init(app_version, omaha_url)) {
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700125 LOG(ERROR) << "Unable to initialize Omaha request device params.";
126 return;
127 }
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700128 CHECK(!processor_->IsRunning());
129 processor_->set_delegate(this);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700130
131 // Actions:
Darin Petkov6a5b3222010-07-13 14:55:28 -0700132 shared_ptr<OmahaRequestAction> update_check_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700133 new OmahaRequestAction(prefs_,
134 omaha_request_params_,
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700135 NULL,
136 new LibcurlHttpFetcher));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700137 shared_ptr<OmahaResponseHandlerAction> response_handler_action(
138 new OmahaResponseHandlerAction);
139 shared_ptr<FilesystemCopierAction> filesystem_copier_action(
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700140 new FilesystemCopierAction(false));
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700141 shared_ptr<FilesystemCopierAction> kernel_filesystem_copier_action(
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700142 new FilesystemCopierAction(true));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700143 shared_ptr<OmahaRequestAction> download_started_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700144 new OmahaRequestAction(prefs_,
145 omaha_request_params_,
Darin Petkov8c2980e2010-07-16 15:16:49 -0700146 new OmahaEvent(
Darin Petkove17f86b2010-07-20 09:12:01 -0700147 OmahaEvent::kTypeUpdateDownloadStarted),
Darin Petkov8c2980e2010-07-16 15:16:49 -0700148 new LibcurlHttpFetcher));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700149 shared_ptr<DownloadAction> download_action(
150 new DownloadAction(new LibcurlHttpFetcher));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700151 shared_ptr<OmahaRequestAction> download_finished_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700152 new OmahaRequestAction(prefs_,
153 omaha_request_params_,
Darin Petkov8c2980e2010-07-16 15:16:49 -0700154 new OmahaEvent(
Darin Petkove17f86b2010-07-20 09:12:01 -0700155 OmahaEvent::kTypeUpdateDownloadFinished),
Darin Petkov8c2980e2010-07-16 15:16:49 -0700156 new LibcurlHttpFetcher));
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700157 shared_ptr<PostinstallRunnerAction> postinstall_runner_action_precommit(
158 new PostinstallRunnerAction(true));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700159 shared_ptr<SetBootableFlagAction> set_bootable_flag_action(
160 new SetBootableFlagAction);
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700161 shared_ptr<PostinstallRunnerAction> postinstall_runner_action_postcommit(
162 new PostinstallRunnerAction(false));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700163 shared_ptr<OmahaRequestAction> update_complete_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700164 new OmahaRequestAction(prefs_,
165 omaha_request_params_,
Darin Petkove17f86b2010-07-20 09:12:01 -0700166 new OmahaEvent(OmahaEvent::kTypeUpdateComplete),
Darin Petkov0dc8e9a2010-07-14 14:51:57 -0700167 new LibcurlHttpFetcher));
Darin Petkov6a5b3222010-07-13 14:55:28 -0700168
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700169 download_action->set_delegate(this);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700170 response_handler_action_ = response_handler_action;
171
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700172 actions_.push_back(shared_ptr<AbstractAction>(update_check_action));
173 actions_.push_back(shared_ptr<AbstractAction>(response_handler_action));
174 actions_.push_back(shared_ptr<AbstractAction>(filesystem_copier_action));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700175 actions_.push_back(shared_ptr<AbstractAction>(
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700176 kernel_filesystem_copier_action));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700177 actions_.push_back(shared_ptr<AbstractAction>(download_started_action));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700178 actions_.push_back(shared_ptr<AbstractAction>(download_action));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700179 actions_.push_back(shared_ptr<AbstractAction>(download_finished_action));
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700180 actions_.push_back(shared_ptr<AbstractAction>(
181 postinstall_runner_action_precommit));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700182 actions_.push_back(shared_ptr<AbstractAction>(set_bootable_flag_action));
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700183 actions_.push_back(shared_ptr<AbstractAction>(
184 postinstall_runner_action_postcommit));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700185 actions_.push_back(shared_ptr<AbstractAction>(update_complete_action));
Darin Petkov6a5b3222010-07-13 14:55:28 -0700186
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700187 // Enqueue the actions
188 for (vector<shared_ptr<AbstractAction> >::iterator it = actions_.begin();
189 it != actions_.end(); ++it) {
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700190 processor_->EnqueueAction(it->get());
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700191 }
192
193 // Bond them together. We have to use the leaf-types when calling
194 // BondActions().
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700195 BondActions(update_check_action.get(),
196 response_handler_action.get());
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700197 BondActions(response_handler_action.get(),
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700198 filesystem_copier_action.get());
199 BondActions(filesystem_copier_action.get(),
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700200 kernel_filesystem_copier_action.get());
201 BondActions(kernel_filesystem_copier_action.get(),
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700202 download_action.get());
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700203 BondActions(download_action.get(),
204 postinstall_runner_action_precommit.get());
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700205 BondActions(postinstall_runner_action_precommit.get(),
206 set_bootable_flag_action.get());
207 BondActions(set_bootable_flag_action.get(),
208 postinstall_runner_action_postcommit.get());
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700209
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700210 SetStatusAndNotify(UPDATE_STATUS_CHECKING_FOR_UPDATE);
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700211 processor_->StartProcessing();
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700212}
213
Darin Petkov5a7f5652010-07-22 21:40:09 -0700214void UpdateAttempter::CheckForUpdate(const std::string& app_version,
215 const std::string& omaha_url) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700216 if (status_ != UPDATE_STATUS_IDLE) {
217 LOG(INFO) << "Check for update requested, but status is "
218 << UpdateStatusToString(status_) << ", so not checking.";
219 return;
220 }
Darin Petkov5a7f5652010-07-22 21:40:09 -0700221 Update(app_version, omaha_url);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700222}
223
Darin Petkov296889c2010-07-23 16:20:54 -0700224bool UpdateAttempter::RebootIfNeeded() {
225 if (status_ != UPDATE_STATUS_UPDATED_NEED_REBOOT) {
226 LOG(INFO) << "Reboot requested, but status is "
227 << UpdateStatusToString(status_) << ", so not rebooting.";
228 return false;
229 }
230 TEST_AND_RETURN_FALSE(utils::Reboot());
231 return true;
232}
233
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700234// Delegate methods:
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700235void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
Darin Petkovc1a8b422010-07-19 11:34:49 -0700236 ActionExitCode code) {
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700237 CHECK(response_handler_action_);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700238 LOG(INFO) << "Processing Done.";
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700239 actions_.clear();
Darin Petkov09f96c32010-07-20 09:24:57 -0700240
Darin Petkovc6c135c2010-08-11 13:36:18 -0700241 // Reset process priority back to normal.
242 CleanupPriorityManagement();
243
Darin Petkov09f96c32010-07-20 09:24:57 -0700244 if (status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
245 LOG(INFO) << "Error event sent.";
246 SetStatusAndNotify(UPDATE_STATUS_IDLE);
247 return;
248 }
249
Darin Petkovc1a8b422010-07-19 11:34:49 -0700250 if (code == kActionCodeSuccess) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700251 SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700252 utils::WriteFile(kUpdateCompletedMarker, "", 0);
Darin Petkov9d65b7b2010-07-20 09:13:01 -0700253
254 // Report the time it took to update the system.
255 int64_t update_time = time(NULL) - last_checked_time_;
256 metrics_lib_->SendToUMA("Installer.UpdateTime",
257 static_cast<int>(update_time), // sample
258 1, // min = 1 second
259 20 * 60, // max = 20 minutes
260 50); // buckets
Darin Petkov09f96c32010-07-20 09:24:57 -0700261 return;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700262 }
Darin Petkov09f96c32010-07-20 09:24:57 -0700263
Darin Petkov1023a602010-08-30 13:47:51 -0700264 if (ScheduleErrorEventAction()) {
Darin Petkov09f96c32010-07-20 09:24:57 -0700265 return;
Darin Petkov1023a602010-08-30 13:47:51 -0700266 }
267 LOG(INFO) << "No update.";
Darin Petkov09f96c32010-07-20 09:24:57 -0700268 SetStatusAndNotify(UPDATE_STATUS_IDLE);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700269}
270
271void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) {
Darin Petkovc6c135c2010-08-11 13:36:18 -0700272 // Reset process priority back to normal.
273 CleanupPriorityManagement();
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700274 download_progress_ = 0.0;
275 SetStatusAndNotify(UPDATE_STATUS_IDLE);
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700276 actions_.clear();
Darin Petkov09f96c32010-07-20 09:24:57 -0700277 error_event_.reset(NULL);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700278}
279
280// Called whenever an action has finished processing, either successfully
281// or otherwise.
282void UpdateAttempter::ActionCompleted(ActionProcessor* processor,
283 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -0700284 ActionExitCode code) {
Darin Petkov1023a602010-08-30 13:47:51 -0700285 // Reset download progress regardless of whether or not the download
286 // action succeeded. Also, get the response code from HTTP request
287 // actions (update download as well as the initial update check
288 // actions).
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700289 const string type = action->Type();
Darin Petkov1023a602010-08-30 13:47:51 -0700290 if (type == DownloadAction::StaticType()) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700291 download_progress_ = 0.0;
Darin Petkov1023a602010-08-30 13:47:51 -0700292 DownloadAction* download_action = dynamic_cast<DownloadAction*>(action);
293 http_response_code_ = download_action->GetHTTPResponseCode();
294 } else if (type == OmahaRequestAction::StaticType()) {
295 OmahaRequestAction* omaha_request_action =
296 dynamic_cast<OmahaRequestAction*>(action);
297 // If the request is not an event, then it's the update-check.
298 if (!omaha_request_action->IsEvent()) {
299 http_response_code_ = omaha_request_action->GetHTTPResponseCode();
Darin Petkov85ced132010-09-01 10:20:56 -0700300 // Forward the server-dictated poll interval to the update check
301 // scheduler, if any.
302 if (update_check_scheduler_) {
303 update_check_scheduler_->set_poll_interval(
304 omaha_request_action->GetOutputObject().poll_interval);
305 }
Darin Petkov1023a602010-08-30 13:47:51 -0700306 }
307 }
Darin Petkov09f96c32010-07-20 09:24:57 -0700308 if (code != kActionCodeSuccess) {
Darin Petkov777dbfa2010-07-20 15:03:37 -0700309 // On failure, schedule an error event to be sent to Omaha.
310 CreatePendingErrorEvent(action, code);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700311 return;
Darin Petkov09f96c32010-07-20 09:24:57 -0700312 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700313 // Find out which action completed.
314 if (type == OmahaResponseHandlerAction::StaticType()) {
Darin Petkov9d911fa2010-08-19 09:36:08 -0700315 // Note that the status will be updated to DOWNLOADING when some
316 // bytes get actually downloaded from the server and the
317 // BytesReceived callback is invoked. This avoids notifying the
318 // user that a download has started in cases when the server and
319 // the client are unable to initiate the download.
Darin Petkov6a5b3222010-07-13 14:55:28 -0700320 OmahaResponseHandlerAction* omaha_response_handler_action =
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700321 dynamic_cast<OmahaResponseHandlerAction*>(action);
322 CHECK(omaha_response_handler_action);
323 const InstallPlan& plan = omaha_response_handler_action->install_plan();
324 last_checked_time_ = time(NULL);
325 // TODO(adlr): put version in InstallPlan
326 new_version_ = "0.0.0.0";
327 new_size_ = plan.size;
Darin Petkovc6c135c2010-08-11 13:36:18 -0700328 SetupPriorityManagement();
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700329 } else if (type == DownloadAction::StaticType()) {
330 SetStatusAndNotify(UPDATE_STATUS_FINALIZING);
331 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700332}
333
334// Stop updating. An attempt will be made to record status to the disk
335// so that updates can be resumed later.
336void UpdateAttempter::Terminate() {
337 // TODO(adlr): implement this method.
338 NOTIMPLEMENTED();
339}
340
341// Try to resume from a previously Terminate()d update.
342void UpdateAttempter::ResumeUpdating() {
343 // TODO(adlr): implement this method.
344 NOTIMPLEMENTED();
345}
346
Darin Petkov9d911fa2010-08-19 09:36:08 -0700347void UpdateAttempter::SetDownloadStatus(bool active) {
348 download_active_ = active;
349 LOG(INFO) << "Download status: " << (active ? "active" : "inactive");
350}
351
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700352void UpdateAttempter::BytesReceived(uint64_t bytes_received, uint64_t total) {
Darin Petkov9d911fa2010-08-19 09:36:08 -0700353 if (!download_active_) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700354 LOG(ERROR) << "BytesReceived called while not downloading.";
355 return;
356 }
Darin Petkovaf183052010-08-23 12:07:13 -0700357 double progress = static_cast<double>(bytes_received) /
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700358 static_cast<double>(total);
Darin Petkovaf183052010-08-23 12:07:13 -0700359 // Self throttle based on progress. Also send notifications if
360 // progress is too slow.
361 const double kDeltaPercent = 0.01; // 1%
362 if (status_ != UPDATE_STATUS_DOWNLOADING ||
363 bytes_received == total ||
364 progress - download_progress_ >= kDeltaPercent ||
365 TimeTicks::Now() - last_notify_time_ >= TimeDelta::FromSeconds(10)) {
366 download_progress_ = progress;
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700367 SetStatusAndNotify(UPDATE_STATUS_DOWNLOADING);
368 }
369}
370
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700371bool UpdateAttempter::GetStatus(int64_t* last_checked_time,
372 double* progress,
373 std::string* current_operation,
374 std::string* new_version,
375 int64_t* new_size) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700376 *last_checked_time = last_checked_time_;
377 *progress = download_progress_;
378 *current_operation = UpdateStatusToString(status_);
379 *new_version = new_version_;
380 *new_size = new_size_;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700381 return true;
382}
383
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700384void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) {
385 status_ = status;
Darin Petkov1023a602010-08-30 13:47:51 -0700386 if (update_check_scheduler_) {
387 update_check_scheduler_->SetUpdateStatus(status_);
388 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700389 if (!dbus_service_)
390 return;
Darin Petkovaf183052010-08-23 12:07:13 -0700391 last_notify_time_ = TimeTicks::Now();
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700392 update_engine_service_emit_status_update(
393 dbus_service_,
394 last_checked_time_,
395 download_progress_,
396 UpdateStatusToString(status_),
397 new_version_.c_str(),
398 new_size_);
399}
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700400
Darin Petkov777dbfa2010-07-20 15:03:37 -0700401void UpdateAttempter::CreatePendingErrorEvent(AbstractAction* action,
402 ActionExitCode code) {
Darin Petkov09f96c32010-07-20 09:24:57 -0700403 if (error_event_.get()) {
404 // This shouldn't really happen.
405 LOG(WARNING) << "There's already an existing pending error event.";
406 return;
407 }
Darin Petkov777dbfa2010-07-20 15:03:37 -0700408
409 // For now assume that Omaha response action failure means that
410 // there's no update so don't send an event. Also, double check that
411 // the failure has not occurred while sending an error event -- in
412 // which case don't schedule another. This shouldn't really happen
413 // but just in case...
414 if (action->Type() == OmahaResponseHandlerAction::StaticType() ||
415 status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
416 return;
417 }
418
419 code = GetErrorCodeForAction(action, code);
Darin Petkov09f96c32010-07-20 09:24:57 -0700420 error_event_.reset(new OmahaEvent(OmahaEvent::kTypeUpdateComplete,
421 OmahaEvent::kResultError,
422 code));
423}
424
425bool UpdateAttempter::ScheduleErrorEventAction() {
426 if (error_event_.get() == NULL)
427 return false;
428
Darin Petkov1023a602010-08-30 13:47:51 -0700429 LOG(INFO) << "Update failed -- reporting the error event.";
Darin Petkov09f96c32010-07-20 09:24:57 -0700430 shared_ptr<OmahaRequestAction> error_event_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700431 new OmahaRequestAction(prefs_,
432 omaha_request_params_,
Darin Petkov09f96c32010-07-20 09:24:57 -0700433 error_event_.release(), // Pass ownership.
434 new LibcurlHttpFetcher));
435 actions_.push_back(shared_ptr<AbstractAction>(error_event_action));
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700436 processor_->EnqueueAction(error_event_action.get());
Darin Petkov09f96c32010-07-20 09:24:57 -0700437 SetStatusAndNotify(UPDATE_STATUS_REPORTING_ERROR_EVENT);
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700438 processor_->StartProcessing();
Darin Petkov09f96c32010-07-20 09:24:57 -0700439 return true;
440}
441
Darin Petkovc6c135c2010-08-11 13:36:18 -0700442void UpdateAttempter::SetPriority(utils::ProcessPriority priority) {
443 if (priority_ == priority) {
444 return;
445 }
446 if (utils::SetProcessPriority(priority)) {
447 priority_ = priority;
448 LOG(INFO) << "Process priority = " << priority_;
449 }
450}
451
452void UpdateAttempter::SetupPriorityManagement() {
453 if (manage_priority_source_) {
454 LOG(ERROR) << "Process priority timeout source hasn't been destroyed.";
455 CleanupPriorityManagement();
456 }
457 const int kPriorityTimeout = 10 * 60; // 10 minutes
458 manage_priority_source_ = g_timeout_source_new_seconds(kPriorityTimeout);
459 g_source_set_callback(manage_priority_source_,
460 StaticManagePriorityCallback,
461 this,
462 NULL);
463 g_source_attach(manage_priority_source_, NULL);
464 SetPriority(utils::kProcessPriorityLow);
465}
466
467void UpdateAttempter::CleanupPriorityManagement() {
468 if (manage_priority_source_) {
469 g_source_destroy(manage_priority_source_);
470 manage_priority_source_ = NULL;
471 }
472 SetPriority(utils::kProcessPriorityNormal);
473}
474
475gboolean UpdateAttempter::StaticManagePriorityCallback(gpointer data) {
476 return reinterpret_cast<UpdateAttempter*>(data)->ManagePriorityCallback();
477}
478
479bool UpdateAttempter::ManagePriorityCallback() {
480 // If the current process priority is below normal, set it to normal
481 // and let GLib invoke this callback again.
482 if (utils::ComparePriorities(priority_, utils::kProcessPriorityNormal) < 0) {
483 SetPriority(utils::kProcessPriorityNormal);
484 return true;
485 }
486 // Set the priority to high and let GLib destroy the timeout source.
487 SetPriority(utils::kProcessPriorityHigh);
488 manage_priority_source_ = NULL;
489 return false;
490}
491
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700492} // namespace chromeos_update_engine