blob: 210e78ac4ce3e6a49cb58a1df5c1bd8abde9c8c3 [file] [log] [blame]
Darin Petkov58dd1342011-05-06 12:05:13 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -07002// 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 <string>
Darin Petkov9b230572010-10-08 10:20:09 -070014#include <tr1/memory>
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070015#include <vector>
Darin Petkov9d65b7b2010-07-20 09:13:01 -070016
Gilad Arnold28e2f392012-02-09 14:36:46 -080017#include <base/eintr_wrapper.h>
Andrew de los Reyes45168102010-11-22 11:13:50 -080018#include <base/rand_util.h>
Gilad Arnold28e2f392012-02-09 14:36:46 -080019#include <base/string_util.h>
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070020#include <glib.h>
Darin Petkov1023a602010-08-30 13:47:51 -070021#include <metrics/metrics_library.h>
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +020022#include <policy/libpolicy.h>
23#include <policy/device_policy.h>
Darin Petkov9d65b7b2010-07-20 09:13:01 -070024
Bruno Rocha7f9aea22011-09-12 14:31:24 -070025#include "update_engine/certificate_checker.h"
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070026#include "update_engine/dbus_service.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070027#include "update_engine/download_action.h"
28#include "update_engine/filesystem_copier_action.h"
29#include "update_engine/libcurl_http_fetcher.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080030#include "update_engine/multi_range_http_fetcher.h"
Darin Petkov6a5b3222010-07-13 14:55:28 -070031#include "update_engine/omaha_request_action.h"
Darin Petkova4a8a8c2010-07-15 22:21:12 -070032#include "update_engine/omaha_request_params.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070033#include "update_engine/omaha_response_handler_action.h"
34#include "update_engine/postinstall_runner_action.h"
Darin Petkov36275772010-10-01 11:40:57 -070035#include "update_engine/prefs_interface.h"
Andrew de los Reyes6dbf30a2011-04-19 10:58:16 -070036#include "update_engine/subprocess.h"
Darin Petkov1023a602010-08-30 13:47:51 -070037#include "update_engine/update_check_scheduler.h"
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070038
Darin Petkovaf183052010-08-23 12:07:13 -070039using base::TimeDelta;
40using base::TimeTicks;
Andrew de los Reyes21816e12011-04-07 14:18:56 -070041using google::protobuf::NewPermanentCallback;
Darin Petkov9b230572010-10-08 10:20:09 -070042using std::make_pair;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -070043using std::tr1::shared_ptr;
44using std::string;
45using std::vector;
46
47namespace chromeos_update_engine {
48
Darin Petkov36275772010-10-01 11:40:57 -070049const int UpdateAttempter::kMaxDeltaUpdateFailures = 3;
50
Gilad Arnold28e2f392012-02-09 14:36:46 -080051// TODO(garnold) this is currently an arbitrary address and will change based on
52// discussion about the actual test lab configuration.
53const char* const UpdateAttempter::kTestUpdateUrl("https://10.0.0.1/update");
54
Darin Petkovcd1666f2010-09-23 09:53:44 -070055const char* kUpdateCompletedMarker =
56 "/var/run/update_engine_autoupdate_completed";
Andrew de los Reyes6b78e292010-05-10 15:54:39 -070057
Andrew de los Reyes45168102010-11-22 11:13:50 -080058namespace {
59const int kMaxConsecutiveObeyProxyRequests = 20;
Gilad Arnold28e2f392012-02-09 14:36:46 -080060
61// Names of udev properties that are linked to the GPIO chip device and identify
62// the two dutflag GPIOs on different boards.
63const char kIdGpioDutflaga[] = "ID_GPIO_DUTFLAGA";
64const char kIdGpioDutflagb[] = "ID_GPIO_DUTFLAGB";
65
66// Scoped closer for udev and udev_enumerate objects.
67// TODO(garnold) chromium-os:26934: it would be nice to generalize the different
68// ScopedFooCloser implementations in update engine using a single template.
69class ScopedUdevCloser {
70 public:
71 explicit ScopedUdevCloser(udev **udev_p) : udev_p_(udev_p) {}
72 ~ScopedUdevCloser() {
73 if (udev_p_ && *udev_p_) {
74 udev_unref(*udev_p_);
75 *udev_p_ = NULL;
76 }
77 }
78 private:
79 struct udev **udev_p_;
80
81 DISALLOW_COPY_AND_ASSIGN(ScopedUdevCloser);
82};
83
84class ScopedUdevEnumerateCloser {
85 public:
86 explicit ScopedUdevEnumerateCloser(udev_enumerate **udev_enum_p) :
87 udev_enum_p_(udev_enum_p) {}
88 ~ScopedUdevEnumerateCloser() {
89 if (udev_enum_p_ && *udev_enum_p_) {
90 udev_enumerate_unref(*udev_enum_p_);
91 *udev_enum_p_ = NULL;
92 }
93 }
94 private:
95 struct udev_enumerate **udev_enum_p_;
96
97 DISALLOW_COPY_AND_ASSIGN(ScopedUdevEnumerateCloser);
98};
Andrew de los Reyes45168102010-11-22 11:13:50 -080099} // namespace {}
100
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700101const char* UpdateStatusToString(UpdateStatus status) {
102 switch (status) {
103 case UPDATE_STATUS_IDLE:
104 return "UPDATE_STATUS_IDLE";
105 case UPDATE_STATUS_CHECKING_FOR_UPDATE:
106 return "UPDATE_STATUS_CHECKING_FOR_UPDATE";
107 case UPDATE_STATUS_UPDATE_AVAILABLE:
108 return "UPDATE_STATUS_UPDATE_AVAILABLE";
109 case UPDATE_STATUS_DOWNLOADING:
110 return "UPDATE_STATUS_DOWNLOADING";
111 case UPDATE_STATUS_VERIFYING:
112 return "UPDATE_STATUS_VERIFYING";
113 case UPDATE_STATUS_FINALIZING:
114 return "UPDATE_STATUS_FINALIZING";
115 case UPDATE_STATUS_UPDATED_NEED_REBOOT:
116 return "UPDATE_STATUS_UPDATED_NEED_REBOOT";
Darin Petkov09f96c32010-07-20 09:24:57 -0700117 case UPDATE_STATUS_REPORTING_ERROR_EVENT:
118 return "UPDATE_STATUS_REPORTING_ERROR_EVENT";
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700119 default:
120 return "unknown status";
121 }
122}
123
Darin Petkov777dbfa2010-07-20 15:03:37 -0700124// Turns a generic kActionCodeError to a generic error code specific
125// to |action| (e.g., kActionCodeFilesystemCopierError). If |code| is
126// not kActionCodeError, or the action is not matched, returns |code|
127// unchanged.
128ActionExitCode GetErrorCodeForAction(AbstractAction* action,
129 ActionExitCode code) {
130 if (code != kActionCodeError)
131 return code;
132
133 const string type = action->Type();
134 if (type == OmahaRequestAction::StaticType())
135 return kActionCodeOmahaRequestError;
136 if (type == OmahaResponseHandlerAction::StaticType())
137 return kActionCodeOmahaResponseHandlerError;
138 if (type == FilesystemCopierAction::StaticType())
139 return kActionCodeFilesystemCopierError;
140 if (type == PostinstallRunnerAction::StaticType())
141 return kActionCodePostinstallRunnerError;
Darin Petkov777dbfa2010-07-20 15:03:37 -0700142
143 return code;
144}
145
Darin Petkovc6c135c2010-08-11 13:36:18 -0700146UpdateAttempter::UpdateAttempter(PrefsInterface* prefs,
Andrew de los Reyes45168102010-11-22 11:13:50 -0800147 MetricsLibraryInterface* metrics_lib,
148 DbusGlibInterface* dbus_iface)
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700149 : processor_(new ActionProcessor()),
150 dbus_service_(NULL),
Darin Petkovc6c135c2010-08-11 13:36:18 -0700151 prefs_(prefs),
152 metrics_lib_(metrics_lib),
Darin Petkov1023a602010-08-30 13:47:51 -0700153 update_check_scheduler_(NULL),
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700154 fake_update_success_(false),
Darin Petkov1023a602010-08-30 13:47:51 -0700155 http_response_code_(0),
Darin Petkovc6c135c2010-08-11 13:36:18 -0700156 priority_(utils::kProcessPriorityNormal),
157 manage_priority_source_(NULL),
Darin Petkov9d911fa2010-08-19 09:36:08 -0700158 download_active_(false),
Darin Petkovc6c135c2010-08-11 13:36:18 -0700159 status_(UPDATE_STATUS_IDLE),
160 download_progress_(0.0),
161 last_checked_time_(0),
162 new_version_("0.0.0.0"),
Darin Petkov36275772010-10-01 11:40:57 -0700163 new_size_(0),
Andrew de los Reyes45168102010-11-22 11:13:50 -0800164 proxy_manual_checks_(0),
165 obeying_proxies_(true),
Andrew de los Reyes6dbf30a2011-04-19 10:58:16 -0700166 chrome_proxy_resolver_(dbus_iface),
Darin Petkov58dd1342011-05-06 12:05:13 -0700167 updated_boot_flags_(false),
168 update_boot_flags_running_(false),
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +0200169 start_action_processor_(false),
170 policy_provider_(NULL) {
Darin Petkovc6c135c2010-08-11 13:36:18 -0700171 if (utils::FileExists(kUpdateCompletedMarker))
172 status_ = UPDATE_STATUS_UPDATED_NEED_REBOOT;
173}
174
175UpdateAttempter::~UpdateAttempter() {
176 CleanupPriorityManagement();
177}
178
Gilad Arnold28e2f392012-02-09 14:36:46 -0800179void UpdateAttempter::Update(const string& app_version,
180 const string& omaha_url,
Andrew de los Reyesfb2f4612011-06-09 18:21:49 -0700181 bool obey_proxies,
182 bool interactive) {
Andrew de los Reyes000d8952011-03-02 15:21:14 -0800183 chrome_proxy_resolver_.Init();
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700184 fake_update_success_ = false;
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700185 if (status_ == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
Thieu Le116fda32011-04-19 11:01:54 -0700186 // Although we have applied an update, we still want to ping Omaha
187 // to ensure the number of active statistics is accurate.
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700188 LOG(INFO) << "Not updating b/c we already updated and we're waiting for "
Thieu Le116fda32011-04-19 11:01:54 -0700189 << "reboot, we'll ping Omaha instead";
190 PingOmaha();
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700191 return;
192 }
193 if (status_ != UPDATE_STATUS_IDLE) {
194 // Update in progress. Do nothing
195 return;
196 }
Darin Petkov1023a602010-08-30 13:47:51 -0700197 http_response_code_ = 0;
Patrick Dubroy7fbbe8a2011-08-01 17:28:22 +0200198
199 // Lazy initialize the policy provider, or reload the latest policy data.
200 if (!policy_provider_.get()) {
201 policy_provider_.reset(new policy::PolicyProvider());
202 } else {
203 policy_provider_->Reload();
204 }
205
206 // If the release_track is specified by policy, that takes precedence.
207 string release_track;
208 if (policy_provider_->device_policy_is_loaded())
209 policy_provider_->GetDevicePolicy().GetReleaseChannel(&release_track);
210
Gilad Arnold28e2f392012-02-09 14:36:46 -0800211 // Force alternate default address for automated test case, based on GPIO
212 // signal. We replicate the URL string so as not to overwrite the argument.
213 string omaha_url_to_use = omaha_url;
214 if (omaha_url_to_use.empty()) {
215 bool dutflaga_gpio_status;
216 if (GetDutflagaGpio(&dutflaga_gpio_status)) {
217 LOG(INFO) << "dutflaga GPIO status: "
218 << (dutflaga_gpio_status ? "on" : "off");
219
220 // The dut_flaga GPIO is actually signaled when in the 'off' position.
221 if (!dutflaga_gpio_status) {
222 LOG(INFO) << "using alternative server address: " << kTestUpdateUrl;
223 omaha_url_to_use = kTestUpdateUrl;
224 }
225 } else {
226 LOG(ERROR) << "reading dutflaga GPIO status failed";
227 }
228 }
229
230 if (!omaha_request_params_.Init(app_version, omaha_url_to_use,
231 release_track)) {
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700232 LOG(ERROR) << "Unable to initialize Omaha request device params.";
233 return;
234 }
Darin Petkov3aefa862010-12-07 14:45:00 -0800235
Andrew de los Reyes45168102010-11-22 11:13:50 -0800236 obeying_proxies_ = true;
237 if (obey_proxies || proxy_manual_checks_ == 0) {
238 LOG(INFO) << "forced to obey proxies";
239 // If forced to obey proxies, every 20th request will not use proxies
240 proxy_manual_checks_++;
241 LOG(INFO) << "proxy manual checks: " << proxy_manual_checks_;
242 if (proxy_manual_checks_ >= kMaxConsecutiveObeyProxyRequests) {
243 proxy_manual_checks_ = 0;
244 obeying_proxies_ = false;
245 }
246 } else if (base::RandInt(0, 4) == 0) {
247 obeying_proxies_ = false;
248 }
249 LOG_IF(INFO, !obeying_proxies_) << "To help ensure updates work, this update "
250 "check we are ignoring the proxy settings and using "
251 "direct connections.";
252
Darin Petkov36275772010-10-01 11:40:57 -0700253 DisableDeltaUpdateIfNeeded();
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700254 CHECK(!processor_->IsRunning());
255 processor_->set_delegate(this);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700256
257 // Actions:
Darin Petkova0929552010-11-29 14:19:06 -0800258 LibcurlHttpFetcher* update_check_fetcher =
259 new LibcurlHttpFetcher(GetProxyResolver());
Andrew de los Reyesfb2f4612011-06-09 18:21:49 -0700260 // Try harder to connect to the network, esp when not interactive.
261 // See comment in libcurl_http_fetcher.cc.
262 update_check_fetcher->set_no_network_max_retries(interactive ? 1 : 3);
Bruno Rocha7f9aea22011-09-12 14:31:24 -0700263 update_check_fetcher->set_check_certificate(CertificateChecker::kUpdate);
Darin Petkov6a5b3222010-07-13 14:55:28 -0700264 shared_ptr<OmahaRequestAction> update_check_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700265 new OmahaRequestAction(prefs_,
266 omaha_request_params_,
Darin Petkova4a8a8c2010-07-15 22:21:12 -0700267 NULL,
Thieu Le116fda32011-04-19 11:01:54 -0700268 update_check_fetcher, // passes ownership
269 false));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700270 shared_ptr<OmahaResponseHandlerAction> response_handler_action(
Darin Petkov73058b42010-10-06 16:32:19 -0700271 new OmahaResponseHandlerAction(prefs_));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700272 shared_ptr<FilesystemCopierAction> filesystem_copier_action(
Darin Petkov3aefa862010-12-07 14:45:00 -0800273 new FilesystemCopierAction(false, false));
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700274 shared_ptr<FilesystemCopierAction> kernel_filesystem_copier_action(
Darin Petkov3aefa862010-12-07 14:45:00 -0800275 new FilesystemCopierAction(true, false));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700276 shared_ptr<OmahaRequestAction> download_started_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700277 new OmahaRequestAction(prefs_,
278 omaha_request_params_,
Darin Petkov8c2980e2010-07-16 15:16:49 -0700279 new OmahaEvent(
Darin Petkove17f86b2010-07-20 09:12:01 -0700280 OmahaEvent::kTypeUpdateDownloadStarted),
Thieu Le116fda32011-04-19 11:01:54 -0700281 new LibcurlHttpFetcher(GetProxyResolver()),
282 false));
Bruno Rocha7f9aea22011-09-12 14:31:24 -0700283 LibcurlHttpFetcher* download_fetcher =
284 new LibcurlHttpFetcher(GetProxyResolver());
285 download_fetcher->set_check_certificate(CertificateChecker::kDownload);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700286 shared_ptr<DownloadAction> download_action(
Bruno Rocha7f9aea22011-09-12 14:31:24 -0700287 new DownloadAction(prefs_,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800288 new MultiRangeHttpFetcher(
Bruno Rocha7f9aea22011-09-12 14:31:24 -0700289 download_fetcher))); // passes ownership
Darin Petkov8c2980e2010-07-16 15:16:49 -0700290 shared_ptr<OmahaRequestAction> download_finished_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700291 new OmahaRequestAction(prefs_,
292 omaha_request_params_,
Darin Petkov8c2980e2010-07-16 15:16:49 -0700293 new OmahaEvent(
Darin Petkove17f86b2010-07-20 09:12:01 -0700294 OmahaEvent::kTypeUpdateDownloadFinished),
Thieu Le116fda32011-04-19 11:01:54 -0700295 new LibcurlHttpFetcher(GetProxyResolver()),
296 false));
Darin Petkov3aefa862010-12-07 14:45:00 -0800297 shared_ptr<FilesystemCopierAction> filesystem_verifier_action(
298 new FilesystemCopierAction(false, true));
299 shared_ptr<FilesystemCopierAction> kernel_filesystem_verifier_action(
300 new FilesystemCopierAction(true, true));
Darin Petkov6d5dbf62010-11-08 16:09:55 -0800301 shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
302 new PostinstallRunnerAction);
Darin Petkov8c2980e2010-07-16 15:16:49 -0700303 shared_ptr<OmahaRequestAction> update_complete_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700304 new OmahaRequestAction(prefs_,
305 omaha_request_params_,
Darin Petkove17f86b2010-07-20 09:12:01 -0700306 new OmahaEvent(OmahaEvent::kTypeUpdateComplete),
Thieu Le116fda32011-04-19 11:01:54 -0700307 new LibcurlHttpFetcher(GetProxyResolver()),
308 false));
Darin Petkov6a5b3222010-07-13 14:55:28 -0700309
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700310 download_action->set_delegate(this);
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700311 response_handler_action_ = response_handler_action;
Darin Petkov9b230572010-10-08 10:20:09 -0700312 download_action_ = download_action;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700313
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700314 actions_.push_back(shared_ptr<AbstractAction>(update_check_action));
315 actions_.push_back(shared_ptr<AbstractAction>(response_handler_action));
316 actions_.push_back(shared_ptr<AbstractAction>(filesystem_copier_action));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700317 actions_.push_back(shared_ptr<AbstractAction>(
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700318 kernel_filesystem_copier_action));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700319 actions_.push_back(shared_ptr<AbstractAction>(download_started_action));
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700320 actions_.push_back(shared_ptr<AbstractAction>(download_action));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700321 actions_.push_back(shared_ptr<AbstractAction>(download_finished_action));
Darin Petkov3aefa862010-12-07 14:45:00 -0800322 actions_.push_back(shared_ptr<AbstractAction>(filesystem_verifier_action));
323 actions_.push_back(shared_ptr<AbstractAction>(
324 kernel_filesystem_verifier_action));
Darin Petkov6d5dbf62010-11-08 16:09:55 -0800325 actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
Darin Petkov8c2980e2010-07-16 15:16:49 -0700326 actions_.push_back(shared_ptr<AbstractAction>(update_complete_action));
Darin Petkov6a5b3222010-07-13 14:55:28 -0700327
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700328 // Enqueue the actions
329 for (vector<shared_ptr<AbstractAction> >::iterator it = actions_.begin();
330 it != actions_.end(); ++it) {
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700331 processor_->EnqueueAction(it->get());
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700332 }
333
334 // Bond them together. We have to use the leaf-types when calling
335 // BondActions().
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700336 BondActions(update_check_action.get(),
337 response_handler_action.get());
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700338 BondActions(response_handler_action.get(),
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700339 filesystem_copier_action.get());
340 BondActions(filesystem_copier_action.get(),
Andrew de los Reyesf9714432010-05-04 10:21:23 -0700341 kernel_filesystem_copier_action.get());
342 BondActions(kernel_filesystem_copier_action.get(),
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700343 download_action.get());
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700344 BondActions(download_action.get(),
Darin Petkov3aefa862010-12-07 14:45:00 -0800345 filesystem_verifier_action.get());
346 BondActions(filesystem_verifier_action.get(),
347 kernel_filesystem_verifier_action.get());
348 BondActions(kernel_filesystem_verifier_action.get(),
Darin Petkov6d5dbf62010-11-08 16:09:55 -0800349 postinstall_runner_action.get());
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700350
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700351 SetStatusAndNotify(UPDATE_STATUS_CHECKING_FOR_UPDATE);
Darin Petkove6ef2f82011-03-07 17:31:11 -0800352
Darin Petkov58dd1342011-05-06 12:05:13 -0700353 // Just in case we didn't update boot flags yet, make sure they're updated
354 // before any update processing starts.
355 start_action_processor_ = true;
356 UpdateBootFlags();
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700357}
358
Gilad Arnold28e2f392012-02-09 14:36:46 -0800359void UpdateAttempter::CheckForUpdate(const string& app_version,
360 const string& omaha_url) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700361 if (status_ != UPDATE_STATUS_IDLE) {
362 LOG(INFO) << "Check for update requested, but status is "
363 << UpdateStatusToString(status_) << ", so not checking.";
364 return;
365 }
Andrew de los Reyesfb2f4612011-06-09 18:21:49 -0700366 Update(app_version, omaha_url, true, true);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700367}
368
Darin Petkov296889c2010-07-23 16:20:54 -0700369bool UpdateAttempter::RebootIfNeeded() {
370 if (status_ != UPDATE_STATUS_UPDATED_NEED_REBOOT) {
371 LOG(INFO) << "Reboot requested, but status is "
372 << UpdateStatusToString(status_) << ", so not rebooting.";
373 return false;
374 }
375 TEST_AND_RETURN_FALSE(utils::Reboot());
376 return true;
377}
378
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700379// Delegate methods:
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700380void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
Darin Petkovc1a8b422010-07-19 11:34:49 -0700381 ActionExitCode code) {
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700382 CHECK(response_handler_action_);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700383 LOG(INFO) << "Processing Done.";
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700384 actions_.clear();
Darin Petkov09f96c32010-07-20 09:24:57 -0700385
Darin Petkovc6c135c2010-08-11 13:36:18 -0700386 // Reset process priority back to normal.
387 CleanupPriorityManagement();
388
Darin Petkov09f96c32010-07-20 09:24:57 -0700389 if (status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
390 LOG(INFO) << "Error event sent.";
391 SetStatusAndNotify(UPDATE_STATUS_IDLE);
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700392 if (!fake_update_success_) {
393 return;
394 }
395 LOG(INFO) << "Booted from FW B and tried to install new firmware, "
396 "so requesting reboot from user.";
Darin Petkov09f96c32010-07-20 09:24:57 -0700397 }
398
Darin Petkovc1a8b422010-07-19 11:34:49 -0700399 if (code == kActionCodeSuccess) {
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700400 utils::WriteFile(kUpdateCompletedMarker, "", 0);
Darin Petkov36275772010-10-01 11:40:57 -0700401 prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
Darin Petkov95508da2011-01-05 12:42:29 -0800402 prefs_->SetString(kPrefsPreviousVersion, omaha_request_params_.app_version);
Darin Petkov9b230572010-10-08 10:20:09 -0700403 DeltaPerformer::ResetUpdateProgress(prefs_, false);
404 SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
Darin Petkov9d65b7b2010-07-20 09:13:01 -0700405
406 // Report the time it took to update the system.
407 int64_t update_time = time(NULL) - last_checked_time_;
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700408 if (!fake_update_success_)
409 metrics_lib_->SendToUMA("Installer.UpdateTime",
410 static_cast<int>(update_time), // sample
411 1, // min = 1 second
412 20 * 60, // max = 20 minutes
413 50); // buckets
Darin Petkov09f96c32010-07-20 09:24:57 -0700414 return;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700415 }
Darin Petkov09f96c32010-07-20 09:24:57 -0700416
Darin Petkov1023a602010-08-30 13:47:51 -0700417 if (ScheduleErrorEventAction()) {
Darin Petkov09f96c32010-07-20 09:24:57 -0700418 return;
Darin Petkov1023a602010-08-30 13:47:51 -0700419 }
420 LOG(INFO) << "No update.";
Darin Petkov09f96c32010-07-20 09:24:57 -0700421 SetStatusAndNotify(UPDATE_STATUS_IDLE);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700422}
423
424void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) {
Darin Petkovc6c135c2010-08-11 13:36:18 -0700425 // Reset process priority back to normal.
426 CleanupPriorityManagement();
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700427 download_progress_ = 0.0;
428 SetStatusAndNotify(UPDATE_STATUS_IDLE);
Andrew de los Reyes6b78e292010-05-10 15:54:39 -0700429 actions_.clear();
Darin Petkov09f96c32010-07-20 09:24:57 -0700430 error_event_.reset(NULL);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700431}
432
433// Called whenever an action has finished processing, either successfully
434// or otherwise.
435void UpdateAttempter::ActionCompleted(ActionProcessor* processor,
436 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -0700437 ActionExitCode code) {
Darin Petkov1023a602010-08-30 13:47:51 -0700438 // Reset download progress regardless of whether or not the download
439 // action succeeded. Also, get the response code from HTTP request
440 // actions (update download as well as the initial update check
441 // actions).
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700442 const string type = action->Type();
Darin Petkov1023a602010-08-30 13:47:51 -0700443 if (type == DownloadAction::StaticType()) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700444 download_progress_ = 0.0;
Darin Petkov1023a602010-08-30 13:47:51 -0700445 DownloadAction* download_action = dynamic_cast<DownloadAction*>(action);
446 http_response_code_ = download_action->GetHTTPResponseCode();
447 } else if (type == OmahaRequestAction::StaticType()) {
448 OmahaRequestAction* omaha_request_action =
449 dynamic_cast<OmahaRequestAction*>(action);
450 // If the request is not an event, then it's the update-check.
451 if (!omaha_request_action->IsEvent()) {
452 http_response_code_ = omaha_request_action->GetHTTPResponseCode();
Darin Petkov85ced132010-09-01 10:20:56 -0700453 // Forward the server-dictated poll interval to the update check
454 // scheduler, if any.
455 if (update_check_scheduler_) {
456 update_check_scheduler_->set_poll_interval(
457 omaha_request_action->GetOutputObject().poll_interval);
458 }
Darin Petkov1023a602010-08-30 13:47:51 -0700459 }
460 }
Darin Petkov09f96c32010-07-20 09:24:57 -0700461 if (code != kActionCodeSuccess) {
Darin Petkov7ed561b2011-10-04 02:59:03 -0700462 // If the current state is at or past the download phase, count the failure
463 // in case a switch to full update becomes necessary. Ignore network
464 // transfer timeouts and failures.
Darin Petkov36275772010-10-01 11:40:57 -0700465 if (status_ >= UPDATE_STATUS_DOWNLOADING &&
Darin Petkov36275772010-10-01 11:40:57 -0700466 code != kActionCodeDownloadTransferError) {
467 MarkDeltaUpdateFailure();
468 }
Darin Petkov777dbfa2010-07-20 15:03:37 -0700469 // On failure, schedule an error event to be sent to Omaha.
470 CreatePendingErrorEvent(action, code);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700471 return;
Darin Petkov09f96c32010-07-20 09:24:57 -0700472 }
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700473 // Find out which action completed.
474 if (type == OmahaResponseHandlerAction::StaticType()) {
Darin Petkov9b230572010-10-08 10:20:09 -0700475 // Note that the status will be updated to DOWNLOADING when some bytes get
476 // actually downloaded from the server and the BytesReceived callback is
477 // invoked. This avoids notifying the user that a download has started in
478 // cases when the server and the client are unable to initiate the download.
479 CHECK(action == response_handler_action_.get());
480 const InstallPlan& plan = response_handler_action_->install_plan();
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700481 last_checked_time_ = time(NULL);
482 // TODO(adlr): put version in InstallPlan
483 new_version_ = "0.0.0.0";
484 new_size_ = plan.size;
Darin Petkov9b230572010-10-08 10:20:09 -0700485 SetupDownload();
Darin Petkovc6c135c2010-08-11 13:36:18 -0700486 SetupPriorityManagement();
Darin Petkovb00bccc2010-10-26 14:13:08 -0700487 SetStatusAndNotify(UPDATE_STATUS_UPDATE_AVAILABLE);
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700488 } else if (type == DownloadAction::StaticType()) {
489 SetStatusAndNotify(UPDATE_STATUS_FINALIZING);
490 }
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700491}
492
493// Stop updating. An attempt will be made to record status to the disk
494// so that updates can be resumed later.
495void UpdateAttempter::Terminate() {
496 // TODO(adlr): implement this method.
497 NOTIMPLEMENTED();
498}
499
500// Try to resume from a previously Terminate()d update.
501void UpdateAttempter::ResumeUpdating() {
502 // TODO(adlr): implement this method.
503 NOTIMPLEMENTED();
504}
505
Darin Petkov9d911fa2010-08-19 09:36:08 -0700506void UpdateAttempter::SetDownloadStatus(bool active) {
507 download_active_ = active;
508 LOG(INFO) << "Download status: " << (active ? "active" : "inactive");
509}
510
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700511void UpdateAttempter::BytesReceived(uint64_t bytes_received, uint64_t total) {
Darin Petkov9d911fa2010-08-19 09:36:08 -0700512 if (!download_active_) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700513 LOG(ERROR) << "BytesReceived called while not downloading.";
514 return;
515 }
Darin Petkovaf183052010-08-23 12:07:13 -0700516 double progress = static_cast<double>(bytes_received) /
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700517 static_cast<double>(total);
Darin Petkovaf183052010-08-23 12:07:13 -0700518 // Self throttle based on progress. Also send notifications if
519 // progress is too slow.
520 const double kDeltaPercent = 0.01; // 1%
521 if (status_ != UPDATE_STATUS_DOWNLOADING ||
522 bytes_received == total ||
523 progress - download_progress_ >= kDeltaPercent ||
524 TimeTicks::Now() - last_notify_time_ >= TimeDelta::FromSeconds(10)) {
525 download_progress_ = progress;
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700526 SetStatusAndNotify(UPDATE_STATUS_DOWNLOADING);
527 }
528}
529
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700530bool UpdateAttempter::GetStatus(int64_t* last_checked_time,
531 double* progress,
Gilad Arnold28e2f392012-02-09 14:36:46 -0800532 string* current_operation,
533 string* new_version,
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700534 int64_t* new_size) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700535 *last_checked_time = last_checked_time_;
536 *progress = download_progress_;
537 *current_operation = UpdateStatusToString(status_);
538 *new_version = new_version_;
539 *new_size = new_size_;
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700540 return true;
541}
542
Gilad Arnold28e2f392012-02-09 14:36:46 -0800543// Discovers the dut_flag GPIO identified by |gpio_dutflag_str| and stores the
544// full device name in |dutflag_dev_name_p|. The function uses an open libudev
545// instance |udev|. Returns zero on success, -1 otherwise.
546bool UpdateAttempter::GetDutflagGpioDevName(struct udev* udev,
547 const string& gpio_dutflag_str,
548 string* dutflag_dev_name_p) {
549 CHECK(udev && dutflag_dev_name_p);
550
551 struct udev_enumerate* udev_enum = NULL;
552 int num_gpio_dutflags = 0;
553 const string gpio_dutflag_pattern = "*" + gpio_dutflag_str;
554 int ret;
555
556 // Initialize udev enumerate context and closer.
557 if (!(udev_enum = udev_enumerate_new(udev))) {
558 LOG(ERROR) << "failed to obtain udev enumerate context";
559 return false;
560 }
561 ScopedUdevEnumerateCloser udev_enum_closer(&udev_enum);
562
563 // Populate filters for find an initialized GPIO chip.
564 if ((ret = udev_enumerate_add_match_subsystem(udev_enum, "gpio")) ||
565 (ret = udev_enumerate_add_match_sysname(udev_enum,
566 gpio_dutflag_pattern.c_str()))) {
567 LOG(ERROR) << "failed to initialize udev enumerate context (" << ret << ")";
568 return false;
569 }
570
571 // Obtain list of matching devices.
572 if ((ret = udev_enumerate_scan_devices(udev_enum))) {
573 LOG(ERROR) << "udev enumerate context scan failed (error code "
574 << ret << ")";
575 return false;
576 }
577
578 // Iterate over matching devices, obtain GPIO dut_flaga identifier.
579 struct udev_list_entry* list_entry;
580 udev_list_entry_foreach(list_entry,
581 udev_enumerate_get_list_entry(udev_enum)) {
582 // Make sure we're not enumerating more than one device.
583 num_gpio_dutflags++;
584 if (num_gpio_dutflags > 1) {
585 LOG(WARNING) <<
586 "enumerated multiple dutflag GPIOs, ignoring this one";
587 continue;
588 }
589
590 // Obtain device name.
591 const char* dev_name = udev_list_entry_get_name(list_entry);
592 if (!dev_name) {
593 LOG(WARNING) << "enumerated device has a null name string, skipping";
594 continue;
595 }
596
597 // Obtain device object.
598 struct udev_device* dev = udev_device_new_from_syspath(udev, dev_name);
599 if (!dev) {
600 LOG(WARNING) <<
601 "obtained a null device object for enumerated device, skipping";
602 continue;
603 }
604
605 // Obtain device syspath.
606 const char* dev_syspath = udev_device_get_syspath(dev);
607 if (dev_syspath) {
608 LOG(INFO) << "obtained device syspath: " << dev_syspath;
609 *dutflag_dev_name_p = dev_syspath;
610 } else {
611 LOG(WARNING) << "could not obtain device syspath";
612 }
613
614 udev_device_unref(dev);
615 }
616
617 return true;
618}
619
620// Discovers and stores the device names of the two dut_flag GPIOs. Returns zero
621// upon success, -1 otherwise.
622bool UpdateAttempter::GetDutflagGpioDevNames(string* dutflaga_dev_name_p,
623 string* dutflagb_dev_name_p) {
624 if (!(dutflaga_dev_name_p || dutflagb_dev_name_p))
625 return true; // No output pointers, nothing to do.
626
627 string gpio_dutflaga_str, gpio_dutflagb_str;
628
629 if (dutflaga_dev_name_.empty() || dutflagb_dev_name_.empty()) {
630 struct udev* udev = NULL;
631 struct udev_enumerate* udev_enum = NULL;
632 int num_gpio_chips = 0;
633 const char* id_gpio_dutflaga = NULL;
634 const char* id_gpio_dutflagb = NULL;
635 int ret;
636
637 LOG(INFO) << "begin discovery of dut_flaga/b devices";
638
639 // Obtain libudev instance and closer.
640 if (!(udev = udev_new())) {
641 LOG(ERROR) << "failed to obtain libudev instance";
642 return false;
643 }
644 ScopedUdevCloser udev_closer(&udev);
645
646 // Initialize a udev enumerate object and closer with a bounded lifespan.
647 {
648 if (!(udev_enum = udev_enumerate_new(udev))) {
649 LOG(ERROR) << "failed to obtain udev enumerate context";
650 return false;
651 }
652 ScopedUdevEnumerateCloser udev_enum_closer(&udev_enum);
653
654 // Populate filters for find an initialized GPIO chip.
655 if ((ret = udev_enumerate_add_match_subsystem(udev_enum, "gpio")) ||
656 (ret = udev_enumerate_add_match_sysname(udev_enum, "gpiochip*")) ||
657 (ret = udev_enumerate_add_match_property(udev_enum,
658 kIdGpioDutflaga, "*")) ||
659 (ret = udev_enumerate_add_match_property(udev_enum,
660 kIdGpioDutflagb, "*"))) {
661 LOG(ERROR) << "failed to initialize udev enumerate context ("
662 << ret << ")";
663 return false;
664 }
665
666 // Obtain list of matching devices.
667 if ((ret = udev_enumerate_scan_devices(udev_enum))) {
668 LOG(ERROR) << "udev enumerate context scan failed (" << ret << ")";
669 return false;
670 }
671
672 // Iterate over matching devices, obtain GPIO dut_flaga identifier.
673 struct udev_list_entry* list_entry;
674 udev_list_entry_foreach(list_entry,
675 udev_enumerate_get_list_entry(udev_enum)) {
676 // Make sure we're not enumerating more than one device.
677 num_gpio_chips++;
678 if (num_gpio_chips > 1) {
679 LOG(WARNING) << "enumerated multiple GPIO chips, ignoring this one";
680 continue;
681 }
682
683 // Obtain device name.
684 const char* dev_name = udev_list_entry_get_name(list_entry);
685 if (!dev_name) {
686 LOG(WARNING) << "enumerated device has a null name string, skipping";
687 continue;
688 }
689
690 // Obtain device object.
691 struct udev_device* dev = udev_device_new_from_syspath(udev, dev_name);
692 if (!dev) {
693 LOG(WARNING) <<
694 "obtained a null device object for enumerated device, skipping";
695 continue;
696 }
697
698 // Obtain dut_flaga/b identifiers.
699 id_gpio_dutflaga =
700 udev_device_get_property_value(dev, kIdGpioDutflaga);
701 id_gpio_dutflagb =
702 udev_device_get_property_value(dev, kIdGpioDutflagb);
703 if (id_gpio_dutflaga && id_gpio_dutflagb) {
704 LOG(INFO) << "found dut_flaga/b identifiers: a=" << id_gpio_dutflaga
705 << " b=" << id_gpio_dutflagb;
706
707 gpio_dutflaga_str = id_gpio_dutflaga;
708 gpio_dutflagb_str = id_gpio_dutflagb;
709 } else {
710 LOG(ERROR) << "GPIO chip missing dut_flaga/b properties";
711 }
712
713 udev_device_unref(dev);
714 }
715 }
716
717 // Obtain dut_flaga, reusing the same udev instance.
718 if (dutflaga_dev_name_.empty() && !gpio_dutflaga_str.empty()) {
719 LOG(INFO) << "discovering device for GPIO dut_flaga ";
720 if (!GetDutflagGpioDevName(udev, gpio_dutflaga_str,
721 &dutflaga_dev_name_)) {
722 LOG(ERROR) << "discovery of dut_flaga GPIO device failed";
723 return false;
724 }
725 }
726
727 // Now obtain dut_flagb.
728 if (dutflagb_dev_name_.empty() && !gpio_dutflagb_str.empty()) {
729 LOG(INFO) << "discovering device for GPIO dut_flagb";
730 if (!GetDutflagGpioDevName(udev, gpio_dutflagb_str,
731 &dutflagb_dev_name_)) {
732 LOG(ERROR) << "discovery of dut_flagb GPIO device failed";
733 return false;
734 }
735 }
736
737 LOG(INFO) << "end discovery of dut_flaga/b devices";
738 }
739
740 // Write cached GPIO dutflag(s) to output strings.
741 if (dutflaga_dev_name_p)
742 *dutflaga_dev_name_p = dutflaga_dev_name_;
743 if (dutflagb_dev_name_p)
744 *dutflagb_dev_name_p = dutflagb_dev_name_;
745
746 return true;
747}
748
749// Reads the value of the dut_flaga GPIO and stores it in |status_p|. Returns
750// true upon success, false otherwise (which also means that the GPIO value was
751// not stored and should not be used).
752bool UpdateAttempter::GetDutflagaGpio(bool* status_p) {
753 // Obtain GPIO device file name.
754 string dutflaga_dev_name;
755 GetDutflagGpioDevNames(&dutflaga_dev_name, NULL);
756 if (dutflaga_dev_name.empty()) {
757 LOG(WARNING) << "could not find dutflaga GPIO device";
758 return false;
759 }
760
761 // Open device for reading.
762 string dutflaga_value_dev_name = dutflaga_dev_name + "/value";
763 int dutflaga_fd;
764 HANDLE_EINTR((dutflaga_fd = open(dutflaga_value_dev_name.c_str(), 0)));
765 if (dutflaga_fd < 0) {
766 PLOG(ERROR) << "opening dutflaga GPIO device file failed";
767 return false;
768 }
769 ScopedFdCloser dutflaga_fd_closer(&dutflaga_fd);
770
771 // Read the dut_flaga GPIO signal. We attempt to read more than---but expect
772 // to receive exactly---two characters: a '0' or '1', and a newline. This is
773 // to ensure that the GPIO device returns a legible result.
774 char buf[3];
775 int ret;
776 HANDLE_EINTR((ret = read(dutflaga_fd, buf, 3)));
777 if (ret != 2) {
778 if (ret < 0)
779 PLOG(ERROR) << "reading dutflaga GPIO status failed";
780 else
781 LOG(ERROR) << "read more than one byte (" << ret << ")";
782 return false;
783 }
784
785 // Identify and write GPIO status.
786 char c = buf[0];
787 if ((c == '0' || c == '1') && buf[1] == '\n') {
788 *status_p = (c == '1');
789 } else {
790 buf[2] = '\0';
791 LOG(ERROR) << "read unexpected value from dutflaga GPIO: " << buf;
792 return false;
793 }
794
795 return true;
796}
797
Andrew de los Reyes6dbf30a2011-04-19 10:58:16 -0700798void UpdateAttempter::UpdateBootFlags() {
Darin Petkov58dd1342011-05-06 12:05:13 -0700799 if (update_boot_flags_running_) {
800 LOG(INFO) << "Update boot flags running, nothing to do.";
Andrew de los Reyes6dbf30a2011-04-19 10:58:16 -0700801 return;
802 }
Darin Petkov58dd1342011-05-06 12:05:13 -0700803 if (updated_boot_flags_) {
804 LOG(INFO) << "Already updated boot flags. Skipping.";
805 if (start_action_processor_) {
806 ScheduleProcessingStart();
807 }
808 return;
809 }
810 // This is purely best effort. Failures should be logged by Subprocess. Run
811 // the script asynchronously to avoid blocking the event loop regardless of
812 // the script runtime.
813 update_boot_flags_running_ = true;
814 LOG(INFO) << "Updating boot flags...";
Andrew de los Reyes6dbf30a2011-04-19 10:58:16 -0700815 vector<string> cmd(1, "/usr/sbin/chromeos-setgoodkernel");
Darin Petkov58dd1342011-05-06 12:05:13 -0700816 if (!Subprocess::Get().Exec(cmd, StaticCompleteUpdateBootFlags, this)) {
817 CompleteUpdateBootFlags(1);
818 }
819}
820
821void UpdateAttempter::CompleteUpdateBootFlags(int return_code) {
822 update_boot_flags_running_ = false;
Andrew de los Reyes6dbf30a2011-04-19 10:58:16 -0700823 updated_boot_flags_ = true;
Darin Petkov58dd1342011-05-06 12:05:13 -0700824 if (start_action_processor_) {
825 ScheduleProcessingStart();
826 }
827}
828
829void UpdateAttempter::StaticCompleteUpdateBootFlags(
830 int return_code,
Gilad Arnold28e2f392012-02-09 14:36:46 -0800831 const string& output,
Darin Petkov58dd1342011-05-06 12:05:13 -0700832 void* p) {
833 reinterpret_cast<UpdateAttempter*>(p)->CompleteUpdateBootFlags(return_code);
Andrew de los Reyes6dbf30a2011-04-19 10:58:16 -0700834}
835
Darin Petkov61635a92011-05-18 16:20:36 -0700836void UpdateAttempter::BroadcastStatus() {
837 if (!dbus_service_) {
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700838 return;
Darin Petkov61635a92011-05-18 16:20:36 -0700839 }
Darin Petkovaf183052010-08-23 12:07:13 -0700840 last_notify_time_ = TimeTicks::Now();
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700841 update_engine_service_emit_status_update(
842 dbus_service_,
843 last_checked_time_,
844 download_progress_,
845 UpdateStatusToString(status_),
846 new_version_.c_str(),
847 new_size_);
848}
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -0700849
Darin Petkov61635a92011-05-18 16:20:36 -0700850void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) {
851 status_ = status;
852 if (update_check_scheduler_) {
853 update_check_scheduler_->SetUpdateStatus(status_);
854 }
855 BroadcastStatus();
856}
857
Darin Petkov777dbfa2010-07-20 15:03:37 -0700858void UpdateAttempter::CreatePendingErrorEvent(AbstractAction* action,
859 ActionExitCode code) {
Darin Petkov09f96c32010-07-20 09:24:57 -0700860 if (error_event_.get()) {
861 // This shouldn't really happen.
862 LOG(WARNING) << "There's already an existing pending error event.";
863 return;
864 }
Darin Petkov777dbfa2010-07-20 15:03:37 -0700865
Darin Petkovabc7bc02011-02-23 14:39:43 -0800866 // For now assume that a generic Omaha response action failure means that
867 // there's no update so don't send an event. Also, double check that the
868 // failure has not occurred while sending an error event -- in which case
869 // don't schedule another. This shouldn't really happen but just in case...
870 if ((action->Type() == OmahaResponseHandlerAction::StaticType() &&
871 code == kActionCodeError) ||
Darin Petkov777dbfa2010-07-20 15:03:37 -0700872 status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
873 return;
874 }
875
876 code = GetErrorCodeForAction(action, code);
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700877 fake_update_success_ = code == kActionCodePostinstallBootedFromFirmwareB;
Darin Petkov18c7bce2011-06-16 14:07:00 -0700878
879 // Apply the bit modifiers to the error code.
880 if (!utils::IsNormalBootMode()) {
881 code = static_cast<ActionExitCode>(code | kActionCodeBootModeFlag);
882 }
883 if (response_handler_action_.get() &&
884 response_handler_action_->install_plan().is_resume) {
885 code = static_cast<ActionExitCode>(code | kActionCodeResumedFlag);
886 }
Darin Petkov09f96c32010-07-20 09:24:57 -0700887 error_event_.reset(new OmahaEvent(OmahaEvent::kTypeUpdateComplete,
888 OmahaEvent::kResultError,
889 code));
890}
891
892bool UpdateAttempter::ScheduleErrorEventAction() {
893 if (error_event_.get() == NULL)
894 return false;
895
Darin Petkov1023a602010-08-30 13:47:51 -0700896 LOG(INFO) << "Update failed -- reporting the error event.";
Darin Petkov09f96c32010-07-20 09:24:57 -0700897 shared_ptr<OmahaRequestAction> error_event_action(
Darin Petkov1cbd78f2010-07-29 12:38:34 -0700898 new OmahaRequestAction(prefs_,
899 omaha_request_params_,
Darin Petkov09f96c32010-07-20 09:24:57 -0700900 error_event_.release(), // Pass ownership.
Thieu Le116fda32011-04-19 11:01:54 -0700901 new LibcurlHttpFetcher(GetProxyResolver()),
902 false));
Darin Petkov09f96c32010-07-20 09:24:57 -0700903 actions_.push_back(shared_ptr<AbstractAction>(error_event_action));
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700904 processor_->EnqueueAction(error_event_action.get());
Darin Petkov09f96c32010-07-20 09:24:57 -0700905 SetStatusAndNotify(UPDATE_STATUS_REPORTING_ERROR_EVENT);
Darin Petkovf42cc1c2010-09-01 09:03:02 -0700906 processor_->StartProcessing();
Darin Petkov09f96c32010-07-20 09:24:57 -0700907 return true;
908}
909
Darin Petkovc6c135c2010-08-11 13:36:18 -0700910void UpdateAttempter::SetPriority(utils::ProcessPriority priority) {
911 if (priority_ == priority) {
912 return;
913 }
914 if (utils::SetProcessPriority(priority)) {
915 priority_ = priority;
916 LOG(INFO) << "Process priority = " << priority_;
917 }
918}
919
920void UpdateAttempter::SetupPriorityManagement() {
921 if (manage_priority_source_) {
922 LOG(ERROR) << "Process priority timeout source hasn't been destroyed.";
923 CleanupPriorityManagement();
924 }
Darin Petkovf622ef72010-10-26 13:49:24 -0700925 const int kPriorityTimeout = 2 * 60 * 60; // 2 hours
Darin Petkovc6c135c2010-08-11 13:36:18 -0700926 manage_priority_source_ = g_timeout_source_new_seconds(kPriorityTimeout);
927 g_source_set_callback(manage_priority_source_,
928 StaticManagePriorityCallback,
929 this,
930 NULL);
931 g_source_attach(manage_priority_source_, NULL);
932 SetPriority(utils::kProcessPriorityLow);
933}
934
935void UpdateAttempter::CleanupPriorityManagement() {
936 if (manage_priority_source_) {
937 g_source_destroy(manage_priority_source_);
938 manage_priority_source_ = NULL;
939 }
940 SetPriority(utils::kProcessPriorityNormal);
941}
942
943gboolean UpdateAttempter::StaticManagePriorityCallback(gpointer data) {
944 return reinterpret_cast<UpdateAttempter*>(data)->ManagePriorityCallback();
945}
946
Darin Petkove6ef2f82011-03-07 17:31:11 -0800947gboolean UpdateAttempter::StaticStartProcessing(gpointer data) {
948 reinterpret_cast<UpdateAttempter*>(data)->processor_->StartProcessing();
949 return FALSE; // Don't call this callback again.
950}
951
Darin Petkov58dd1342011-05-06 12:05:13 -0700952void UpdateAttempter::ScheduleProcessingStart() {
953 LOG(INFO) << "Scheduling an action processor start.";
954 start_action_processor_ = false;
955 g_idle_add(&StaticStartProcessing, this);
956}
957
Darin Petkovc6c135c2010-08-11 13:36:18 -0700958bool UpdateAttempter::ManagePriorityCallback() {
Darin Petkovf622ef72010-10-26 13:49:24 -0700959 SetPriority(utils::kProcessPriorityNormal);
Darin Petkovc6c135c2010-08-11 13:36:18 -0700960 manage_priority_source_ = NULL;
Darin Petkovf622ef72010-10-26 13:49:24 -0700961 return false; // Destroy the timeout source.
Darin Petkovc6c135c2010-08-11 13:36:18 -0700962}
963
Darin Petkov36275772010-10-01 11:40:57 -0700964void UpdateAttempter::DisableDeltaUpdateIfNeeded() {
965 int64_t delta_failures;
966 if (omaha_request_params_.delta_okay &&
967 prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) &&
968 delta_failures >= kMaxDeltaUpdateFailures) {
969 LOG(WARNING) << "Too many delta update failures, forcing full update.";
970 omaha_request_params_.delta_okay = false;
971 }
972}
973
974void UpdateAttempter::MarkDeltaUpdateFailure() {
Darin Petkov2dd01092010-10-08 15:43:05 -0700975 // Don't try to resume a failed delta update.
976 DeltaPerformer::ResetUpdateProgress(prefs_, false);
Darin Petkov36275772010-10-01 11:40:57 -0700977 int64_t delta_failures;
978 if (!prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) ||
979 delta_failures < 0) {
980 delta_failures = 0;
981 }
982 prefs_->SetInt64(kPrefsDeltaUpdateFailures, ++delta_failures);
983}
984
Darin Petkov9b230572010-10-08 10:20:09 -0700985void UpdateAttempter::SetupDownload() {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800986 MultiRangeHttpFetcher* fetcher =
987 dynamic_cast<MultiRangeHttpFetcher*>(download_action_->http_fetcher());
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800988 fetcher->ClearRanges();
Darin Petkov9b230572010-10-08 10:20:09 -0700989 if (response_handler_action_->install_plan().is_resume) {
Darin Petkovb21ce5d2010-10-21 16:03:05 -0700990 // Resuming an update so fetch the update manifest metadata first.
Darin Petkov9b230572010-10-08 10:20:09 -0700991 int64_t manifest_metadata_size = 0;
992 prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800993 fetcher->AddRange(0, manifest_metadata_size);
Darin Petkovb21ce5d2010-10-21 16:03:05 -0700994 // If there're remaining unprocessed data blobs, fetch them. Be careful not
995 // to request data beyond the end of the payload to avoid 416 HTTP response
996 // error codes.
Darin Petkov9b230572010-10-08 10:20:09 -0700997 int64_t next_data_offset = 0;
998 prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
Darin Petkovb21ce5d2010-10-21 16:03:05 -0700999 uint64_t resume_offset = manifest_metadata_size + next_data_offset;
1000 if (resume_offset < response_handler_action_->install_plan().size) {
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001001 fetcher->AddRange(resume_offset);
Darin Petkovb21ce5d2010-10-21 16:03:05 -07001002 }
Darin Petkov9b230572010-10-08 10:20:09 -07001003 } else {
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001004 fetcher->AddRange(0);
Darin Petkov9b230572010-10-08 10:20:09 -07001005 }
Darin Petkov9b230572010-10-08 10:20:09 -07001006}
1007
Thieu Le116fda32011-04-19 11:01:54 -07001008void UpdateAttempter::PingOmaha() {
Thieu Led88a8572011-05-26 09:09:19 -07001009 if (!processor_->IsRunning()) {
1010 shared_ptr<OmahaRequestAction> ping_action(
1011 new OmahaRequestAction(prefs_,
1012 omaha_request_params_,
1013 NULL,
1014 new LibcurlHttpFetcher(GetProxyResolver()),
1015 true));
1016 actions_.push_back(shared_ptr<OmahaRequestAction>(ping_action));
1017 processor_->set_delegate(NULL);
1018 processor_->EnqueueAction(ping_action.get());
1019 // Call StartProcessing() synchronously here to avoid any race conditions
1020 // caused by multiple outstanding ping Omaha requests. If we call
1021 // StartProcessing() asynchronously, the device can be suspended before we
1022 // get a chance to callback to StartProcessing(). When the device resumes
1023 // (assuming the device sleeps longer than the next update check period),
1024 // StartProcessing() is called back and at the same time, the next update
1025 // check is fired which eventually invokes StartProcessing(). A crash
1026 // can occur because StartProcessing() checks to make sure that the
1027 // processor is idle which it isn't due to the two concurrent ping Omaha
1028 // requests.
1029 processor_->StartProcessing();
1030 } else {
Darin Petkov58dd1342011-05-06 12:05:13 -07001031 LOG(WARNING) << "Action processor running, Omaha ping suppressed.";
Darin Petkov58dd1342011-05-06 12:05:13 -07001032 }
Thieu Led88a8572011-05-26 09:09:19 -07001033
1034 // Update the status which will schedule the next update check
Thieu Le116fda32011-04-19 11:01:54 -07001035 SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
1036}
1037
Andrew de los Reyes4e9b9f42010-04-26 15:06:43 -07001038} // namespace chromeos_update_engine