Merge "delta_generator: Accept a list of partitions in the command line."
diff --git a/Android.mk b/Android.mk
index abbae26..a1edf1c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -45,6 +45,7 @@
LOCAL_LDFLAGS += \
-Wl,--gc-sections
LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/client_library/include \
external/gtest/include \
system
LOCAL_SHARED_LIBRARIES += \
@@ -177,6 +178,7 @@
update_manager/real_updater_provider.cc \
update_manager/state_factory.cc \
update_manager/update_manager.cc \
+ update_status_utils.cc \
utils.cc \
xz_extent_writer.cc
$(eval $(update_engine_common))
@@ -321,6 +323,36 @@
LOCAL_DBUS_PROXY_PREFIX := update_engine
include $(BUILD_STATIC_LIBRARY)
+# libupdate_engine_client
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libupdate_engine_client
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_CFLAGS := \
+ -Wall \
+ -Werror \
+ -Wno-unused-parameter
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/client_library/include \
+ external/cros/system_api/dbus \
+ system \
+ external/gtest/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/client_library/include
+LOCAL_SHARED_LIBRARIES := \
+ libchrome \
+ libchrome-dbus \
+ libchromeos \
+ libchromeos-dbus
+LOCAL_STATIC_LIBRARIES := \
+ update_engine_client-dbus-proxies
+LOCAL_SRC_FILES := \
+ client_library/client.cc \
+ client_library/client_impl.cc \
+ update_status_utils.cc
+include $(BUILD_SHARED_LIBRARY)
+
# Update payload signing public key.
# ========================================================
diff --git a/client_library/client.cc b/client_library/client.cc
new file mode 100644
index 0000000..d6e7382
--- /dev/null
+++ b/client_library/client.cc
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/client_library/include/update_engine/client.h"
+
+#include <memory>
+
+#include "update_engine/client_library/client_impl.h"
+
+using std::unique_ptr;
+
+namespace update_engine {
+
+std::unique_ptr<UpdateEngineClient> UpdateEngineClient::CreateInstance() {
+ return unique_ptr<UpdateEngineClient>{new internal::UpdateEngineClientImpl{}};
+}
+
+} // namespace update_engine
diff --git a/client_library/client_impl.cc b/client_library/client_impl.cc
new file mode 100644
index 0000000..84ca184
--- /dev/null
+++ b/client_library/client_impl.cc
@@ -0,0 +1,91 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/client_library/client_impl.h"
+
+#include <dbus/bus.h>
+#include <update_engine/dbus-constants.h>
+
+#include "update_engine/update_status_utils.h"
+
+using chromeos_update_engine::StringToUpdateStatus;
+using dbus::Bus;
+using org::chromium::UpdateEngineInterfaceProxy;
+using std::string;
+
+namespace update_engine {
+namespace internal {
+
+UpdateEngineClientImpl::UpdateEngineClientImpl() {
+ Bus::Options options;
+ options.bus_type = Bus::SYSTEM;
+ scoped_refptr<Bus> bus{new Bus{options}};
+ proxy_.reset(new UpdateEngineInterfaceProxy{bus});
+}
+
+bool UpdateEngineClientImpl::AttemptUpdate(const string& in_app_version,
+ const string& in_omaha_url,
+ bool at_user_request) {
+ return proxy_->AttemptUpdateWithFlags(
+ in_app_version,
+ in_omaha_url,
+ (at_user_request) ? 0 : kAttemptUpdateFlagNonInteractive,
+ nullptr);
+}
+
+bool UpdateEngineClientImpl::GetStatus(int64_t* out_last_checked_time,
+ double* out_progress,
+ UpdateStatus* out_update_status,
+ string* out_new_version,
+ int64_t* out_new_size) {
+ string status_as_string;
+ const bool success = proxy_->GetStatus(
+ out_last_checked_time,
+ out_progress,
+ &status_as_string,
+ out_new_version,
+ out_new_size,
+ nullptr);
+ if (!success) {
+ return false;
+ }
+
+ return StringToUpdateStatus(status_as_string, out_update_status);
+}
+
+bool UpdateEngineClientImpl::SetTargetChannel(const string& in_target_channel) {
+ return proxy_->SetChannel(
+ in_target_channel,
+ true,
+ nullptr);
+}
+
+bool UpdateEngineClientImpl::GetTargetChannel(string* out_channel) {
+ return proxy_->GetChannel(
+ false, // Get the target channel.
+ out_channel,
+ nullptr);
+}
+
+bool UpdateEngineClientImpl::GetChannel(string* out_channel) {
+ return proxy_->GetChannel(
+ true, // Get the current channel.
+ out_channel,
+ nullptr);
+}
+
+} // namespace internal
+} // namespace update_engine
diff --git a/client_library/client_impl.h b/client_library/client_impl.h
new file mode 100644
index 0000000..a16136c
--- /dev/null
+++ b/client_library/client_impl.h
@@ -0,0 +1,62 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_CLIENT_LIBRARY_CLIENT_IMPL_H_
+#define UPDATE_ENGINE_CLIENT_LIBRARY_CLIENT_IMPL_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+
+#include "update_engine/dbus-proxies.h"
+#include "update_engine/client_library/include/update_engine/client.h"
+
+namespace update_engine {
+namespace internal {
+
+class UpdateEngineClientImpl : public UpdateEngineClient {
+ public:
+ UpdateEngineClientImpl();
+ virtual ~UpdateEngineClientImpl() = default;
+
+ bool AttemptUpdate(const std::string& app_version,
+ const std::string& omaha_url,
+ bool at_user_request) override;
+
+ bool GetStatus(int64_t* out_last_checked_time,
+ double* out_progress,
+ UpdateStatus* out_update_status,
+ std::string* out_new_version,
+ int64_t* out_new_size) override;
+
+ bool SetTargetChannel(const std::string& target_channel) override;
+
+ bool GetTargetChannel(std::string* out_channel) override;
+
+ bool GetChannel(std::string* out_channel) override;
+
+ private:
+ std::unique_ptr<org::chromium::UpdateEngineInterfaceProxy> proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl);
+}; // class UpdateEngineClientImpl
+
+} // namespace internal
+} // namespace update_engine
+
+#endif // UPDATE_ENGINE_CLIENT_LIBRARY_CLIENT_IMPL_H_
diff --git a/client_library/include/update_engine/client.h b/client_library/include/update_engine/client.h
new file mode 100644
index 0000000..ec39253
--- /dev/null
+++ b/client_library/include/update_engine/client.h
@@ -0,0 +1,89 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UDPATE_ENGINE_CLIENT_LIBRARY_INCLUDE_UPDATE_ENGINE_CLIENT_H_
+#define UDPATE_ENGINE_CLIENT_LIBRARY_INCLUDE_UPDATE_ENGINE_CLIENT_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "update_engine/update_status.h"
+
+namespace update_engine {
+
+class UpdateEngineClient {
+ public:
+ static std::unique_ptr<UpdateEngineClient> CreateInstance();
+
+ virtual ~UpdateEngineClient() = default;
+
+ // Force the update_engine to attempt an update.
+ // |app_version|
+ // Attempt to update to this version. An empty string indicates that
+ // update engine should pick the most recent image on the current channel.
+ // |omaha_url|
+ // Force update_engine to look for updates from the given server. Passing
+ // empty indicates update_engine should get this parameter from its
+ // config. Note that update_engine will ignore this parameter in
+ // production mode to avoid pulling untrusted updates.
+ // |at_user_request|
+ // This update was directly requested by the user.
+ virtual bool AttemptUpdate(const std::string& app_version,
+ const std::string& omaha_url,
+ bool at_user_request) = 0;
+
+ // Returns the current status of the Update Engine.
+ //
+ // |out_last_checked_time|
+ // the last time the update engine checked for an update in seconds since
+ // the epoc.
+ // |out_progress|
+ // when downloading an update, this is calculated as
+ // (number of bytes received) / (total bytes).
+ // |out_update_status|
+ // See update_status.h.
+ // |out_new_version|
+ // string version of the new system image.
+ // |out_new_size|
+ // number of bytes in the new system image.
+ virtual bool GetStatus(int64_t* out_last_checked_time,
+ double* out_progress,
+ UpdateStatus* out_update_status,
+ std::string* out_new_version,
+ int64_t* out_new_size) = 0;
+
+ // Changes the current channel of the device to the target channel.
+ virtual bool SetTargetChannel(const std::string& target_channel) = 0;
+
+ // Get the channel the device will switch to on reboot.
+ virtual bool GetTargetChannel(std::string* out_channel) = 0;
+
+ // Get the channel the device is currently on.
+ virtual bool GetChannel(std::string* out_channel) = 0;
+
+ protected:
+ // Use CreateInstance().
+ UpdateEngineClient() = default;
+
+ private:
+ UpdateEngineClient(const UpdateEngineClient&) = delete;
+ void operator=(const UpdateEngineClient&) = delete;
+}; // class UpdateEngineClient
+
+} // namespace update_engine
+
+#endif // UDPATE_ENGINE_CLIENT_LIBRARY_INCLUDE_UPDATE_ENGINE_CLIENT_H_
diff --git a/client_library/include/update_engine/update_status.h b/client_library/include/update_engine/update_status.h
new file mode 100644
index 0000000..525249c
--- /dev/null
+++ b/client_library/include/update_engine/update_status.h
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef CLIENT_LIBRARY_INCLUDE_UPDATE_ENGINE_UPDATE_STATUS_H_
+#define CLIENT_LIBRARY_INCLUDE_UPDATE_ENGINE_UPDATE_STATUS_H_
+
+namespace update_engine {
+
+enum class UpdateStatus {
+ IDLE = 0,
+ CHECKING_FOR_UPDATE,
+ UPDATE_AVAILABLE,
+ DOWNLOADING,
+ VERIFYING,
+ FINALIZING,
+ UPDATED_NEED_REBOOT,
+ REPORTING_ERROR_EVENT,
+ ATTEMPTING_ROLLBACK,
+ DISABLED,
+};
+
+} // namespace update_engine
+
+#endif // CLIENT_LIBRARY_INCLUDE_UPDATE_ENGINE_UPDATE_STATUS_H_
diff --git a/delta_performer.cc b/delta_performer.cc
index c8a00d3..8aff634 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -18,6 +18,7 @@
#include <endian.h>
#include <errno.h>
+#include <linux/fs.h>
#include <algorithm>
#include <cstring>
@@ -56,8 +57,13 @@
namespace chromeos_update_engine {
+const uint64_t DeltaPerformer::kDeltaVersionOffset = sizeof(kDeltaMagic);
const uint64_t DeltaPerformer::kDeltaVersionSize = 8;
+const uint64_t DeltaPerformer::kDeltaManifestSizeOffset =
+ kDeltaVersionOffset + kDeltaVersionSize;
const uint64_t DeltaPerformer::kDeltaManifestSizeSize = 8;
+const uint64_t DeltaPerformer::kDeltaMetadataSignatureSizeSize = 4;
+const uint64_t DeltaPerformer::kMaxPayloadHeaderSize = 24;
const uint64_t DeltaPerformer::kSupportedMajorPayloadVersion = 1;
const uint64_t DeltaPerformer::kSupportedMinorPayloadVersion = 2;
@@ -327,25 +333,39 @@
} // namespace
-uint64_t DeltaPerformer::GetVersionOffset() {
- // Manifest size is stored right after the magic string and the version.
- return strlen(kDeltaMagic);
+bool DeltaPerformer::GetMetadataSignatureSizeOffset(
+ uint64_t* out_offset) const {
+ if (GetMajorVersion() == kBrilloMajorPayloadVersion) {
+ *out_offset = kDeltaManifestSizeOffset + kDeltaManifestSizeSize;
+ return true;
+ }
+ return false;
}
-uint64_t DeltaPerformer::GetManifestSizeOffset() {
- // Manifest size is stored right after the magic string and the version.
- return strlen(kDeltaMagic) + kDeltaVersionSize;
-}
-
-uint64_t DeltaPerformer::GetManifestOffset() {
- // Actual manifest begins right after the manifest size field.
- return GetManifestSizeOffset() + kDeltaManifestSizeSize;
+bool DeltaPerformer::GetManifestOffset(uint64_t* out_offset) const {
+ // Actual manifest begins right after the manifest size field or
+ // metadata signature size field if major version >= 2.
+ if (major_payload_version_ == kChromeOSMajorPayloadVersion) {
+ *out_offset = kDeltaManifestSizeOffset + kDeltaManifestSizeSize;
+ return true;
+ }
+ if (major_payload_version_ == kBrilloMajorPayloadVersion) {
+ *out_offset = kDeltaManifestSizeOffset + kDeltaManifestSizeSize +
+ kDeltaMetadataSignatureSizeSize;
+ return true;
+ }
+ LOG(ERROR) << "Unknown major payload version: " << major_payload_version_;
+ return false;
}
uint64_t DeltaPerformer::GetMetadataSize() const {
return metadata_size_;
}
+uint64_t DeltaPerformer::GetMajorVersion() const {
+ return major_payload_version_;
+}
+
uint32_t DeltaPerformer::GetMinorVersion() const {
if (manifest_.has_minor_version()) {
return manifest_.minor_version();
@@ -363,56 +383,82 @@
return true;
}
+bool DeltaPerformer::IsHeaderParsed() const {
+ return metadata_size_ != 0;
+}
DeltaPerformer::MetadataParseResult DeltaPerformer::ParsePayloadMetadata(
const chromeos::Blob& payload, ErrorCode* error) {
*error = ErrorCode::kSuccess;
- const uint64_t manifest_offset = GetManifestOffset();
- uint64_t manifest_size = (metadata_size_ ?
- metadata_size_ - manifest_offset : 0);
+ uint64_t manifest_offset;
- if (!manifest_size) {
- // Ensure we have data to cover the payload header.
- if (payload.size() < manifest_offset)
+ if (!IsHeaderParsed()) {
+ // Ensure we have data to cover the major payload version.
+ if (payload.size() < kDeltaManifestSizeOffset)
return kMetadataParseInsufficientData;
// Validate the magic string.
- if (memcmp(payload.data(), kDeltaMagic, strlen(kDeltaMagic)) != 0) {
+ if (memcmp(payload.data(), kDeltaMagic, sizeof(kDeltaMagic)) != 0) {
LOG(ERROR) << "Bad payload format -- invalid delta magic.";
*error = ErrorCode::kDownloadInvalidMetadataMagicString;
return kMetadataParseError;
}
// Extract the payload version from the metadata.
- uint64_t major_payload_version;
- COMPILE_ASSERT(sizeof(major_payload_version) == kDeltaVersionSize,
+ COMPILE_ASSERT(sizeof(major_payload_version_) == kDeltaVersionSize,
major_payload_version_size_mismatch);
- memcpy(&major_payload_version,
- &payload[GetVersionOffset()],
+ memcpy(&major_payload_version_,
+ &payload[kDeltaVersionOffset],
kDeltaVersionSize);
// switch big endian to host
- major_payload_version = be64toh(major_payload_version);
+ major_payload_version_ = be64toh(major_payload_version_);
- if (major_payload_version != kSupportedMajorPayloadVersion) {
+ if (major_payload_version_ != supported_major_version_) {
LOG(ERROR) << "Bad payload format -- unsupported payload version: "
- << major_payload_version;
+ << major_payload_version_;
*error = ErrorCode::kUnsupportedMajorPayloadVersion;
return kMetadataParseError;
}
+ // Get the manifest offset now that we have payload version.
+ if (!GetManifestOffset(&manifest_offset)) {
+ *error = ErrorCode::kUnsupportedMajorPayloadVersion;
+ return kMetadataParseError;
+ }
+ // Check again with the manifest offset.
+ if (payload.size() < manifest_offset)
+ return kMetadataParseInsufficientData;
+
// Next, parse the manifest size.
- COMPILE_ASSERT(sizeof(manifest_size) == kDeltaManifestSizeSize,
+ COMPILE_ASSERT(sizeof(manifest_size_) == kDeltaManifestSizeSize,
manifest_size_size_mismatch);
- memcpy(&manifest_size,
- &payload[GetManifestSizeOffset()],
+ memcpy(&manifest_size_,
+ &payload[kDeltaManifestSizeOffset],
kDeltaManifestSizeSize);
- manifest_size = be64toh(manifest_size); // switch big endian to host
+ manifest_size_ = be64toh(manifest_size_); // switch big endian to host
+
+ uint32_t metadata_signature_size = 0;
+ if (GetMajorVersion() == kBrilloMajorPayloadVersion) {
+ // Parse the metadata signature size.
+ COMPILE_ASSERT(sizeof(metadata_signature_size) ==
+ kDeltaMetadataSignatureSizeSize,
+ metadata_signature_size_size_mismatch);
+ uint64_t metadata_signature_size_offset;
+ if (!GetMetadataSignatureSizeOffset(&metadata_signature_size_offset)) {
+ *error = ErrorCode::kError;
+ return kMetadataParseError;
+ }
+ memcpy(&metadata_signature_size,
+ &payload[metadata_signature_size_offset],
+ kDeltaMetadataSignatureSizeSize);
+ metadata_signature_size = be32toh(metadata_signature_size);
+ }
// If the metadata size is present in install plan, check for it immediately
// even before waiting for that many number of bytes to be downloaded in the
// payload. This will prevent any attack which relies on us downloading data
// beyond the expected metadata size.
- metadata_size_ = manifest_offset + manifest_size;
+ metadata_size_ = manifest_offset + manifest_size_ + metadata_signature_size;
if (install_plan_->hash_checks_mandatory) {
if (install_plan_->metadata_size != metadata_size_) {
LOG(ERROR) << "Mandatory metadata size in Omaha response ("
@@ -460,8 +506,12 @@
*error = ErrorCode::kSuccess;
}
+ if (!GetManifestOffset(&manifest_offset)) {
+ *error = ErrorCode::kUnsupportedMajorPayloadVersion;
+ return kMetadataParseError;
+ }
// The payload metadata is deemed valid, it's safe to parse the protobuf.
- if (!manifest_.ParseFromArray(&payload[manifest_offset], manifest_size)) {
+ if (!manifest_.ParseFromArray(&payload[manifest_offset], manifest_size_)) {
LOG(ERROR) << "Unable to parse manifest in update file.";
*error = ErrorCode::kDownloadManifestParseError;
return kMetadataParseError;
@@ -485,11 +535,11 @@
UpdateOverallProgress(false, "Completed ");
while (!manifest_valid_) {
- // Read data up to the needed limit; this is either the payload header size,
- // or the full metadata size (once it becomes known).
- const bool do_read_header = !metadata_size_;
+ // Read data up to the needed limit; this is either maximium payload header
+ // size, or the full metadata size (once it becomes known).
+ const bool do_read_header = !IsHeaderParsed();
CopyDataToBuffer(&c_bytes, &count,
- (do_read_header ? GetManifestOffset() :
+ (do_read_header ? kMaxPayloadHeaderSize :
metadata_size_));
MetadataParseResult result = ParsePayloadMetadata(buffer_, error);
@@ -497,7 +547,7 @@
return false;
if (result == kMetadataParseInsufficientData) {
// If we just processed the header, make an attempt on the manifest.
- if (do_read_header && metadata_size_)
+ if (do_read_header && IsHeaderParsed())
continue;
return true;
@@ -601,6 +651,10 @@
case InstallOperation::REPLACE_XZ:
op_result = PerformReplaceOperation(op, is_kernel_partition);
break;
+ case InstallOperation::ZERO:
+ case InstallOperation::DISCARD:
+ op_result = PerformZeroOrDiscardOperation(op, is_kernel_partition);
+ break;
case InstallOperation::MOVE:
op_result = PerformMoveOperation(op, is_kernel_partition);
break;
@@ -690,6 +744,44 @@
return true;
}
+bool DeltaPerformer::PerformZeroOrDiscardOperation(
+ const InstallOperation& operation,
+ bool is_kernel_partition) {
+ CHECK(operation.type() == InstallOperation::DISCARD ||
+ operation.type() == InstallOperation::ZERO);
+
+ // These operations have no blob.
+ TEST_AND_RETURN_FALSE(!operation.has_data_offset());
+ TEST_AND_RETURN_FALSE(!operation.has_data_length());
+
+ int request =
+ (operation.type() == InstallOperation::ZERO ? BLKZEROOUT : BLKDISCARD);
+
+ FileDescriptorPtr fd = is_kernel_partition ? kernel_fd_ : fd_;
+ bool attempt_ioctl = true;
+ chromeos::Blob zeros;
+ for (int i = 0; i < operation.dst_extents_size(); i++) {
+ Extent extent = operation.dst_extents(i);
+ const uint64_t start = extent.start_block() * block_size_;
+ const uint64_t length = extent.num_blocks() * block_size_;
+ if (attempt_ioctl) {
+ int result = 0;
+ if (fd->BlkIoctl(request, start, length, &result) && result == 0)
+ continue;
+ attempt_ioctl = false;
+ zeros.resize(16 * block_size_);
+ }
+ // In case of failure, we fall back to writing 0 to the selected region.
+ for (uint64_t offset = 0; offset < length; offset += zeros.size()) {
+ uint64_t chunk_length = min(length - offset,
+ static_cast<uint64_t>(zeros.size()));
+ TEST_AND_RETURN_FALSE(
+ utils::PWriteAll(fd, zeros.data(), chunk_length, start + offset));
+ }
+ }
+ return true;
+}
+
bool DeltaPerformer::PerformMoveOperation(const InstallOperation& operation,
bool is_kernel_partition) {
// Calculate buffer size. Note, this function doesn't do a sliding
diff --git a/delta_performer.h b/delta_performer.h
index 087c2ad..34cb137 100644
--- a/delta_performer.h
+++ b/delta_performer.h
@@ -50,8 +50,12 @@
kMetadataParseInsufficientData,
};
+ static const uint64_t kDeltaVersionOffset;
static const uint64_t kDeltaVersionSize;
+ static const uint64_t kDeltaManifestSizeOffset;
static const uint64_t kDeltaManifestSizeSize;
+ static const uint64_t kDeltaMetadataSignatureSizeSize;
+ static const uint64_t kMaxPayloadHeaderSize;
static const uint64_t kSupportedMajorPayloadVersion;
static const uint64_t kSupportedMinorPayloadVersion;
@@ -81,6 +85,8 @@
manifest_parsed_(false),
manifest_valid_(false),
metadata_size_(0),
+ manifest_size_(0),
+ major_payload_version_(0),
next_operation_num_(0),
buffer_offset_(0),
last_updated_buffer_offset_(kuint64max),
@@ -93,6 +99,7 @@
last_progress_chunk_(0),
forced_progress_log_wait_(
base::TimeDelta::FromSeconds(kProgressLogTimeoutSeconds)),
+ supported_major_version_(kSupportedMajorPayloadVersion),
supported_minor_version_(kSupportedMinorPayloadVersion) {}
// Opens the kernel. Should be called before or after Open(), but before
@@ -186,26 +193,30 @@
public_key_path_ = public_key_path;
}
- // Returns the byte offset at which the payload version can be found.
- static uint64_t GetVersionOffset();
+ // Set |*out_offset| to the byte offset where the size of the metadata signature
+ // is stored in a payload. Return true on success, if this field is not
+ // present in the payload, return false.
+ bool GetMetadataSignatureSizeOffset(uint64_t* out_offset) const;
- // Returns the byte offset where the size of the manifest is stored in
- // a payload. This offset precedes the actual start of the manifest
- // that's returned by the GetManifestOffset method.
- static uint64_t GetManifestSizeOffset();
-
- // Returns the byte offset at which the manifest protobuf begins in a
- // payload.
- static uint64_t GetManifestOffset();
+ // Set |*out_offset| to the byte offset at which the manifest protobuf begins
+ // in a payload. Return true on success, false if the offset is unknown.
+ bool GetManifestOffset(uint64_t* out_offset) const;
// Returns the size of the payload metadata, which includes the payload header
- // and the manifest. Is the header was not yet parsed, returns zero.
+ // and the manifest. If the header was not yet parsed, returns zero.
uint64_t GetMetadataSize() const;
// If the manifest was successfully parsed, copies it to |*out_manifest_p|.
// Returns true on success.
bool GetManifest(DeltaArchiveManifest* out_manifest_p) const;
+ // Return true if header parsing is finished and no errors occurred.
+ bool IsHeaderParsed() const;
+
+ // Returns the major payload version. If the version was not yet parsed,
+ // returns zero.
+ uint64_t GetMajorVersion() const;
+
// Returns the delta minor version. If this value is defined in the manifest,
// it returns that value, otherwise it returns the default value.
uint32_t GetMinorVersion() const;
@@ -268,6 +279,8 @@
// These perform a specific type of operation and return true on success.
bool PerformReplaceOperation(const InstallOperation& operation,
bool is_kernel_partition);
+ bool PerformZeroOrDiscardOperation(const InstallOperation& operation,
+ bool is_kernel_partition);
bool PerformMoveOperation(const InstallOperation& operation,
bool is_kernel_partition);
bool PerformBsdiffOperation(const InstallOperation& operation,
@@ -331,6 +344,8 @@
bool manifest_parsed_;
bool manifest_valid_;
uint64_t metadata_size_;
+ uint64_t manifest_size_;
+ uint64_t major_payload_version_;
// Index of the next operation to perform in the manifest.
size_t next_operation_num_;
@@ -380,6 +395,9 @@
const base::TimeDelta forced_progress_log_wait_;
base::Time forced_progress_log_time_;
+ // The payload major payload version supported by DeltaPerformer.
+ uint64_t supported_major_version_;
+
// The delta minor payload version supported by DeltaPerformer.
uint32_t supported_minor_version_;
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index 839f253..12dd1d3 100644
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -138,14 +138,29 @@
// Apply |payload_data| on partition specified in |source_path|.
chromeos::Blob ApplyPayload(const chromeos::Blob& payload_data,
const string& source_path) {
- install_plan_.source_path = source_path;
- install_plan_.kernel_source_path = "/dev/null";
+ return ApplyPayloadToData(payload_data, source_path, chromeos::Blob());
+ }
+ // Apply the payload provided in |payload_data| reading from the |source_path|
+ // file and writing the contents to a new partition. The existing data in the
+ // new target file are set to |target_data| before applying the payload.
+ // Returns the result of the payload application.
+ chromeos::Blob ApplyPayloadToData(const chromeos::Blob& payload_data,
+ const string& source_path,
+ const chromeos::Blob& target_data) {
string new_part;
EXPECT_TRUE(utils::MakeTempFile("Partition-XXXXXX", &new_part, nullptr));
ScopedPathUnlinker partition_unlinker(new_part);
+ EXPECT_TRUE(utils::WriteFile(new_part.c_str(), target_data.data(),
+ target_data.size()));
+
+ install_plan_.source_path = source_path;
+ install_plan_.kernel_source_path = "/dev/null";
+ install_plan_.install_path = new_part;
+ install_plan_.kernel_install_path = "/dev/null";
EXPECT_EQ(0, performer_.Open(new_part.c_str(), 0, 0));
+ EXPECT_TRUE(performer_.OpenSourceRootfs(source_path.c_str()));
EXPECT_TRUE(performer_.Write(payload_data.data(), payload_data.size()));
EXPECT_EQ(0, performer_.Close());
@@ -260,6 +275,9 @@
EXPECT_EQ(install_plan_.metadata_size, performer_.GetMetadataSize());
}
+ void SetSupportedMajorVersion(uint64_t major_version) {
+ performer_.supported_major_version_ = major_version;
+ }
FakePrefs prefs_;
InstallPlan install_plan_;
FakeSystemState fake_system_state_;
@@ -282,7 +300,7 @@
chromeos::Blob payload_data = GeneratePayload(expected_data, aops, false,
kFullPayloadMinorVersion);
- EXPECT_EQ(expected_data, ApplyPayload(payload_data, ""));
+ EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null"));
}
TEST_F(DeltaPerformerTest, ReplaceOperationTest) {
@@ -345,6 +363,29 @@
EXPECT_EQ(expected_data, ApplyPayload(payload_data, "/dev/null"));
}
+TEST_F(DeltaPerformerTest, ZeroOperationTest) {
+ chromeos::Blob existing_data = chromeos::Blob(4096 * 10, 'a');
+ chromeos::Blob expected_data = existing_data;
+ // Blocks 4, 5 and 7 should have zeros instead of 'a' after the operation is
+ // applied.
+ std::fill(expected_data.data() + 4096 * 4, expected_data.data() + 4096 * 6,
+ 0);
+ std::fill(expected_data.data() + 4096 * 7, expected_data.data() + 4096 * 8,
+ 0);
+
+ AnnotatedOperation aop;
+ *(aop.op.add_dst_extents()) = ExtentForRange(4, 2);
+ *(aop.op.add_dst_extents()) = ExtentForRange(7, 1);
+ aop.op.set_type(InstallOperation::ZERO);
+ vector<AnnotatedOperation> aops = {aop};
+
+ chromeos::Blob payload_data = GeneratePayload(chromeos::Blob(), aops, false,
+ kSourceMinorPayloadVersion);
+
+ EXPECT_EQ(expected_data,
+ ApplyPayloadToData(payload_data, "/dev/null", existing_data));
+}
+
TEST_F(DeltaPerformerTest, SourceCopyOperationTest) {
chromeos::Blob expected_data = chromeos::Blob(std::begin(kRandomString),
std::end(kRandomString));
@@ -460,11 +501,38 @@
ErrorCode::kUnsupportedMinorPayloadVersion);
}
+TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeTest) {
+ SetSupportedMajorVersion(kBrilloMajorPayloadVersion);
+ EXPECT_EQ(0, performer_.Open("/dev/null", 0, 0));
+ EXPECT_TRUE(performer_.OpenKernel("/dev/null"));
+ EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
+
+ uint64_t major_version = htobe64(kBrilloMajorPayloadVersion);
+ EXPECT_TRUE(performer_.Write(&major_version, 8));
+
+ uint64_t manifest_size = rand() % 256;
+ uint64_t manifest_size_be = htobe64(manifest_size);
+ EXPECT_TRUE(performer_.Write(&manifest_size_be, 8));
+
+ uint32_t metadata_signature_size = rand() % 256;
+ uint32_t metadata_signature_size_be = htobe32(metadata_signature_size);
+ EXPECT_TRUE(performer_.Write(&metadata_signature_size_be, 4));
+
+ EXPECT_LT(performer_.Close(), 0);
+
+ EXPECT_TRUE(performer_.IsHeaderParsed());
+ EXPECT_EQ(kBrilloMajorPayloadVersion, performer_.GetMajorVersion());
+ uint64_t manifest_offset;
+ EXPECT_TRUE(performer_.GetManifestOffset(&manifest_offset));
+ EXPECT_EQ(24, manifest_offset); // 4 + 8 + 8 + 4
+ EXPECT_EQ(24 + manifest_size + metadata_signature_size,
+ performer_.GetMetadataSize());
+}
+
TEST_F(DeltaPerformerTest, BadDeltaMagicTest) {
EXPECT_EQ(0, performer_.Open("/dev/null", 0, 0));
EXPECT_TRUE(performer_.OpenKernel("/dev/null"));
EXPECT_TRUE(performer_.Write("junk", 4));
- EXPECT_TRUE(performer_.Write("morejunk", 8));
EXPECT_FALSE(performer_.Write("morejunk", 8));
EXPECT_LT(performer_.Close(), 0);
}
@@ -476,10 +544,9 @@
EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
DownloadProgress(4)).Times(1);
EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
- DownloadProgress(8)).Times(2);
+ DownloadProgress(8)).Times(1);
EXPECT_TRUE(performer_.Write("junk", 4));
- EXPECT_TRUE(performer_.Write("morejunk", 8));
EXPECT_FALSE(performer_.Write("morejunk", 8));
EXPECT_LT(performer_.Close(), 0);
}
diff --git a/download_action.cc b/download_action.cc
index b913c97..a31c8a3 100644
--- a/download_action.cc
+++ b/download_action.cc
@@ -25,6 +25,7 @@
#include <base/strings/stringprintf.h>
#include "update_engine/action_pipe.h"
+#include "update_engine/boot_control_interface.h"
#include "update_engine/omaha_request_params.h"
#include "update_engine/p2p_manager.h"
#include "update_engine/payload_state_interface.h"
@@ -168,6 +169,14 @@
install_plan_.Dump();
+ LOG(INFO) << "Marking new slot as unbootable";
+ if (!system_state_->boot_control()->MarkSlotUnbootable(
+ install_plan_.target_slot)) {
+ LOG(WARNING) << "Unable to mark new slot "
+ << BootControlInterface::SlotName(install_plan_.target_slot)
+ << ". Proceeding with the update anyway.";
+ }
+
if (writer_) {
LOG(INFO) << "Using writer for test.";
} else {
diff --git a/download_action_unittest.cc b/download_action_unittest.cc
index 486f2c5..d1f4bc9 100644
--- a/download_action_unittest.cc
+++ b/download_action_unittest.cc
@@ -134,6 +134,7 @@
bool use_download_delegate) {
chromeos::FakeMessageLoop loop(nullptr);
loop.SetAsCurrent();
+ FakeSystemState fake_system_state;
// TODO(adlr): see if we need a different file for build bots
ScopedTempFile output_temp_file;
@@ -157,6 +158,14 @@
"",
"",
"");
+ install_plan.source_slot = 0;
+ install_plan.target_slot = 1;
+ // We mark both slots as bootable. Only the target slot should be unbootable
+ // after the download starts.
+ fake_system_state.fake_boot_control()->SetSlotBootable(
+ install_plan.source_slot, true);
+ fake_system_state.fake_boot_control()->SetSlotBootable(
+ install_plan.target_slot, true);
ObjectFeederAction<InstallPlan> feeder_action;
feeder_action.set_obj(install_plan);
MockPrefs prefs;
@@ -164,7 +173,7 @@
data.size(),
nullptr);
// takes ownership of passed in HttpFetcher
- DownloadAction download_action(&prefs, nullptr, http_fetcher);
+ DownloadAction download_action(&prefs, &fake_system_state, http_fetcher);
download_action.SetTestFileWriter(&writer);
BondActions(&feeder_action, &download_action);
DownloadActionDelegateMock download_delegate;
@@ -193,6 +202,11 @@
base::Bind(&StartProcessorInRunLoop, &processor, http_fetcher));
loop.Run();
EXPECT_FALSE(loop.PendingTasks());
+
+ EXPECT_TRUE(fake_system_state.fake_boot_control()->IsSlotBootable(
+ install_plan.source_slot));
+ EXPECT_FALSE(fake_system_state.fake_boot_control()->IsSlotBootable(
+ install_plan.target_slot));
}
} // namespace
@@ -269,8 +283,9 @@
InstallPlan install_plan(false, false, "", 0, "", 0, "",
temp_file.GetPath(), "", "", "", "");
feeder_action.set_obj(install_plan);
+ FakeSystemState fake_system_state_;
MockPrefs prefs;
- DownloadAction download_action(&prefs, nullptr,
+ DownloadAction download_action(&prefs, &fake_system_state_,
new MockHttpFetcher(data.data(),
data.size(),
nullptr));
@@ -377,7 +392,8 @@
ObjectFeederAction<InstallPlan> feeder_action;
feeder_action.set_obj(install_plan);
MockPrefs prefs;
- DownloadAction download_action(&prefs, nullptr,
+ FakeSystemState fake_system_state_;
+ DownloadAction download_action(&prefs, &fake_system_state_,
new MockHttpFetcher("x", 1, nullptr));
download_action.SetTestFileWriter(&writer);
@@ -414,7 +430,8 @@
ObjectFeederAction<InstallPlan> feeder_action;
feeder_action.set_obj(install_plan);
MockPrefs prefs;
- DownloadAction download_action(&prefs, nullptr,
+ FakeSystemState fake_system_state_;
+ DownloadAction download_action(&prefs, &fake_system_state_,
new MockHttpFetcher("x", 1, nullptr));
download_action.SetTestFileWriter(&writer);
diff --git a/file_descriptor.cc b/file_descriptor.cc
index 8b8fa72..4718528 100644
--- a/file_descriptor.cc
+++ b/file_descriptor.cc
@@ -17,6 +17,8 @@
#include "update_engine/file_descriptor.h"
#include <fcntl.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -63,6 +65,42 @@
return lseek64(fd_, offset, whence);
}
+bool EintrSafeFileDescriptor::BlkIoctl(int request,
+ uint64_t start,
+ uint64_t length,
+ int* result) {
+ DCHECK(request == BLKDISCARD || request == BLKZEROOUT ||
+ request == BLKSECDISCARD);
+ // On some devices, the BLKDISCARD will actually read back as zeros, instead
+ // of "undefined" data. The BLKDISCARDZEROES ioctl tells whether that's the
+ // case, so we issue a BLKDISCARD in those cases to speed up the writes.
+ unsigned int arg;
+ if (request == BLKZEROOUT && ioctl(fd_, BLKDISCARDZEROES, &arg) == 0 && arg)
+ request = BLKDISCARD;
+
+ // Ensure the |fd_| is in O_DIRECT mode during this operation, so the write
+ // cache for this region is invalidated. This is required since otherwise
+ // reading back this region could consume stale data from the cache.
+ int flags = fcntl(fd_, F_GETFL, 0);
+ if (flags == -1) {
+ PLOG(WARNING) << "Couldn't get flags on fd " << fd_;
+ return false;
+ }
+ if ((flags & O_DIRECT) == 0 && fcntl(fd_, F_SETFL, flags | O_DIRECT) == -1) {
+ PLOG(WARNING) << "Couldn't set O_DIRECT on fd " << fd_;
+ return false;
+ }
+
+ uint64_t range[2] = {start, length};
+ *result = ioctl(fd_, request, range);
+
+ if ((flags & O_DIRECT) == 0 && fcntl(fd_, F_SETFL, flags) == -1) {
+ PLOG(WARNING) << "Couldn't remove O_DIRECT on fd " << fd_;
+ return false;
+ }
+ return true;
+}
+
bool EintrSafeFileDescriptor::Close() {
CHECK_GE(fd_, 0);
if (IGNORE_EINTR(close(fd_)))
diff --git a/file_descriptor.h b/file_descriptor.h
index 4d6e970..bf13611 100644
--- a/file_descriptor.h
+++ b/file_descriptor.h
@@ -78,6 +78,17 @@
// may set errno accordingly.
virtual off64_t Seek(off64_t offset, int whence) = 0;
+ // Runs a ioctl() on the file descriptor if supported. Returns whether
+ // the operation is supported. The |request| can be one of BLKDISCARD,
+ // BLKZEROOUT and BLKSECDISCARD to discard, write zeros or securely discard
+ // the blocks. These ioctls accept a range of bytes (|start| and |length|)
+ // over which they perform the operation. The return value from the ioctl is
+ // stored in |result|.
+ virtual bool BlkIoctl(int request,
+ uint64_t start,
+ uint64_t length,
+ int* result) = 0;
+
// Closes a file descriptor. The descriptor must be open prior to this call.
// Returns true on success, false otherwise. Specific implementations may set
// errno accordingly.
@@ -108,6 +119,10 @@
ssize_t Read(void* buf, size_t count) override;
ssize_t Write(const void* buf, size_t count) override;
off64_t Seek(off64_t offset, int whence) override;
+ bool BlkIoctl(int request,
+ uint64_t start,
+ uint64_t length,
+ int* result) override;
bool Close() override;
void Reset() override;
bool IsSettingErrno() override {
diff --git a/filesystem_verifier_action.cc b/filesystem_verifier_action.cc
index d28526f..2291bc9 100644
--- a/filesystem_verifier_action.cc
+++ b/filesystem_verifier_action.cc
@@ -73,16 +73,6 @@
}
install_plan_ = GetInputObject();
- // TODO(deymo): Remove this from the FileSystemVerifierAction.
- if (partition_type_ == PartitionType::kKernel) {
- LOG(INFO) << "verifying kernel, marking as unbootable";
- if (!system_state_->boot_control()->MarkSlotUnbootable(
- install_plan_.target_slot)) {
- PLOG(ERROR) << "Unable to clear kernel GPT boot flags: " <<
- install_plan_.kernel_install_path;
- }
- }
-
if (install_plan_.is_full_update &&
(partition_type_ == PartitionType::kSourceRootfs ||
partition_type_ == PartitionType::kSourceKernel)) {
diff --git a/filesystem_verifier_action_unittest.cc b/filesystem_verifier_action_unittest.cc
index 32f3c59..8280328 100644
--- a/filesystem_verifier_action_unittest.cc
+++ b/filesystem_verifier_action_unittest.cc
@@ -204,9 +204,6 @@
break;
}
- fake_system_state_.fake_boot_control()->SetSlotBootable(
- install_plan.target_slot, true);
-
ActionProcessor processor;
ObjectFeederAction<InstallPlan> feeder_action;
@@ -263,14 +260,6 @@
bool is_install_plan_eq = (collector_action.object() == install_plan);
EXPECT_TRUE(is_install_plan_eq);
success = success && is_install_plan_eq;
-
- LOG(INFO) << "Verifying bootable flag on: " << a_dev;
-
- // We should always mark a partition as unbootable if it's a kernel
- // partition, but never if it's anything else.
- EXPECT_EQ((partition_type != PartitionType::kKernel),
- fake_system_state_.fake_boot_control()->IsSlotBootable(
- install_plan.target_slot));
return success;
}
diff --git a/mtd_file_descriptor.h b/mtd_file_descriptor.h
index 1d023c4..954e5e5 100644
--- a/mtd_file_descriptor.h
+++ b/mtd_file_descriptor.h
@@ -40,6 +40,12 @@
ssize_t Read(void* buf, size_t count) override;
ssize_t Write(const void* buf, size_t count) override;
off64_t Seek(off64_t offset, int whence) override;
+ bool BlkIoctl(int request,
+ uint64_t start,
+ uint64_t length,
+ int* result) override {
+ return false;
+ }
bool Close() override;
private:
@@ -69,6 +75,12 @@
ssize_t Read(void* buf, size_t count) override;
ssize_t Write(const void* buf, size_t count) override;
off64_t Seek(off64_t offset, int whence) override;
+ bool BlkIoctl(int request,
+ uint64_t start,
+ uint64_t length,
+ int* result) override {
+ return false;
+ }
bool Close() override;
private:
diff --git a/payload_constants.cc b/payload_constants.cc
index b28461b..cc18430 100644
--- a/payload_constants.cc
+++ b/payload_constants.cc
@@ -28,7 +28,7 @@
const char kLegacyPartitionNameKernel[] = "boot";
const char kLegacyPartitionNameRoot[] = "system";
-const char kDeltaMagic[] = "CrAU";
+const char kDeltaMagic[4] = {'C', 'r', 'A', 'U'};
const char kBspatchPath[] = "bspatch";
const char* InstallOperationTypeName(InstallOperation_Type op_type) {
diff --git a/payload_constants.h b/payload_constants.h
index 81bc36a..38cc075 100644
--- a/payload_constants.h
+++ b/payload_constants.h
@@ -48,7 +48,7 @@
extern const char kLegacyPartitionNameRoot[];
extern const char kBspatchPath[];
-extern const char kDeltaMagic[];
+extern const char kDeltaMagic[4];
// A block number denoting a hole on a sparse file. Used on Extents to refer to
// section of blocks not present on disk on a sparse file.
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index f0a66cc..cdcc967 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -191,7 +191,7 @@
ScopedFileWriterCloser writer_closer(&writer);
// Write header
- TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, strlen(kDeltaMagic)));
+ TEST_AND_RETURN_FALSE(writer.Write(kDeltaMagic, sizeof(kDeltaMagic)));
// Write major version number
TEST_AND_RETURN_FALSE(WriteUint64AsBigEndian(&writer, major_version_));
@@ -241,7 +241,7 @@
}
*medatata_size_out =
- strlen(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size();
+ sizeof(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size();
ReportPayloadUsage(*medatata_size_out);
return true;
}
diff --git a/update_attempter.cc b/update_attempter.cc
index d4e1654..433d112 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -64,6 +64,7 @@
#include "update_engine/system_state.h"
#include "update_engine/update_manager/policy.h"
#include "update_engine/update_manager/update_manager.h"
+#include "update_engine/update_status_utils.h"
#include "update_engine/utils.h"
using base::Bind;
@@ -98,33 +99,6 @@
const char kScheduledAUTestURLRequest[] = "autest-scheduled";
} // namespace
-const char* UpdateStatusToString(UpdateStatus status) {
- switch (status) {
- case UPDATE_STATUS_IDLE:
- return update_engine::kUpdateStatusIdle;
- case UPDATE_STATUS_CHECKING_FOR_UPDATE:
- return update_engine::kUpdateStatusCheckingForUpdate;
- case UPDATE_STATUS_UPDATE_AVAILABLE:
- return update_engine::kUpdateStatusUpdateAvailable;
- case UPDATE_STATUS_DOWNLOADING:
- return update_engine::kUpdateStatusDownloading;
- case UPDATE_STATUS_VERIFYING:
- return update_engine::kUpdateStatusVerifying;
- case UPDATE_STATUS_FINALIZING:
- return update_engine::kUpdateStatusFinalizing;
- case UPDATE_STATUS_UPDATED_NEED_REBOOT:
- return update_engine::kUpdateStatusUpdatedNeedReboot;
- case UPDATE_STATUS_REPORTING_ERROR_EVENT:
- return update_engine::kUpdateStatusReportingErrorEvent;
- case UPDATE_STATUS_ATTEMPTING_ROLLBACK:
- return update_engine::kUpdateStatusAttemptingRollback;
- case UPDATE_STATUS_DISABLED:
- return update_engine::kUpdateStatusDisabled;
- default:
- return "unknown status";
- }
-}
-
// Turns a generic ErrorCode::kError to a generic error code specific
// to |action| (e.g., ErrorCode::kFilesystemVerifierError). If |code| is
// not ErrorCode::kError, or the action is not matched, returns |code|
@@ -166,9 +140,9 @@
debugd_proxy_(debugd_proxy) {
if (!update_completed_marker_.empty() &&
utils::FileExists(update_completed_marker_.c_str())) {
- status_ = UPDATE_STATUS_UPDATED_NEED_REBOOT;
+ status_ = UpdateStatus::UPDATED_NEED_REBOOT;
} else {
- status_ = UPDATE_STATUS_IDLE;
+ status_ = UpdateStatus::IDLE;
}
}
@@ -278,7 +252,7 @@
chrome_proxy_resolver_.Init();
fake_update_success_ = false;
- if (status_ == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
+ if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
// Although we have applied an update, we still want to ping Omaha
// to ensure the number of active statistics is accurate.
//
@@ -293,7 +267,7 @@
PingOmaha();
return;
}
- if (status_ != UPDATE_STATUS_IDLE) {
+ if (status_ != UpdateStatus::IDLE) {
// Update in progress. Do nothing
return;
}
@@ -309,7 +283,7 @@
BuildUpdateActions(interactive);
- SetStatusAndNotify(UPDATE_STATUS_CHECKING_FOR_UPDATE);
+ SetStatusAndNotify(UpdateStatus::CHECKING_FOR_UPDATE);
// Update the last check time here; it may be re-updated when an Omaha
// response is received, but this will prevent us from repeatedly scheduling
@@ -751,7 +725,7 @@
// Update the payload state for Rollback.
system_state_->payload_state()->Rollback();
- SetStatusAndNotify(UPDATE_STATUS_ATTEMPTING_ROLLBACK);
+ SetStatusAndNotify(UpdateStatus::ATTEMPTING_ROLLBACK);
// Just in case we didn't update boot flags yet, make sure they're updated
// before any update processing starts. This also schedules the start of the
@@ -764,7 +738,7 @@
bool UpdateAttempter::CanRollback() const {
// We can only rollback if the update_engine isn't busy and we have a valid
// rollback partition.
- return (status_ == UPDATE_STATUS_IDLE &&
+ return (status_ == UpdateStatus::IDLE &&
GetRollbackSlot() != BootControlInterface::kInvalidSlot);
}
@@ -829,7 +803,7 @@
}
bool UpdateAttempter::RebootIfNeeded() {
- if (status_ != UPDATE_STATUS_UPDATED_NEED_REBOOT) {
+ if (status_ != UpdateStatus::UPDATED_NEED_REBOOT) {
LOG(INFO) << "Reboot requested, but status is "
<< UpdateStatusToString(status_) << ", so not rebooting.";
return false;
@@ -890,8 +864,8 @@
// actually notice one on subsequent calls. Note that we don't need to
// re-schedule a check in this case as updates are permanently disabled;
// further (forced) checks may still initiate a scheduling call.
- SetStatusAndNotify(UPDATE_STATUS_DISABLED);
- SetStatusAndNotify(UPDATE_STATUS_IDLE);
+ SetStatusAndNotify(UpdateStatus::DISABLED);
+ SetStatusAndNotify(UpdateStatus::IDLE);
return;
}
@@ -937,11 +911,11 @@
// Reset cpu shares back to normal.
CleanupCpuSharesManagement();
- if (status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
+ if (status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
LOG(INFO) << "Error event sent.";
// Inform scheduler of new status;
- SetStatusAndNotify(UPDATE_STATUS_IDLE);
+ SetStatusAndNotify(UpdateStatus::IDLE);
ScheduleUpdates();
if (!fake_update_success_) {
@@ -973,7 +947,7 @@
system_state_->payload_state()->SetScatteringWaitPeriod(TimeDelta());
prefs_->Delete(kPrefsUpdateFirstSeenAt);
- SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
+ SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
ScheduleUpdates();
LOG(INFO) << "Update successfully applied, waiting to reboot.";
@@ -1006,7 +980,7 @@
return;
}
LOG(INFO) << "No update.";
- SetStatusAndNotify(UPDATE_STATUS_IDLE);
+ SetStatusAndNotify(UpdateStatus::IDLE);
ScheduleUpdates();
}
@@ -1014,7 +988,7 @@
// Reset cpu shares back to normal.
CleanupCpuSharesManagement();
download_progress_ = 0.0;
- SetStatusAndNotify(UPDATE_STATUS_IDLE);
+ SetStatusAndNotify(UpdateStatus::IDLE);
ScheduleUpdates();
actions_.clear();
error_event_.reset(nullptr);
@@ -1058,7 +1032,7 @@
// If the current state is at or past the download phase, count the failure
// in case a switch to full update becomes necessary. Ignore network
// transfer timeouts and failures.
- if (status_ >= UPDATE_STATUS_DOWNLOADING &&
+ if (status_ >= UpdateStatus::DOWNLOADING &&
code != ErrorCode::kDownloadTransferError) {
MarkDeltaUpdateFailure();
}
@@ -1079,9 +1053,9 @@
new_payload_size_ = plan.payload_size;
SetupDownload();
SetupCpuSharesManagement();
- SetStatusAndNotify(UPDATE_STATUS_UPDATE_AVAILABLE);
+ SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
} else if (type == DownloadAction::StaticType()) {
- SetStatusAndNotify(UPDATE_STATUS_FINALIZING);
+ SetStatusAndNotify(UpdateStatus::FINALIZING);
}
}
@@ -1100,32 +1074,32 @@
// Self throttle based on progress. Also send notifications if
// progress is too slow.
const double kDeltaPercent = 0.01; // 1%
- if (status_ != UPDATE_STATUS_DOWNLOADING ||
+ if (status_ != UpdateStatus::DOWNLOADING ||
bytes_received == total ||
progress - download_progress_ >= kDeltaPercent ||
TimeTicks::Now() - last_notify_time_ >= TimeDelta::FromSeconds(10)) {
download_progress_ = progress;
- SetStatusAndNotify(UPDATE_STATUS_DOWNLOADING);
+ SetStatusAndNotify(UpdateStatus::DOWNLOADING);
}
}
bool UpdateAttempter::ResetStatus() {
LOG(INFO) << "Attempting to reset state from "
- << UpdateStatusToString(status_) << " to UPDATE_STATUS_IDLE";
+ << UpdateStatusToString(status_) << " to UpdateStatus::IDLE";
switch (status_) {
- case UPDATE_STATUS_IDLE:
+ case UpdateStatus::IDLE:
// no-op.
return true;
- case UPDATE_STATUS_UPDATED_NEED_REBOOT: {
+ case UpdateStatus::UPDATED_NEED_REBOOT: {
bool ret_value = true;
- status_ = UPDATE_STATUS_IDLE;
+ status_ = UpdateStatus::IDLE;
LOG(INFO) << "Reset Successful";
// Remove the reboot marker so that if the machine is rebooted
// after resetting to idle state, it doesn't go back to
- // UPDATE_STATUS_UPDATED_NEED_REBOOT state.
+ // UpdateStatus::UPDATED_NEED_REBOOT state.
if (!update_completed_marker_.empty()) {
if (!base::DeleteFile(base::FilePath(update_completed_marker_), false))
ret_value = false;
@@ -1261,7 +1235,7 @@
// don't schedule another. This shouldn't really happen but just in case...
if ((action->Type() == OmahaResponseHandlerAction::StaticType() &&
code == ErrorCode::kError) ||
- status_ == UPDATE_STATUS_REPORTING_ERROR_EVENT) {
+ status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
return;
}
@@ -1310,7 +1284,7 @@
false));
actions_.push_back(shared_ptr<AbstractAction>(error_event_action));
processor_->EnqueueAction(error_event_action.get());
- SetStatusAndNotify(UPDATE_STATUS_REPORTING_ERROR_EVENT);
+ SetStatusAndNotify(UpdateStatus::REPORTING_ERROR_EVENT);
processor_->StartProcessing();
return true;
}
@@ -1439,7 +1413,7 @@
UpdateLastCheckedTime();
// Update the status which will schedule the next update check
- SetStatusAndNotify(UPDATE_STATUS_UPDATED_NEED_REBOOT);
+ SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
ScheduleUpdates();
}
@@ -1574,8 +1548,8 @@
}
bool UpdateAttempter::IsUpdateRunningOrScheduled() {
- return ((status_ != UPDATE_STATUS_IDLE &&
- status_ != UPDATE_STATUS_UPDATED_NEED_REBOOT) ||
+ return ((status_ != UpdateStatus::IDLE &&
+ status_ != UpdateStatus::UPDATED_NEED_REBOOT) ||
waiting_for_scheduled_check_);
}
diff --git a/update_attempter.h b/update_attempter.h
index 06a3dac..a106a2e 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -39,6 +39,7 @@
#include "update_engine/system_state.h"
#include "update_engine/update_manager/policy.h"
#include "update_engine/update_manager/update_manager.h"
+#include "update_engine/update_status.h"
class MetricsLibraryInterface;
@@ -50,24 +51,10 @@
class UpdateEngineAdaptor;
-enum UpdateStatus {
- UPDATE_STATUS_IDLE = 0,
- UPDATE_STATUS_CHECKING_FOR_UPDATE,
- UPDATE_STATUS_UPDATE_AVAILABLE,
- UPDATE_STATUS_DOWNLOADING,
- UPDATE_STATUS_VERIFYING,
- UPDATE_STATUS_FINALIZING,
- UPDATE_STATUS_UPDATED_NEED_REBOOT,
- UPDATE_STATUS_REPORTING_ERROR_EVENT,
- UPDATE_STATUS_ATTEMPTING_ROLLBACK,
- UPDATE_STATUS_DISABLED,
-};
-
-const char* UpdateStatusToString(UpdateStatus status);
-
class UpdateAttempter : public ActionProcessorDelegate,
public DownloadActionDelegate {
public:
+ using UpdateStatus = update_engine::UpdateStatus;
static const int kMaxDeltaUpdateFailures;
UpdateAttempter(SystemState* system_state,
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 749ad3b..51e7920 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -71,6 +71,7 @@
using testing::SaveArg;
using testing::SetArgumentPointee;
using testing::_;
+using update_engine::UpdateStatus;
namespace chromeos_update_engine {
@@ -137,7 +138,7 @@
EXPECT_EQ(utils::kCpuSharesNormal, attempter_.shares_);
EXPECT_EQ(MessageLoop::kTaskIdNull, attempter_.manage_shares_id_);
EXPECT_FALSE(attempter_.download_active_);
- EXPECT_EQ(UPDATE_STATUS_IDLE, attempter_.status_);
+ EXPECT_EQ(UpdateStatus::IDLE, attempter_.status_);
EXPECT_EQ(0.0, attempter_.download_progress_);
EXPECT_EQ(0, attempter_.last_checked_time_);
EXPECT_EQ("0.0.0.0", attempter_.new_version_);
@@ -227,14 +228,14 @@
EXPECT_CALL(*prefs_, GetInt64(kPrefsDeltaUpdateFailures, _)).Times(0);
attempter_.ActionCompleted(nullptr, &action, ErrorCode::kSuccess);
EXPECT_EQ(503, attempter_.http_response_code());
- EXPECT_EQ(UPDATE_STATUS_FINALIZING, attempter_.status());
+ EXPECT_EQ(UpdateStatus::FINALIZING, attempter_.status());
ASSERT_EQ(nullptr, attempter_.error_event_.get());
}
TEST_F(UpdateAttempterTest, ActionCompletedErrorTest) {
MockAction action;
EXPECT_CALL(action, Type()).WillRepeatedly(Return("MockAction"));
- attempter_.status_ = UPDATE_STATUS_DOWNLOADING;
+ attempter_.status_ = UpdateStatus::DOWNLOADING;
EXPECT_CALL(*prefs_, GetInt64(kPrefsDeltaUpdateFailures, _))
.WillOnce(Return(false));
attempter_.ActionCompleted(nullptr, &action, ErrorCode::kError);
@@ -254,7 +255,7 @@
EXPECT_CALL(*prefs_, GetInt64(kPrefsDeltaUpdateFailures, _)).Times(0);
attempter_.ActionCompleted(nullptr, &action, ErrorCode::kSuccess);
EXPECT_EQ(500, attempter_.http_response_code());
- EXPECT_EQ(UPDATE_STATUS_IDLE, attempter_.status());
+ EXPECT_EQ(UpdateStatus::IDLE, attempter_.status());
EXPECT_EQ(234, attempter_.server_dictated_poll_interval_);
ASSERT_TRUE(attempter_.error_event_.get() == nullptr);
}
@@ -272,7 +273,7 @@
nullptr,
&debugd_proxy_mock_,
test_update_completed_marker);
- EXPECT_EQ(UPDATE_STATUS_UPDATED_NEED_REBOOT, attempter.status());
+ EXPECT_EQ(UpdateStatus::UPDATED_NEED_REBOOT, attempter.status());
}
TEST_F(UpdateAttempterTest, GetErrorCodeForActionTest) {
@@ -373,7 +374,7 @@
OmahaEvent::kResultError,
err));
attempter_.ScheduleErrorEventAction();
- EXPECT_EQ(UPDATE_STATUS_REPORTING_ERROR_EVENT, attempter_.status());
+ EXPECT_EQ(UpdateStatus::REPORTING_ERROR_EVENT, attempter_.status());
}
namespace {
@@ -439,7 +440,7 @@
dynamic_cast<DownloadAction*>(attempter_.actions_[5].get());
ASSERT_NE(nullptr, download_action);
EXPECT_EQ(&attempter_, download_action->delegate());
- EXPECT_EQ(UPDATE_STATUS_CHECKING_FOR_UPDATE, attempter_.status());
+ EXPECT_EQ(UpdateStatus::CHECKING_FOR_UPDATE, attempter_.status());
loop_.BreakLoop();
}
@@ -515,7 +516,7 @@
for (size_t i = 0; i < arraysize(kRollbackActionTypes); ++i) {
EXPECT_EQ(kRollbackActionTypes[i], attempter_.actions_[i]->Type());
}
- EXPECT_EQ(UPDATE_STATUS_ATTEMPTING_ROLLBACK, attempter_.status());
+ EXPECT_EQ(UpdateStatus::ATTEMPTING_ROLLBACK, attempter_.status());
InstallPlanAction* install_plan_action =
dynamic_cast<InstallPlanAction*>(attempter_.actions_[0].get());
InstallPlan* install_plan = install_plan_action->install_plan();
@@ -573,7 +574,7 @@
base::Bind(&UpdateAttempterTest::PingOmahaTestStart,
base::Unretained(this)));
chromeos::MessageLoopRunMaxIterations(&loop_, 100);
- EXPECT_EQ(UPDATE_STATUS_UPDATED_NEED_REBOOT, attempter_.status());
+ EXPECT_EQ(UpdateStatus::UPDATED_NEED_REBOOT, attempter_.status());
EXPECT_TRUE(attempter_.schedule_updates_called());
}
diff --git a/update_engine.gyp b/update_engine.gyp
index 2a1768e..ec32550 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -51,6 +51,7 @@
# We need this include dir because we include all the local code as
# "update_engine/...".
'<(platform2_root)/../aosp/system',
+ '<(platform2_root)/../aosp/system/update_engine/client_library/include',
],
},
'targets': [
@@ -213,6 +214,7 @@
'update_manager/real_updater_provider.cc',
'update_manager/state_factory.cc',
'update_manager/update_manager.cc',
+ 'update_status_utils.cc',
'utils.cc',
'xz_extent_writer.cc',
],
diff --git a/update_status_utils.cc b/update_status_utils.cc
new file mode 100644
index 0000000..ff039b8
--- /dev/null
+++ b/update_status_utils.cc
@@ -0,0 +1,89 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include "update_engine/update_status_utils.h"
+
+#include <base/logging.h>
+#include <update_engine/dbus-constants.h>
+
+using update_engine::UpdateStatus;
+
+namespace chromeos_update_engine {
+
+const char* UpdateStatusToString(const UpdateStatus& status) {
+ switch (status) {
+ case UpdateStatus::IDLE:
+ return update_engine::kUpdateStatusIdle;
+ case UpdateStatus::CHECKING_FOR_UPDATE:
+ return update_engine::kUpdateStatusCheckingForUpdate;
+ case UpdateStatus::UPDATE_AVAILABLE:
+ return update_engine::kUpdateStatusUpdateAvailable;
+ case UpdateStatus::DOWNLOADING:
+ return update_engine::kUpdateStatusDownloading;
+ case UpdateStatus::VERIFYING:
+ return update_engine::kUpdateStatusVerifying;
+ case UpdateStatus::FINALIZING:
+ return update_engine::kUpdateStatusFinalizing;
+ case UpdateStatus::UPDATED_NEED_REBOOT:
+ return update_engine::kUpdateStatusUpdatedNeedReboot;
+ case UpdateStatus::REPORTING_ERROR_EVENT:
+ return update_engine::kUpdateStatusReportingErrorEvent;
+ case UpdateStatus::ATTEMPTING_ROLLBACK:
+ return update_engine::kUpdateStatusAttemptingRollback;
+ case UpdateStatus::DISABLED:
+ return update_engine::kUpdateStatusDisabled;
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
+
+bool StringToUpdateStatus(const std::string& s,
+ UpdateStatus* status) {
+ if (s == update_engine::kUpdateStatusIdle) {
+ *status = UpdateStatus::IDLE;
+ return true;
+ } else if (s == update_engine::kUpdateStatusCheckingForUpdate) {
+ *status = UpdateStatus::CHECKING_FOR_UPDATE;
+ return true;
+ } else if (s == update_engine::kUpdateStatusUpdateAvailable) {
+ *status = UpdateStatus::UPDATE_AVAILABLE;
+ return true;
+ } else if (s == update_engine::kUpdateStatusDownloading) {
+ *status = UpdateStatus::DOWNLOADING;
+ return true;
+ } else if (s == update_engine::kUpdateStatusVerifying) {
+ *status = UpdateStatus::VERIFYING;
+ return true;
+ } else if (s == update_engine::kUpdateStatusFinalizing) {
+ *status = UpdateStatus::FINALIZING;
+ return true;
+ } else if (s == update_engine::kUpdateStatusUpdatedNeedReboot) {
+ *status = UpdateStatus::UPDATED_NEED_REBOOT;
+ return true;
+ } else if (s == update_engine::kUpdateStatusReportingErrorEvent) {
+ *status = UpdateStatus::REPORTING_ERROR_EVENT;
+ return true;
+ } else if (s == update_engine::kUpdateStatusAttemptingRollback) {
+ *status = UpdateStatus::ATTEMPTING_ROLLBACK;
+ return true;
+ } else if (s == update_engine::kUpdateStatusDisabled) {
+ *status = UpdateStatus::DISABLED;
+ return true;
+ }
+ return false;
+}
+
+} // namespace chromeos_update_engine
diff --git a/update_status_utils.h b/update_status_utils.h
new file mode 100644
index 0000000..78d3530
--- /dev/null
+++ b/update_status_utils.h
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef CLIENT_LIBRARY_UPDATE_STATUS_TO_STRING_H_
+#define CLIENT_LIBRARY_UPDATE_STATUS_TO_STRING_H_
+
+#include <string>
+
+#include "update_engine/update_status.h"
+
+namespace chromeos_update_engine {
+
+const char* UpdateStatusToString(const update_engine::UpdateStatus& status);
+
+bool StringToUpdateStatus(const std::string& update_status_as_string,
+ update_engine::UpdateStatus* status);
+
+} // namespace chromeos_update_engine
+
+#endif // CLIENT_LIBRARY_UPDATE_STATUS_TO_STRING_H_