blob: 131efbb96beff99aaffc4a1b97d723573f0c404e [file] [log] [blame]
Alex Deymo5e3ea272016-01-28 13:42:23 -08001//
2// Copyright (C) 2016 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/update_attempter_android.h"
18
19#include <algorithm>
20#include <utility>
21
22#include <base/bind.h>
23#include <base/logging.h>
24#include <brillo/bind_lambda.h>
25#include <brillo/message_loops/message_loop.h>
26
27#include "update_engine/common/constants.h"
28#include "update_engine/common/libcurl_http_fetcher.h"
29#include "update_engine/common/multi_range_http_fetcher.h"
30#include "update_engine/common/utils.h"
31#include "update_engine/daemon_state_android.h"
32#include "update_engine/payload_consumer/download_action.h"
33#include "update_engine/payload_consumer/filesystem_verifier_action.h"
34#include "update_engine/payload_consumer/postinstall_runner_action.h"
35
36using base::Bind;
37using base::TimeDelta;
38using base::TimeTicks;
39using std::shared_ptr;
40using std::string;
41using std::vector;
42
43namespace chromeos_update_engine {
44
45namespace {
46
47const char* const kErrorDomain = "update_engine";
48// TODO(deymo): Convert the different errors to a numeric value to report them
49// back on the service error.
50const char* const kGenericError = "generic_error";
51
52// Log and set the error on the passed ErrorPtr.
53bool LogAndSetError(brillo::ErrorPtr* error,
54 const tracked_objects::Location& location,
55 const string& reason) {
56 brillo::Error::AddTo(error, location, kErrorDomain, kGenericError, reason);
57 LOG(ERROR) << "Replying with failure: " << location.ToString() << ": "
58 << reason;
59 return false;
60}
61
62} // namespace
63
64UpdateAttempterAndroid::UpdateAttempterAndroid(
65 DaemonStateAndroid* daemon_state,
66 PrefsInterface* prefs,
67 BootControlInterface* boot_control,
68 HardwareInterface* hardware)
69 : daemon_state_(daemon_state),
70 prefs_(prefs),
71 boot_control_(boot_control),
72 hardware_(hardware),
73 processor_(new ActionProcessor()) {
74}
75
76UpdateAttempterAndroid::~UpdateAttempterAndroid() {
77 // Release ourselves as the ActionProcessor's delegate to prevent
78 // re-scheduling the updates due to the processing stopped.
79 processor_->set_delegate(nullptr);
80}
81
82void UpdateAttempterAndroid::Init() {
83 // In case of update_engine restart without a reboot we need to restore the
84 // reboot needed state.
85 if (UpdateCompletedOnThisBoot())
86 status_ = UpdateStatus::UPDATED_NEED_REBOOT;
87 else
88 status_ = UpdateStatus::IDLE;
89}
90
91bool UpdateAttempterAndroid::ApplyPayload(
92 const string& payload_url,
93 int64_t payload_offset,
94 int64_t payload_size,
95 const vector<string>& key_value_pair_headers,
96 brillo::ErrorPtr* error) {
97 if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
98 return LogAndSetError(
99 error, FROM_HERE, "An update already applied, waiting for reboot");
100 }
101 if (ongoing_update_) {
102 return LogAndSetError(
103 error, FROM_HERE, "Already processing an update, cancel it first.");
104 }
105 DCHECK(status_ == UpdateStatus::IDLE);
106
107 // Unique identifier for the payload.
108 // TODO(deymo): Set this the payload unique id using a value passed in the
109 // |key_value_pair_headers| list to allow resuming updates.
110 string payload_id = "";
111
112 // Setup the InstallPlan based on the request.
113 install_plan_ = InstallPlan();
114
115 install_plan_.download_url = payload_url;
116 install_plan_.version = "";
117 install_plan_.payload_size = payload_size;
118 // TODO(deymo): Retrieve the payload_hash from the properties.
119 install_plan_.payload_hash = "";
120 install_plan_.metadata_size = 0;
121 install_plan_.metadata_signature = "";
122 // The |public_key_rsa| key would override the public key stored on disk.
123 install_plan_.public_key_rsa = "";
124
125 install_plan_.hash_checks_mandatory = hardware_->IsOfficialBuild();
126 install_plan_.is_resume = !payload_id.empty() &&
127 DeltaPerformer::CanResumeUpdate(prefs_, payload_id);
128 if (!install_plan_.is_resume) {
129 if (!DeltaPerformer::ResetUpdateProgress(prefs_, false)) {
130 LOG(WARNING) << "Unable to reset the update progress.";
131 }
132 if (!prefs_->SetString(kPrefsUpdateCheckResponseHash, payload_id)) {
133 LOG(WARNING) << "Unable to save the update check response hash.";
134 }
135 }
136 // The |is_full_update| is not used anymore since minor_version 3.
137 install_plan_.is_full_update = true;
138
139 install_plan_.source_slot = boot_control_->GetCurrentSlot();
140 install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0;
141 install_plan_.powerwash_required = false;
142
143 LOG(INFO) << "Using this install plan:";
144 install_plan_.Dump();
145
146 BuildUpdateActions();
147 SetupDownload();
148 cpu_limiter_.StartLimiter();
149 SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
150
151 // Just in case we didn't update boot flags yet, make sure they're updated
152 // before any update processing starts. This will start the update process.
153 UpdateBootFlags();
154 return true;
155}
156
157bool UpdateAttempterAndroid::SuspendUpdate(brillo::ErrorPtr* error) {
158 // TODO(deymo): Implement suspend/resume.
159 return LogAndSetError(error, FROM_HERE, "Suspend/resume not implemented");
160}
161
162bool UpdateAttempterAndroid::ResumeUpdate(brillo::ErrorPtr* error) {
163 // TODO(deymo): Implement suspend/resume.
164 return LogAndSetError(error, FROM_HERE, "Suspend/resume not implemented");
165}
166
167bool UpdateAttempterAndroid::CancelUpdate(brillo::ErrorPtr* error) {
168 if (status_ == UpdateStatus::IDLE ||
169 status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
170 return LogAndSetError(error, FROM_HERE, "No ongoing update to cancel.");
171 }
172
173 // TODO(deymo): Implement cancel.
174 return LogAndSetError(error, FROM_HERE, "Cancel not implemented");
175}
176
177void UpdateAttempterAndroid::ProcessingDone(const ActionProcessor* processor,
178 ErrorCode code) {
179 LOG(INFO) << "Processing Done.";
180
181 if (code == ErrorCode::kSuccess) {
182 // Update succeeded.
183 WriteUpdateCompletedMarker();
184 prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
185 DeltaPerformer::ResetUpdateProgress(prefs_, false);
186
187 LOG(INFO) << "Update successfully applied, waiting to reboot.";
188 }
189
190 TerminateUpdateAndNotify(code);
191}
192
193void UpdateAttempterAndroid::ProcessingStopped(
194 const ActionProcessor* processor) {
195 TerminateUpdateAndNotify(ErrorCode::kUserCanceled);
196}
197
198void UpdateAttempterAndroid::ActionCompleted(ActionProcessor* processor,
199 AbstractAction* action,
200 ErrorCode code) {
201 // Reset download progress regardless of whether or not the download
202 // action succeeded.
203 const string type = action->Type();
204 if (type == DownloadAction::StaticType()) {
205 download_progress_ = 0.0;
206 }
207 if (code != ErrorCode::kSuccess) {
208 // If an action failed, the ActionProcessor will cancel the whole thing.
209 return;
210 }
211 if (type == DownloadAction::StaticType()) {
212 SetStatusAndNotify(UpdateStatus::FINALIZING);
213 }
214}
215
216void UpdateAttempterAndroid::BytesReceived(uint64_t bytes_progressed,
217 uint64_t bytes_received,
218 uint64_t total) {
219 double progress = 0.;
220 if (total)
221 progress = static_cast<double>(bytes_received) / static_cast<double>(total);
222 // Self throttle based on progress. Also send notifications if
223 // progress is too slow.
224 const double kDeltaPercent = 0.01; // 1%
225 if (status_ != UpdateStatus::DOWNLOADING || bytes_received == total ||
226 progress - download_progress_ >= kDeltaPercent ||
227 TimeTicks::Now() - last_notify_time_ >= TimeDelta::FromSeconds(10)) {
228 download_progress_ = progress;
229 SetStatusAndNotify(UpdateStatus::DOWNLOADING);
230 }
231}
232
233bool UpdateAttempterAndroid::ShouldCancel(ErrorCode* cancel_reason) {
234 // TODO(deymo): Notify the DownloadAction that it should cancel the update
235 // download.
236 return false;
237}
238
239void UpdateAttempterAndroid::DownloadComplete() {
240 // Nothing needs to be done when the download completes.
241}
242
243void UpdateAttempterAndroid::UpdateBootFlags() {
244 if (updated_boot_flags_) {
245 LOG(INFO) << "Already updated boot flags. Skipping.";
246 CompleteUpdateBootFlags(true);
247 return;
248 }
249 // This is purely best effort.
250 LOG(INFO) << "Marking booted slot as good.";
251 if (!boot_control_->MarkBootSuccessfulAsync(
252 Bind(&UpdateAttempterAndroid::CompleteUpdateBootFlags,
253 base::Unretained(this)))) {
254 LOG(ERROR) << "Failed to mark current boot as successful.";
255 CompleteUpdateBootFlags(false);
256 }
257}
258
259void UpdateAttempterAndroid::CompleteUpdateBootFlags(bool successful) {
260 updated_boot_flags_ = true;
261 ScheduleProcessingStart();
262}
263
264void UpdateAttempterAndroid::ScheduleProcessingStart() {
265 LOG(INFO) << "Scheduling an action processor start.";
266 brillo::MessageLoop::current()->PostTask(
267 FROM_HERE, Bind([this] { this->processor_->StartProcessing(); }));
268}
269
270void UpdateAttempterAndroid::TerminateUpdateAndNotify(ErrorCode error_code) {
271 if (status_ == UpdateStatus::IDLE) {
272 LOG(ERROR) << "No ongoing update, but TerminatedUpdate() called.";
273 return;
274 }
275
276 // Reset cpu shares back to normal.
277 cpu_limiter_.StopLimiter();
278 download_progress_ = 0.0;
279 actions_.clear();
280 UpdateStatus new_status =
281 (error_code == ErrorCode::kSuccess ? UpdateStatus::UPDATED_NEED_REBOOT
282 : UpdateStatus::IDLE);
283 SetStatusAndNotify(new_status);
284 ongoing_update_ = false;
285
286 for (auto observer : daemon_state_->service_observers())
287 observer->SendPayloadApplicationComplete(error_code);
288}
289
290void UpdateAttempterAndroid::SetStatusAndNotify(UpdateStatus status) {
291 status_ = status;
292 for (auto observer : daemon_state_->service_observers()) {
293 observer->SendStatusUpdate(
294 0, download_progress_, status_, "", install_plan_.payload_size);
295 }
296 last_notify_time_ = TimeTicks::Now();
297}
298
299void UpdateAttempterAndroid::BuildUpdateActions() {
300 CHECK(!processor_->IsRunning());
301 processor_->set_delegate(this);
302
303 // Actions:
304 shared_ptr<InstallPlanAction> install_plan_action(
305 new InstallPlanAction(install_plan_));
306
307 LibcurlHttpFetcher* download_fetcher =
308 new LibcurlHttpFetcher(&proxy_resolver_, hardware_);
309 download_fetcher->set_server_to_check(ServerToCheck::kDownload);
310 shared_ptr<DownloadAction> download_action(new DownloadAction(
311 prefs_,
312 boot_control_,
313 hardware_,
314 nullptr, // system_state, not used.
315 new MultiRangeHttpFetcher(download_fetcher))); // passes ownership
316 shared_ptr<FilesystemVerifierAction> dst_filesystem_verifier_action(
317 new FilesystemVerifierAction(boot_control_,
318 VerifierMode::kVerifyTargetHash));
319
320 shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
321 new PostinstallRunnerAction(boot_control_));
322
323 download_action->set_delegate(this);
324 download_action_ = download_action;
325
326 actions_.push_back(shared_ptr<AbstractAction>(install_plan_action));
327 actions_.push_back(shared_ptr<AbstractAction>(download_action));
328 actions_.push_back(
329 shared_ptr<AbstractAction>(dst_filesystem_verifier_action));
330 actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
331
332 // Bond them together. We have to use the leaf-types when calling
333 // BondActions().
334 BondActions(install_plan_action.get(), download_action.get());
335 BondActions(download_action.get(), dst_filesystem_verifier_action.get());
336 BondActions(dst_filesystem_verifier_action.get(),
337 postinstall_runner_action.get());
338
339 // Enqueue the actions.
340 for (const shared_ptr<AbstractAction>& action : actions_)
341 processor_->EnqueueAction(action.get());
342}
343
344void UpdateAttempterAndroid::SetupDownload() {
345 MultiRangeHttpFetcher* fetcher =
346 static_cast<MultiRangeHttpFetcher*>(download_action_->http_fetcher());
347 fetcher->ClearRanges();
348 if (install_plan_.is_resume) {
349 // Resuming an update so fetch the update manifest metadata first.
350 int64_t manifest_metadata_size = 0;
351 prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
352 fetcher->AddRange(0, manifest_metadata_size);
353 // If there're remaining unprocessed data blobs, fetch them. Be careful not
354 // to request data beyond the end of the payload to avoid 416 HTTP response
355 // error codes.
356 int64_t next_data_offset = 0;
357 prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
358 uint64_t resume_offset = manifest_metadata_size + next_data_offset;
359 if (!install_plan_.payload_size ||
360 resume_offset < install_plan_.payload_size) {
361 fetcher->AddRange(resume_offset);
362 }
363 } else {
364 fetcher->AddRange(0);
365 }
366}
367
368bool UpdateAttempterAndroid::WriteUpdateCompletedMarker() {
369 string boot_id;
370 TEST_AND_RETURN_FALSE(utils::GetBootId(&boot_id));
371 prefs_->SetString(kPrefsUpdateCompletedOnBootId, boot_id);
372 return true;
373}
374
375bool UpdateAttempterAndroid::UpdateCompletedOnThisBoot() {
376 // In case of an update_engine restart without a reboot, we stored the boot_id
377 // when the update was completed by setting a pref, so we can check whether
378 // the last update was on this boot or a previous one.
379 string boot_id;
380 TEST_AND_RETURN_FALSE(utils::GetBootId(&boot_id));
381
382 string update_completed_on_boot_id;
383 return (prefs_->Exists(kPrefsUpdateCompletedOnBootId) &&
384 prefs_->GetString(kPrefsUpdateCompletedOnBootId,
385 &update_completed_on_boot_id) &&
386 update_completed_on_boot_id == boot_id);
387}
388
389} // namespace chromeos_update_engine