Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: delta_performer.cc

Issue 3521016: AU: Start checkpointing update progress. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/update_engine.git
Patch Set: address review comments Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « delta_performer.h ('k') | delta_performer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "update_engine/delta_performer.h" 5 #include "update_engine/delta_performer.h"
6 6
7 #include <endian.h> 7 #include <endian.h>
8 #include <errno.h> 8 #include <errno.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <cstring> 11 #include <cstring>
12 #include <string> 12 #include <string>
13 #include <vector> 13 #include <vector>
14 14
15 #include <base/scoped_ptr.h> 15 #include <base/scoped_ptr.h>
16 #include <base/string_util.h> 16 #include <base/string_util.h>
17 #include <google/protobuf/repeated_field.h> 17 #include <google/protobuf/repeated_field.h>
18 18
19 #include "update_engine/bzip_extent_writer.h" 19 #include "update_engine/bzip_extent_writer.h"
20 #include "update_engine/delta_diff_generator.h" 20 #include "update_engine/delta_diff_generator.h"
21 #include "update_engine/extent_writer.h" 21 #include "update_engine/extent_writer.h"
22 #include "update_engine/graph_types.h" 22 #include "update_engine/graph_types.h"
23 #include "update_engine/payload_signer.h" 23 #include "update_engine/payload_signer.h"
24 #include "update_engine/prefs_interface.h"
24 #include "update_engine/subprocess.h" 25 #include "update_engine/subprocess.h"
25 26
26 using std::min; 27 using std::min;
27 using std::string; 28 using std::string;
28 using std::vector; 29 using std::vector;
29 using google::protobuf::RepeatedPtrField; 30 using google::protobuf::RepeatedPtrField;
30 31
31 namespace chromeos_update_engine { 32 namespace chromeos_update_engine {
32 33
33 namespace { 34 namespace {
34 35
35 const int kDeltaVersionLength = 8; 36 const int kDeltaVersionLength = 8;
36 const int kDeltaProtobufLengthLength = 8; 37 const int kDeltaProtobufLengthLength = 8;
37 const char kUpdatePayloadPublicKeyPath[] = 38 const char kUpdatePayloadPublicKeyPath[] =
38 "/usr/share/update_engine/update-payload-key.pub.pem"; 39 "/usr/share/update_engine/update-payload-key.pub.pem";
40 const int kUpdateStateOperationInvalid = -1;
41
42 // Returns true if |op| is idempotent -- i.e., if we can interrupt it and repeat
43 // it safely. Returns false otherwise.
44 bool IsIdempotentOperation(const DeltaArchiveManifest_InstallOperation& op) {
45 if (op.src_extents_size() == 0) {
46 return true;
47 }
48 // TODO(petkov): Cover the case where the source and target extents don't
49 // intersect.
50 return false;
51 }
39 52
40 // Converts extents to a human-readable string, for use by DumpUpdateProto(). 53 // Converts extents to a human-readable string, for use by DumpUpdateProto().
41 string ExtentsToString(const RepeatedPtrField<Extent>& extents) { 54 string ExtentsToString(const RepeatedPtrField<Extent>& extents) {
42 string ret; 55 string ret;
43 for (int i = 0; i < extents.size(); i++) { 56 for (int i = 0; i < extents.size(); i++) {
44 const Extent& extent = extents.Get(i); 57 const Extent& extent = extents.Get(i);
45 if (extent.start_block() == kSparseHole) { 58 if (extent.start_block() == kSparseHole) {
46 ret += StringPrintf("{kSparseHole, %" PRIu64 "}, ", extent.num_blocks()); 59 ret += StringPrintf("{kSparseHole, %" PRIu64 "}, ", extent.num_blocks());
47 } else { 60 } else {
48 ret += StringPrintf("{%" PRIu64 ", %" PRIu64 "}, ", 61 ret += StringPrintf("{%" PRIu64 ", %" PRIu64 "}, ",
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 } 183 }
171 // We have the full proto buffer in buffer_. Parse it. 184 // We have the full proto buffer in buffer_. Parse it.
172 const int offset = strlen(kDeltaMagic) + kDeltaVersionLength + 185 const int offset = strlen(kDeltaMagic) + kDeltaVersionLength +
173 kDeltaProtobufLengthLength; 186 kDeltaProtobufLengthLength;
174 if (!manifest_.ParseFromArray(&buffer_[offset], protobuf_length)) { 187 if (!manifest_.ParseFromArray(&buffer_[offset], protobuf_length)) {
175 LOG(ERROR) << "Unable to parse manifest in update file."; 188 LOG(ERROR) << "Unable to parse manifest in update file.";
176 return -EINVAL; 189 return -EINVAL;
177 } 190 }
178 // Remove protobuf and header info from buffer_, so buffer_ contains 191 // Remove protobuf and header info from buffer_, so buffer_ contains
179 // just data blobs 192 // just data blobs
180 DiscardBufferHeadBytes(strlen(kDeltaMagic) + 193 size_t metadata_size = strlen(kDeltaMagic) + kDeltaVersionLength +
181 kDeltaVersionLength + 194 kDeltaProtobufLengthLength + protobuf_length;
182 kDeltaProtobufLengthLength + protobuf_length, 195 DiscardBufferHeadBytes(metadata_size,
183 true); // do_hash 196 true); // do_hash
197 LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize,
198 metadata_size))
199 << "Unable to save the manifest metadata size.";
184 manifest_valid_ = true; 200 manifest_valid_ = true;
185 block_size_ = manifest_.block_size(); 201 block_size_ = manifest_.block_size();
186 } 202 }
187 ssize_t total_operations = manifest_.install_operations_size() + 203 ssize_t total_operations = manifest_.install_operations_size() +
188 manifest_.kernel_install_operations_size(); 204 manifest_.kernel_install_operations_size();
189 while (next_operation_num_ < total_operations) { 205 while (next_operation_num_ < total_operations) {
190 const DeltaArchiveManifest_InstallOperation &op = 206 const DeltaArchiveManifest_InstallOperation &op =
191 next_operation_num_ < manifest_.install_operations_size() ? 207 next_operation_num_ < manifest_.install_operations_size() ?
192 manifest_.install_operations(next_operation_num_) : 208 manifest_.install_operations(next_operation_num_) :
193 manifest_.kernel_install_operations( 209 manifest_.kernel_install_operations(
194 next_operation_num_ - manifest_.install_operations_size()); 210 next_operation_num_ - manifest_.install_operations_size());
195 if (!CanPerformInstallOperation(op)) 211 if (!CanPerformInstallOperation(op))
196 break; 212 break;
197 // Log every thousandth operation, and also the first and last ones 213 // Log every thousandth operation, and also the first and last ones
198 if ((next_operation_num_ % 1000 == 0) || 214 if ((next_operation_num_ % 1000 == 0) ||
199 (next_operation_num_ + 1 == total_operations)) { 215 (next_operation_num_ + 1 == total_operations)) {
200 LOG(INFO) << "Performing operation " << (next_operation_num_ + 1) << "/" 216 LOG(INFO) << "Performing operation " << (next_operation_num_ + 1) << "/"
201 << total_operations; 217 << total_operations;
202 } 218 }
203 bool is_kernel_partition = 219 bool is_kernel_partition =
204 (next_operation_num_ >= manifest_.install_operations_size()); 220 (next_operation_num_ >= manifest_.install_operations_size());
221 // If about to start a non-idempotent operation, clear the update state so
222 // that if the operation gets interrupted, we don't try to resume the
223 // update.
224 if (!IsIdempotentOperation(op)) {
225 ResetUpdateProgress();
226 }
205 if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE || 227 if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
206 op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) { 228 op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
207 if (!PerformReplaceOperation(op, is_kernel_partition)) { 229 if (!PerformReplaceOperation(op, is_kernel_partition)) {
208 LOG(ERROR) << "Failed to perform replace operation " 230 LOG(ERROR) << "Failed to perform replace operation "
209 << next_operation_num_; 231 << next_operation_num_;
210 return -EINVAL; 232 return -EINVAL;
211 } 233 }
212 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) { 234 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) {
213 if (!PerformMoveOperation(op, is_kernel_partition)) { 235 if (!PerformMoveOperation(op, is_kernel_partition)) {
214 LOG(ERROR) << "Failed to perform move operation " 236 LOG(ERROR) << "Failed to perform move operation "
215 << next_operation_num_; 237 << next_operation_num_;
216 return -EINVAL; 238 return -EINVAL;
217 } 239 }
218 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) { 240 } else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) {
219 if (!PerformBsdiffOperation(op, is_kernel_partition)) { 241 if (!PerformBsdiffOperation(op, is_kernel_partition)) {
220 LOG(ERROR) << "Failed to perform bsdiff operation " 242 LOG(ERROR) << "Failed to perform bsdiff operation "
221 << next_operation_num_; 243 << next_operation_num_;
222 return -EINVAL; 244 return -EINVAL;
223 } 245 }
224 } 246 }
225 next_operation_num_++; 247 next_operation_num_++;
248 CheckpointUpdateProgress();
226 } 249 }
227 return count; 250 return count;
228 } 251 }
229 252
230 bool DeltaPerformer::CanPerformInstallOperation( 253 bool DeltaPerformer::CanPerformInstallOperation(
231 const chromeos_update_engine::DeltaArchiveManifest_InstallOperation& 254 const chromeos_update_engine::DeltaArchiveManifest_InstallOperation&
232 operation) { 255 operation) {
233 // Move operations don't require any data blob, so they can always 256 // Move operations don't require any data blob, so they can always
234 // be performed 257 // be performed
235 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) 258 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE)
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 return hash_data == signed_hash_data; 505 return hash_data == signed_hash_data;
483 } 506 }
484 507
485 void DeltaPerformer::DiscardBufferHeadBytes(size_t count, bool do_hash) { 508 void DeltaPerformer::DiscardBufferHeadBytes(size_t count, bool do_hash) {
486 if (do_hash) { 509 if (do_hash) {
487 hash_calculator_.Update(&buffer_[0], count); 510 hash_calculator_.Update(&buffer_[0], count);
488 } 511 }
489 buffer_.erase(buffer_.begin(), buffer_.begin() + count); 512 buffer_.erase(buffer_.begin(), buffer_.begin() + count);
490 } 513 }
491 514
515 bool DeltaPerformer::ResetUpdateProgress() {
516 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextOperation,
517 kUpdateStateOperationInvalid));
518 return true;
519 }
520
521 bool DeltaPerformer::CheckpointUpdateProgress() {
522 // First reset the progress in case we die in the middle of the state update.
523 ResetUpdateProgress();
524 TEST_AND_RETURN_FALSE(prefs_->SetString(kPrefsUpdateStateSignedSHA256Context,
525 hash_calculator_.GetContext()));
526 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataOffset,
527 buffer_offset_));
528 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextOperation,
529 next_operation_num_));
530 return true;
531 }
532
492 } // namespace chromeos_update_engine 533 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « delta_performer.h ('k') | delta_performer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698