Merge remote-tracking branch 'aosp/upstream-master' into aosp/master.
The following change is reverted because aosp has newer libchrome.
71818c84 Partially Revert 2b9d241
Added stub override for ReportInternalErrorCode().
Fixed RunPosinstallAction typo.
Bug: 112326236
Test: update_engine_unittests
Change-Id: Ieaae0eef425cbb1278067a48aa19b14ed056317a
diff --git a/Android.mk b/Android.mk
index d1d8488..08492c0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -661,6 +661,7 @@
payload_generator/annotated_operation.cc \
payload_generator/blob_file_writer.cc \
payload_generator/block_mapping.cc \
+ payload_generator/boot_img_filesystem.cc \
payload_generator/bzip.cc \
payload_generator/cycle_breaker.cc \
payload_generator/deflate_utils.cc \
@@ -962,6 +963,7 @@
payload_generator/ab_generator_unittest.cc \
payload_generator/blob_file_writer_unittest.cc \
payload_generator/block_mapping_unittest.cc \
+ payload_generator/boot_img_filesystem_unittest.cc \
payload_generator/cycle_breaker_unittest.cc \
payload_generator/deflate_utils_unittest.cc \
payload_generator/delta_diff_utils_unittest.cc \
@@ -1048,7 +1050,6 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/update_engine
LOCAL_MODULE_STEM := update-payload-key.pub.pem
LOCAL_SRC_FILES := update_payload_key/brillo-update-payload-key.pub.pem
-LOCAL_BUILT_MODULE_STEM := update_payload_key/brillo-update-payload-key.pub.pem
include $(BUILD_PREBUILT)
endif # PRODUCT_IOT
diff --git a/common/error_code.h b/common/error_code.h
index 0d86a7b..86b7a3e 100644
--- a/common/error_code.h
+++ b/common/error_code.h
@@ -74,7 +74,7 @@
kUserCanceled = 48,
kNonCriticalUpdateInOOBE = 49,
kOmahaUpdateIgnoredOverCellular = 50,
- // kPayloadTimestampError = 51,
+ kPayloadTimestampError = 51,
kUpdatedButNotActive = 52,
kNoUpdate = 53,
kRollbackNotPossible = 54,
diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
index 2a2a0a3..930dafe 100644
--- a/common/error_code_utils.cc
+++ b/common/error_code_utils.cc
@@ -146,6 +146,8 @@
return "ErrorCode::kNonCriticalUpdateInOOBE";
case ErrorCode::kOmahaUpdateIgnoredOverCellular:
return "ErrorCode::kOmahaUpdateIgnoredOverCellular";
+ case ErrorCode::kPayloadTimestampError:
+ return "ErrorCode::kPayloadTimestampError";
case ErrorCode::kUpdatedButNotActive:
return "ErrorCode::kUpdatedButNotActive";
case ErrorCode::kNoUpdate:
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 55dcc2c..55ef32d 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -124,6 +124,8 @@
return false;
}
+ int64_t GetBuildTimestamp() const override { return build_timestamp_; }
+
bool GetFirstActiveOmahaPingSent() const override {
return first_active_omaha_ping_sent_;
}
@@ -185,6 +187,10 @@
powerwash_count_ = powerwash_count;
}
+ void SetBuildTimestamp(int64_t build_timestamp) {
+ build_timestamp_ = build_timestamp;
+ }
+
// Getters to verify state.
int GetMaxKernelKeyRollforward() const { return kernel_max_rollforward_; }
@@ -205,6 +211,7 @@
int firmware_max_rollforward_{kFirmwareMaxRollforward};
int powerwash_count_{kPowerwashCountNotSet};
bool powerwash_scheduled_{false};
+ int64_t build_timestamp_{0};
bool first_active_omaha_ping_sent_{false};
DISALLOW_COPY_AND_ASSIGN(FakeHardware);
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index dd42e05..bbc8660 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -17,6 +17,8 @@
#ifndef UPDATE_ENGINE_COMMON_HARDWARE_INTERFACE_H_
#define UPDATE_ENGINE_COMMON_HARDWARE_INTERFACE_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
@@ -116,6 +118,9 @@
// returns false.
virtual bool GetPowerwashSafeDirectory(base::FilePath* path) const = 0;
+ // Returns the timestamp of the current OS build.
+ virtual int64_t GetBuildTimestamp() const = 0;
+
// Returns whether the first active ping was sent to Omaha at some point, and
// that the value is persisted across recovery (and powerwash) once set with
// |SetFirstActiveOmahaPingSent()|.
diff --git a/common/hash_calculator_unittest.cc b/common/hash_calculator_unittest.cc
index 233237b..79f22ad 100644
--- a/common/hash_calculator_unittest.cc
+++ b/common/hash_calculator_unittest.cc
@@ -26,6 +26,7 @@
#include <brillo/secure_blob.h>
#include <gtest/gtest.h>
+#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
using std::string;
@@ -43,10 +44,7 @@
0xc8, 0x8b, 0x59, 0xb2, 0xdc, 0x32, 0x7a, 0xa4
};
-class HashCalculatorTest : public ::testing::Test {
- public:
- HashCalculatorTest() {}
-};
+class HashCalculatorTest : public ::testing::Test {};
TEST_F(HashCalculatorTest, SimpleTest) {
HashCalculator calc;
@@ -54,7 +52,7 @@
calc.Finalize();
brillo::Blob raw_hash(std::begin(kExpectedRawHash),
std::end(kExpectedRawHash));
- EXPECT_TRUE(raw_hash == calc.raw_hash());
+ EXPECT_EQ(raw_hash, calc.raw_hash());
}
TEST_F(HashCalculatorTest, MultiUpdateTest) {
@@ -64,7 +62,7 @@
calc.Finalize();
brillo::Blob raw_hash(std::begin(kExpectedRawHash),
std::end(kExpectedRawHash));
- EXPECT_TRUE(raw_hash == calc.raw_hash());
+ EXPECT_EQ(raw_hash, calc.raw_hash());
}
TEST_F(HashCalculatorTest, ContextTest) {
@@ -78,7 +76,7 @@
calc_next.Finalize();
brillo::Blob raw_hash(std::begin(kExpectedRawHash),
std::end(kExpectedRawHash));
- EXPECT_TRUE(raw_hash == calc_next.raw_hash());
+ EXPECT_EQ(raw_hash, calc_next.raw_hash());
}
TEST_F(HashCalculatorTest, BigTest) {
@@ -108,25 +106,21 @@
}
TEST_F(HashCalculatorTest, UpdateFileSimpleTest) {
- string data_path;
- ASSERT_TRUE(
- utils::MakeTempFile("data.XXXXXX", &data_path, nullptr));
- ScopedPathUnlinker data_path_unlinker(data_path);
- ASSERT_TRUE(utils::WriteFile(data_path.c_str(), "hi", 2));
+ test_utils::ScopedTempFile data_file("data.XXXXXX");
+ ASSERT_TRUE(test_utils::WriteFileString(data_file.path(), "hi"));
- static const int kLengths[] = { -1, 2, 10 };
- for (size_t i = 0; i < arraysize(kLengths); i++) {
+ for (const int length : {-1, 2, 10}) {
HashCalculator calc;
- EXPECT_EQ(2, calc.UpdateFile(data_path, kLengths[i]));
+ EXPECT_EQ(2, calc.UpdateFile(data_file.path(), length));
EXPECT_TRUE(calc.Finalize());
brillo::Blob raw_hash(std::begin(kExpectedRawHash),
std::end(kExpectedRawHash));
- EXPECT_TRUE(raw_hash == calc.raw_hash());
+ EXPECT_EQ(raw_hash, calc.raw_hash());
}
HashCalculator calc;
- EXPECT_EQ(0, calc.UpdateFile(data_path, 0));
- EXPECT_EQ(1, calc.UpdateFile(data_path, 1));
+ EXPECT_EQ(0, calc.UpdateFile(data_file.path(), 0));
+ EXPECT_EQ(1, calc.UpdateFile(data_file.path(), 1));
EXPECT_TRUE(calc.Finalize());
// echo -n h | openssl dgst -sha256 -binary | openssl base64
EXPECT_EQ("qqlAJmTxpB9A67xSyZk+tmrrNmYClY/fqig7ceZNsSM=",
@@ -134,21 +128,16 @@
}
TEST_F(HashCalculatorTest, RawHashOfFileSimpleTest) {
- string data_path;
- ASSERT_TRUE(
- utils::MakeTempFile("data.XXXXXX", &data_path, nullptr));
- ScopedPathUnlinker data_path_unlinker(data_path);
- ASSERT_TRUE(utils::WriteFile(data_path.c_str(), "hi", 2));
+ test_utils::ScopedTempFile data_file("data.XXXXXX");
+ ASSERT_TRUE(test_utils::WriteFileString(data_file.path(), "hi"));
- static const int kLengths[] = { -1, 2, 10 };
- for (size_t i = 0; i < arraysize(kLengths); i++) {
+ for (const int length : {-1, 2, 10}) {
brillo::Blob exp_raw_hash(std::begin(kExpectedRawHash),
std::end(kExpectedRawHash));
brillo::Blob raw_hash;
- EXPECT_EQ(2, HashCalculator::RawHashOfFile(data_path,
- kLengths[i],
- &raw_hash));
- EXPECT_TRUE(exp_raw_hash == raw_hash);
+ EXPECT_EQ(
+ 2, HashCalculator::RawHashOfFile(data_file.path(), length, &raw_hash));
+ EXPECT_EQ(exp_raw_hash, raw_hash);
}
}
diff --git a/common/http_fetcher_unittest.cc b/common/http_fetcher_unittest.cc
index a0b0522..23df67a 100644
--- a/common/http_fetcher_unittest.cc
+++ b/common/http_fetcher_unittest.cc
@@ -32,7 +32,6 @@
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/time/time.h>
-#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
diff --git a/common/subprocess_unittest.cc b/common/subprocess_unittest.cc
index 10710e8..c8996db 100644
--- a/common/subprocess_unittest.cc
+++ b/common/subprocess_unittest.cc
@@ -32,7 +32,6 @@
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/time/time.h>
-#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
diff --git a/common/utils.h b/common/utils.h
index ecb97a3..f7f285b 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -318,6 +318,16 @@
// reboot. Returns whether it succeeded getting the boot_id.
bool GetBootId(std::string* boot_id);
+// Divide |x| by |y| and round up to the nearest integer.
+constexpr uint64_t DivRoundUp(uint64_t x, uint64_t y) {
+ return (x + y - 1) / y;
+}
+
+// Round |x| up to be a multiple of |y|.
+constexpr uint64_t RoundUp(uint64_t x, uint64_t y) {
+ return DivRoundUp(x, y) * y;
+}
+
// Returns the integer value of the first section of |version|. E.g. for
// "10575.39." returns 10575. Returns 0 if |version| is empty, returns -1 if
// first section of |version| is invalid (e.g. not a number).
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index 1590eeb..3405b68 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -59,13 +59,11 @@
}
TEST(UtilsTest, WriteFileReadFile) {
- base::FilePath file;
- EXPECT_TRUE(base::CreateTemporaryFile(&file));
- ScopedPathUnlinker unlinker(file.value());
- EXPECT_TRUE(utils::WriteFile(file.value().c_str(), "hello", 5));
+ test_utils::ScopedTempFile file;
+ EXPECT_TRUE(utils::WriteFile(file.path().c_str(), "hello", 5));
brillo::Blob readback;
- EXPECT_TRUE(utils::ReadFile(file.value().c_str(), &readback));
+ EXPECT_TRUE(utils::ReadFile(file.path().c_str(), &readback));
EXPECT_EQ("hello", string(readback.begin(), readback.end()));
}
@@ -75,24 +73,21 @@
}
TEST(UtilsTest, ReadFileChunk) {
- base::FilePath file;
- EXPECT_TRUE(base::CreateTemporaryFile(&file));
- ScopedPathUnlinker unlinker(file.value());
+ test_utils::ScopedTempFile file;
brillo::Blob data;
const size_t kSize = 1024 * 1024;
for (size_t i = 0; i < kSize; i++) {
data.push_back(i % 255);
}
- EXPECT_TRUE(utils::WriteFile(file.value().c_str(), data.data(), data.size()));
+ EXPECT_TRUE(test_utils::WriteFileVector(file.path(), data));
brillo::Blob in_data;
- EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), kSize, 10, &in_data));
+ EXPECT_TRUE(utils::ReadFileChunk(file.path().c_str(), kSize, 10, &in_data));
EXPECT_TRUE(in_data.empty());
- EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 0, -1, &in_data));
- EXPECT_TRUE(data == in_data);
+ EXPECT_TRUE(utils::ReadFileChunk(file.path().c_str(), 0, -1, &in_data));
+ EXPECT_EQ(data, in_data);
in_data.clear();
- EXPECT_TRUE(utils::ReadFileChunk(file.value().c_str(), 10, 20, &in_data));
- EXPECT_TRUE(brillo::Blob(data.begin() + 10, data.begin() + 10 + 20) ==
- in_data);
+ EXPECT_TRUE(utils::ReadFileChunk(file.path().c_str(), 10, 20, &in_data));
+ EXPECT_EQ(brillo::Blob(data.begin() + 10, data.begin() + 10 + 20), in_data);
}
TEST(UtilsTest, ErrnoNumberAsStringTest) {
@@ -305,8 +300,9 @@
base::Time::Exploded exploded = (base::Time::Exploded) {
.year = 2001, .month = 9, .day_of_week = 0, .day_of_month = 9,
.hour = 1, .minute = 46, .second = 40, .millisecond = 42};
- EXPECT_EQ(base::Time::FromUTCExploded(exploded),
- utils::TimeFromStructTimespec(&ts));
+ base::Time time;
+ EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time));
+ EXPECT_EQ(time, utils::TimeFromStructTimespec(&ts));
}
TEST(UtilsTest, DecodeAndStoreBase64String) {
@@ -481,20 +477,18 @@
}
TEST(UtilsTest, RunAsRootUnmountFilesystemBusyFailureTest) {
- string tmp_image;
- EXPECT_TRUE(utils::MakeTempFile("img.XXXXXX", &tmp_image, nullptr));
- ScopedPathUnlinker tmp_image_unlinker(tmp_image);
+ test_utils::ScopedTempFile tmp_image("img.XXXXXX");
EXPECT_TRUE(base::CopyFile(
test_utils::GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
- base::FilePath(tmp_image)));
+ base::FilePath(tmp_image.path())));
base::ScopedTempDir mnt_dir;
EXPECT_TRUE(mnt_dir.CreateUniqueTempDir());
string loop_dev;
test_utils::ScopedLoopbackDeviceBinder loop_binder(
- tmp_image, true, &loop_dev);
+ tmp_image.path(), true, &loop_dev);
EXPECT_FALSE(utils::IsMountpoint(mnt_dir.GetPath().value()));
// This is the actual test part. While we hold a file descriptor open for the
@@ -523,10 +517,8 @@
EXPECT_TRUE(mnt_dir.CreateUniqueTempDir());
EXPECT_FALSE(utils::IsMountpoint(mnt_dir.GetPath().value()));
- base::FilePath file;
- EXPECT_TRUE(base::CreateTemporaryFile(&file));
- ScopedPathUnlinker unlinker(file.value());
- EXPECT_FALSE(utils::IsMountpoint(file.value()));
+ test_utils::ScopedTempFile file;
+ EXPECT_FALSE(utils::IsMountpoint(file.path()));
}
TEST(UtilsTest, VersionPrefix) {
diff --git a/hardware_android.cc b/hardware_android.cc
index deabc5c..9dd8bb6 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -34,6 +34,7 @@
#include "update_engine/utils_android.h"
using android::base::GetBoolProperty;
+using android::base::GetIntProperty;
using android::base::GetProperty;
using std::string;
@@ -55,6 +56,7 @@
const char kPropProductManufacturer[] = "ro.product.manufacturer";
const char kPropBootHardwareSKU[] = "ro.boot.hardware.sku";
const char kPropBootRevision[] = "ro.boot.revision";
+const char kPropBuildDateUTC[] = "ro.build.date.utc";
// Write a recovery command line |message| to the BCB. The arguments to recovery
// must be separated by '\n'. An empty string will erase the BCB.
@@ -219,6 +221,10 @@
return false;
}
+int64_t HardwareAndroid::GetBuildTimestamp() const {
+ return GetIntProperty<int64_t>(kPropBuildDateUTC, 0);
+}
+
bool HardwareAndroid::GetFirstActiveOmahaPingSent() const {
LOG(WARNING) << "STUB: Assuming first active omaha was never set.";
return false;
diff --git a/hardware_android.h b/hardware_android.h
index b7a6f96..920b659 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -52,6 +52,7 @@
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
+ int64_t GetBuildTimestamp() const override;
bool GetFirstActiveOmahaPingSent() const override;
bool SetFirstActiveOmahaPingSent() override;
diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
index 6cfe5ef..3949328 100644
--- a/hardware_chromeos.cc
+++ b/hardware_chromeos.cc
@@ -261,6 +261,11 @@
return true;
}
+int64_t HardwareChromeOS::GetBuildTimestamp() const {
+ // TODO(senj): implement this in Chrome OS.
+ return 0;
+}
+
void HardwareChromeOS::LoadConfig(const string& root_prefix, bool normal_mode) {
brillo::KeyValueStore store;
diff --git a/hardware_chromeos.h b/hardware_chromeos.h
index 3aeeb0b..5c66641 100644
--- a/hardware_chromeos.h
+++ b/hardware_chromeos.h
@@ -57,6 +57,7 @@
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
+ int64_t GetBuildTimestamp() const override;
bool GetFirstActiveOmahaPingSent() const override;
bool SetFirstActiveOmahaPingSent() override;
diff --git a/metrics_reporter_stub.h b/metrics_reporter_stub.h
index 486dc2f..87023ee 100644
--- a/metrics_reporter_stub.h
+++ b/metrics_reporter_stub.h
@@ -85,6 +85,8 @@
void ReportInstallDateProvisioningSource(int source, int max) override {}
+ void ReportInternalErrorCode(ErrorCode error_code) override {}
+
void ReportKeyVersionMetrics(int kernel_min_version,
int kernel_max_rollforward_version,
bool kernel_max_rollforward_success) override {}
diff --git a/metrics_utils.cc b/metrics_utils.cc
index b85f257..d80d394 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -78,6 +78,7 @@
case ErrorCode::kDownloadPayloadVerificationError:
case ErrorCode::kSignedDeltaPayloadExpectedError:
case ErrorCode::kDownloadPayloadPubKeyVerificationError:
+ case ErrorCode::kPayloadTimestampError:
return metrics::AttemptResult::kPayloadVerificationFailed;
case ErrorCode::kNewRootfsVerificationError:
@@ -218,6 +219,7 @@
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
case ErrorCode::kOmahaUpdateIgnoredOverCellular:
+ case ErrorCode::kPayloadTimestampError:
case ErrorCode::kUpdatedButNotActive:
case ErrorCode::kNoUpdate:
case ErrorCode::kRollbackNotPossible:
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index bdec86f..4e101ee 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -176,11 +176,8 @@
}
TEST_F(OmahaResponseHandlerActionTest, SimpleTest) {
- string test_deadline_file;
- CHECK(utils::MakeTempFile("omaha_response_handler_action_unittest-XXXXXX",
- &test_deadline_file,
- nullptr));
- ScopedPathUnlinker deadline_unlinker(test_deadline_file);
+ test_utils::ScopedTempFile test_deadline_file(
+ "omaha_response_handler_action_unittest-XXXXXX");
{
OmahaResponse in;
in.update_exists = true;
@@ -193,15 +190,15 @@
in.prompt = false;
in.deadline = "20101020";
InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
+ EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
EXPECT_EQ(1U, install_plan.target_slot);
string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
+ EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
EXPECT_EQ("20101020", deadline);
struct stat deadline_stat;
- EXPECT_EQ(0, stat(test_deadline_file.c_str(), &deadline_stat));
+ EXPECT_EQ(0, stat(test_deadline_file.path().c_str(), &deadline_stat));
EXPECT_EQ(
static_cast<mode_t>(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH),
deadline_stat.st_mode);
@@ -220,12 +217,12 @@
InstallPlan install_plan;
// Set the other slot as current.
fake_system_state_.fake_boot_control()->SetCurrentSlot(1);
- EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
+ EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
EXPECT_EQ(0U, install_plan.target_slot);
string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline) &&
+ EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline) &&
deadline.empty());
EXPECT_EQ(in.version, install_plan.version);
}
@@ -245,12 +242,12 @@
EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
GetRollbackHappened())
.WillOnce(Return(true));
- EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
+ EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
EXPECT_EQ(1U, install_plan.target_slot);
string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
+ EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
EXPECT_TRUE(deadline.empty());
EXPECT_EQ(in.version, install_plan.version);
}
@@ -268,12 +265,12 @@
EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
GetRollbackHappened())
.WillOnce(Return(false));
- EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
+ EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
EXPECT_EQ(1U, install_plan.target_slot);
string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
+ EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
EXPECT_EQ("some-deadline", deadline);
EXPECT_EQ(in.version, install_plan.version);
}
diff --git a/payload_consumer/bzip_extent_writer_unittest.cc b/payload_consumer/bzip_extent_writer_unittest.cc
index bf050ef..4426876 100644
--- a/payload_consumer/bzip_extent_writer_unittest.cc
+++ b/payload_consumer/bzip_extent_writer_unittest.cc
@@ -100,8 +100,7 @@
for (size_t i = 0; i < decompressed_data.size(); ++i)
decompressed_data[i] = static_cast<uint8_t>("ABC\n"[i % 4]);
- vector<Extent> extents = {
- ExtentForRange(0, (kDecompressedLength + kBlockSize - 1) / kBlockSize)};
+ vector<Extent> extents = {ExtentForBytes(kBlockSize, 0, kDecompressedLength)};
BzipExtentWriter bzip_writer(std::make_unique<DirectExtentWriter>());
EXPECT_TRUE(
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 86bd6c3..7831c0f 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -1587,6 +1587,14 @@
}
}
+ if (manifest_.max_timestamp() < hardware_->GetBuildTimestamp()) {
+ LOG(ERROR) << "The current OS build timestamp ("
+ << hardware_->GetBuildTimestamp()
+ << ") is newer than the maximum timestamp in the manifest ("
+ << manifest_.max_timestamp() << ")";
+ return ErrorCode::kPayloadTimestampError;
+ }
+
// TODO(garnold) we should be adding more and more manifest checks, such as
// partition boundaries etc (see chromium-os:37661).
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index 78647a5..b2fda15 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -234,9 +234,7 @@
RSA_free(rsa);
}
int signature_size = GetSignatureSize(private_key_path);
- string hash_file;
- ASSERT_TRUE(utils::MakeTempFile("hash.XXXXXX", &hash_file, nullptr));
- ScopedPathUnlinker hash_unlinker(hash_file);
+ test_utils::ScopedTempFile hash_file("hash.XXXXXX");
string signature_size_string;
if (signature_test == kSignatureGeneratedShellRotateCl1 ||
signature_test == kSignatureGeneratedShellRotateCl2)
@@ -251,28 +249,25 @@
delta_generator_path.c_str(),
payload_path.c_str(),
signature_size_string.c_str(),
- hash_file.c_str())));
+ hash_file.path().c_str())));
// Sign the hash
brillo::Blob hash, signature;
- ASSERT_TRUE(utils::ReadFile(hash_file, &hash));
+ ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
- string sig_file;
- ASSERT_TRUE(utils::MakeTempFile("signature.XXXXXX", &sig_file, nullptr));
- ScopedPathUnlinker sig_unlinker(sig_file);
- ASSERT_TRUE(test_utils::WriteFileVector(sig_file, signature));
+ test_utils::ScopedTempFile sig_file("signature.XXXXXX");
+ ASSERT_TRUE(test_utils::WriteFileVector(sig_file.path(), signature));
+ string sig_files = sig_file.path();
- string sig_file2;
- ASSERT_TRUE(utils::MakeTempFile("signature.XXXXXX", &sig_file2, nullptr));
- ScopedPathUnlinker sig2_unlinker(sig_file2);
+ test_utils::ScopedTempFile sig_file2("signature.XXXXXX");
if (signature_test == kSignatureGeneratedShellRotateCl1 ||
signature_test == kSignatureGeneratedShellRotateCl2) {
ASSERT_TRUE(PayloadSigner::SignHash(
hash, GetBuildArtifactsPath(kUnittestPrivateKey2Path), &signature));
- ASSERT_TRUE(test_utils::WriteFileVector(sig_file2, signature));
+ ASSERT_TRUE(test_utils::WriteFileVector(sig_file2.path(), signature));
// Append second sig file to first path
- sig_file += ":" + sig_file2;
+ sig_files += ":" + sig_file2.path();
}
ASSERT_EQ(0,
@@ -280,7 +275,7 @@
"%s -in_file=%s -payload_signature_file=%s -out_file=%s",
delta_generator_path.c_str(),
payload_path.c_str(),
- sig_file.c_str(),
+ sig_files.c_str(),
payload_path.c_str())));
int verify_result = System(base::StringPrintf(
"%s -in_file=%s -public_key=%s -public_key_version=%d",
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index 21f22d6..b0520e7 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -185,12 +185,8 @@
bool sign_payload,
uint64_t major_version,
uint32_t minor_version) {
- string blob_path;
- EXPECT_TRUE(utils::MakeTempFile("Blob-XXXXXX", &blob_path, nullptr));
- ScopedPathUnlinker blob_unlinker(blob_path);
- EXPECT_TRUE(utils::WriteFile(blob_path.c_str(),
- blob_data.data(),
- blob_data.size()));
+ test_utils::ScopedTempFile blob_file("Blob-XXXXXX");
+ EXPECT_TRUE(test_utils::WriteFileVector(blob_file.path(), blob_data));
PayloadGenerationConfig config;
config.version.major = major_version;
@@ -218,16 +214,16 @@
new_part.size = 0;
payload.AddPartition(old_part, new_part, {});
- string payload_path;
- EXPECT_TRUE(utils::MakeTempFile("Payload-XXXXXX", &payload_path, nullptr));
- ScopedPathUnlinker payload_unlinker(payload_path);
+ test_utils::ScopedTempFile payload_file("Payload-XXXXXX");
string private_key =
sign_payload ? GetBuildArtifactsPath(kUnittestPrivateKeyPath) : "";
- EXPECT_TRUE(payload.WritePayload(
- payload_path, blob_path, private_key, &payload_.metadata_size));
+ EXPECT_TRUE(payload.WritePayload(payload_file.path(),
+ blob_file.path(),
+ private_key,
+ &payload_.metadata_size));
brillo::Blob payload_data;
- EXPECT_TRUE(utils::ReadFile(payload_path, &payload_data));
+ EXPECT_TRUE(utils::ReadFile(payload_file.path(), &payload_data));
return payload_data;
}
@@ -268,16 +264,13 @@
const string& source_path,
const brillo::Blob& target_data,
bool expect_success) {
- 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()));
+ test_utils::ScopedTempFile new_part("Partition-XXXXXX");
+ EXPECT_TRUE(test_utils::WriteFileVector(new_part.path(), target_data));
// We installed the operations only in the rootfs partition, but the
// delta performer needs to access all the partitions.
fake_boot_control_.SetPartitionDevice(
- kPartitionNameRoot, install_plan_.target_slot, new_part);
+ kPartitionNameRoot, install_plan_.target_slot, new_part.path());
fake_boot_control_.SetPartitionDevice(
kPartitionNameRoot, install_plan_.source_slot, source_path);
fake_boot_control_.SetPartitionDevice(
@@ -290,7 +283,7 @@
EXPECT_EQ(0, performer_.Close());
brillo::Blob partition_data;
- EXPECT_TRUE(utils::ReadFile(new_part, &partition_data));
+ EXPECT_TRUE(utils::ReadFile(new_part.path(), &partition_data));
return partition_data;
}
@@ -568,15 +561,10 @@
brillo::Blob payload_data = GeneratePayload(brillo::Blob(), {aop}, false);
- string source_path;
- EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX",
- &source_path, nullptr));
- ScopedPathUnlinker path_unlinker(source_path);
- EXPECT_TRUE(utils::WriteFile(source_path.c_str(),
- expected_data.data(),
- expected_data.size()));
+ test_utils::ScopedTempFile source("Source-XXXXXX");
+ EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
- EXPECT_EQ(expected_data, ApplyPayload(payload_data, source_path, true));
+ EXPECT_EQ(expected_data, ApplyPayload(payload_data, source.path(), true));
}
TEST_F(DeltaPerformerTest, PuffdiffOperationTest) {
@@ -596,13 +584,11 @@
brillo::Blob payload_data = GeneratePayload(puffdiff_payload, {aop}, false);
- string source_path;
- EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", &source_path, nullptr));
- ScopedPathUnlinker path_unlinker(source_path);
- EXPECT_TRUE(utils::WriteFile(source_path.c_str(), src.data(), src.size()));
+ test_utils::ScopedTempFile source("Source-XXXXXX");
+ EXPECT_TRUE(test_utils::WriteFileVector(source.path(), src));
brillo::Blob dst(std::begin(dst_deflates), std::end(dst_deflates));
- EXPECT_EQ(dst, ApplyPayload(payload_data, source_path, true));
+ EXPECT_EQ(dst, ApplyPayload(payload_data, source.path(), true));
}
TEST_F(DeltaPerformerTest, SourceHashMismatchTest) {
@@ -621,27 +607,21 @@
brillo::Blob payload_data = GeneratePayload(brillo::Blob(), {aop}, false);
- string source_path;
- EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", &source_path, nullptr));
- ScopedPathUnlinker path_unlinker(source_path);
- EXPECT_TRUE(utils::WriteFile(source_path.c_str(), actual_data.data(),
- actual_data.size()));
+ test_utils::ScopedTempFile source("Source-XXXXXX");
+ EXPECT_TRUE(test_utils::WriteFileVector(source.path(), actual_data));
- EXPECT_EQ(actual_data, ApplyPayload(payload_data, source_path, false));
+ EXPECT_EQ(actual_data, ApplyPayload(payload_data, source.path(), false));
}
// Test that the error-corrected file descriptor is used to read the partition
// since the source partition doesn't match the operation hash.
TEST_F(DeltaPerformerTest, ErrorCorrectionSourceCopyFallbackTest) {
- const size_t kCopyOperationSize = 4 * 4096;
- string source_path;
- EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", &source_path, nullptr));
- ScopedPathUnlinker path_unlinker(source_path);
+ constexpr size_t kCopyOperationSize = 4 * 4096;
+ test_utils::ScopedTempFile source("Source-XXXXXX");
// Write invalid data to the source image, which doesn't match the expected
// hash.
brillo::Blob invalid_data(kCopyOperationSize, 0x55);
- EXPECT_TRUE(utils::WriteFile(
- source_path.c_str(), invalid_data.data(), invalid_data.size()));
+ EXPECT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
// Setup the fec file descriptor as the fake stream, which matches
// |expected_data|.
@@ -649,7 +629,7 @@
brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
brillo::Blob payload_data = GenerateSourceCopyPayload(expected_data, true);
- EXPECT_EQ(expected_data, ApplyPayload(payload_data, source_path, true));
+ EXPECT_EQ(expected_data, ApplyPayload(payload_data, source.path(), true));
// Verify that the fake_fec was actually used.
EXPECT_EQ(1U, fake_fec->GetReadOps().size());
EXPECT_EQ(1U, GetSourceEccRecoveredFailures());
@@ -659,14 +639,11 @@
// when no hash is available for SOURCE_COPY but it falls back to the normal
// file descriptor when the size of the error corrected one is too small.
TEST_F(DeltaPerformerTest, ErrorCorrectionSourceCopyWhenNoHashFallbackTest) {
- const size_t kCopyOperationSize = 4 * 4096;
- string source_path;
- EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", &source_path, nullptr));
- ScopedPathUnlinker path_unlinker(source_path);
+ constexpr size_t kCopyOperationSize = 4 * 4096;
+ test_utils::ScopedTempFile source("Source-XXXXXX");
// Setup the source path with the right expected data.
brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
- EXPECT_TRUE(utils::WriteFile(
- source_path.c_str(), expected_data.data(), expected_data.size()));
+ EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
// Setup the fec file descriptor as the fake stream, with smaller data than
// the expected.
@@ -674,7 +651,7 @@
// The payload operation doesn't include an operation hash.
brillo::Blob payload_data = GenerateSourceCopyPayload(expected_data, false);
- EXPECT_EQ(expected_data, ApplyPayload(payload_data, source_path, true));
+ EXPECT_EQ(expected_data, ApplyPayload(payload_data, source.path(), true));
// Verify that the fake_fec was attempted to be used. Since the file
// descriptor is shorter it can actually do more than one read to realize it
// reached the EOF.
@@ -685,18 +662,15 @@
}
TEST_F(DeltaPerformerTest, ChooseSourceFDTest) {
- const size_t kSourceSize = 4 * 4096;
- string source_path;
- EXPECT_TRUE(utils::MakeTempFile("Source-XXXXXX", &source_path, nullptr));
- ScopedPathUnlinker path_unlinker(source_path);
+ constexpr size_t kSourceSize = 4 * 4096;
+ test_utils::ScopedTempFile source("Source-XXXXXX");
// Write invalid data to the source image, which doesn't match the expected
// hash.
brillo::Blob invalid_data(kSourceSize, 0x55);
- EXPECT_TRUE(utils::WriteFile(
- source_path.c_str(), invalid_data.data(), invalid_data.size()));
+ EXPECT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
performer_.source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
- performer_.source_fd_->Open(source_path.c_str(), O_RDONLY);
+ performer_.source_fd_->Open(source.path().c_str(), O_RDONLY);
performer_.block_size_ = 4096;
// Setup the fec file descriptor as the fake stream, which matches
@@ -861,6 +835,20 @@
ErrorCode::kUnsupportedMinorPayloadVersion);
}
+TEST_F(DeltaPerformerTest, ValidateManifestDowngrade) {
+ // The Manifest we are validating.
+ DeltaArchiveManifest manifest;
+
+ manifest.set_minor_version(kFullPayloadMinorVersion);
+ manifest.set_max_timestamp(1);
+ fake_hardware_.SetBuildTimestamp(2);
+
+ RunManifestValidation(manifest,
+ kMaxSupportedMajorPayloadVersion,
+ InstallPayloadType::kFull,
+ ErrorCode::kPayloadTimestampError);
+}
+
TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeTest) {
unsigned int seed = time(nullptr);
EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
diff --git a/payload_consumer/download_action_unittest.cc b/payload_consumer/download_action_unittest.cc
index 8efcd8e..84673c8 100644
--- a/payload_consumer/download_action_unittest.cc
+++ b/payload_consumer/download_action_unittest.cc
@@ -29,7 +29,6 @@
#include <base/files/file_util.h>
#include <base/location.h>
#include <base/strings/stringprintf.h>
-#include <brillo/bind_lambda.h>
#include <brillo/message_loops/fake_message_loop.h>
#include <brillo/message_loops/message_loop.h>
diff --git a/payload_consumer/file_writer_unittest.cc b/payload_consumer/file_writer_unittest.cc
index 92837c8..05df307 100644
--- a/payload_consumer/file_writer_unittest.cc
+++ b/payload_consumer/file_writer_unittest.cc
@@ -36,19 +36,17 @@
TEST(FileWriterTest, SimpleTest) {
// Create a uniquely named file for testing.
- string path;
- ASSERT_TRUE(utils::MakeTempFile("FileWriterTest-XXXXXX", &path, nullptr));
- ScopedPathUnlinker path_unlinker(path);
-
+ test_utils::ScopedTempFile file("FileWriterTest-XXXXXX");
DirectFileWriter file_writer;
- EXPECT_EQ(0, file_writer.Open(path.c_str(),
- O_CREAT | O_LARGEFILE | O_TRUNC | O_WRONLY,
- 0644));
+ EXPECT_EQ(0,
+ file_writer.Open(file.path().c_str(),
+ O_CREAT | O_LARGEFILE | O_TRUNC | O_WRONLY,
+ 0644));
EXPECT_TRUE(file_writer.Write("test", 4));
brillo::Blob actual_data;
- EXPECT_TRUE(utils::ReadFile(path, &actual_data));
+ EXPECT_TRUE(utils::ReadFile(file.path(), &actual_data));
- EXPECT_FALSE(memcmp("test", actual_data.data(), actual_data.size()));
+ EXPECT_EQ("test", string(actual_data.begin(), actual_data.end()));
EXPECT_EQ(0, file_writer.Close());
}
@@ -61,14 +59,12 @@
TEST(FileWriterTest, WriteErrorTest) {
// Create a uniquely named file for testing.
- string path;
- ASSERT_TRUE(utils::MakeTempFile("FileWriterTest-XXXXXX", &path, nullptr));
- ScopedPathUnlinker path_unlinker(path);
-
+ test_utils::ScopedTempFile file("FileWriterTest-XXXXXX");
DirectFileWriter file_writer;
- EXPECT_EQ(0, file_writer.Open(path.c_str(),
- O_CREAT | O_LARGEFILE | O_TRUNC | O_RDONLY,
- 0644));
+ EXPECT_EQ(0,
+ file_writer.Open(file.path().c_str(),
+ O_CREAT | O_LARGEFILE | O_TRUNC | O_RDONLY,
+ 0644));
EXPECT_FALSE(file_writer.Write("x", 1));
EXPECT_EQ(0, file_writer.Close());
}
diff --git a/payload_consumer/filesystem_verifier_action_unittest.cc b/payload_consumer/filesystem_verifier_action_unittest.cc
index 895d816..91a7da4 100644
--- a/payload_consumer/filesystem_verifier_action_unittest.cc
+++ b/payload_consumer/filesystem_verifier_action_unittest.cc
@@ -28,7 +28,6 @@
#include <base/posix/eintr_wrapper.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
-#include <brillo/bind_lambda.h>
#include <brillo/message_loops/fake_message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
#include <gmock/gmock.h>
@@ -99,13 +98,7 @@
bool FilesystemVerifierActionTest::DoTest(bool terminate_early,
bool hash_fail) {
- string a_loop_file;
-
- if (!(utils::MakeTempFile("a_loop_file.XXXXXX", &a_loop_file, nullptr))) {
- ADD_FAILURE();
- return false;
- }
- ScopedPathUnlinker a_loop_file_unlinker(a_loop_file);
+ test_utils::ScopedTempFile a_loop_file("a_loop_file.XXXXXX");
// Make random data for a.
const size_t kLoopFileSize = 10 * 1024 * 1024 + 512;
@@ -113,7 +106,7 @@
test_utils::FillWithData(&a_loop_data);
// Write data to disk
- if (!(test_utils::WriteFileVector(a_loop_file, a_loop_data))) {
+ if (!(test_utils::WriteFileVector(a_loop_file.path(), a_loop_data))) {
ADD_FAILURE();
return false;
}
@@ -121,13 +114,13 @@
// Attach loop devices to the files
string a_dev;
test_utils::ScopedLoopbackDeviceBinder a_dev_releaser(
- a_loop_file, false, &a_dev);
+ a_loop_file.path(), false, &a_dev);
if (!(a_dev_releaser.is_bound())) {
ADD_FAILURE();
return false;
}
- LOG(INFO) << "verifying: " << a_loop_file << " (" << a_dev << ")";
+ LOG(INFO) << "verifying: " << a_loop_file.path() << " (" << a_dev << ")";
bool success = true;
diff --git a/payload_consumer/postinstall_runner_action_unittest.cc b/payload_consumer/postinstall_runner_action_unittest.cc
index 3c606c1..8381472 100644
--- a/payload_consumer/postinstall_runner_action_unittest.cc
+++ b/payload_consumer/postinstall_runner_action_unittest.cc
@@ -29,7 +29,6 @@
#include <base/message_loop/message_loop.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
-#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
#include <gmock/gmock.h>
@@ -330,7 +329,7 @@
// SElinux labels are only set on Android.
TEST_F(PostinstallRunnerActionTest, RunAsRootCheckFileContextsTest) {
ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
- RunPosinstallAction(loop.dev(), "bin/self_check_context", false, false);
+ RunPostinstallAction(loop.dev(), "bin/self_check_context", false, false);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
}
#endif // __ANDROID__
diff --git a/payload_generator/ab_generator_unittest.cc b/payload_generator/ab_generator_unittest.cc
index 25609c7..d083d8a 100644
--- a/payload_generator/ab_generator_unittest.cc
+++ b/payload_generator/ab_generator_unittest.cc
@@ -58,10 +58,6 @@
const size_t part_num_blocks = 7;
// Create the target partition data.
- string part_path;
- EXPECT_TRUE(utils::MakeTempFile(
- "SplitReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
- ScopedPathUnlinker part_path_unlinker(part_path);
const size_t part_size = part_num_blocks * kBlockSize;
brillo::Blob part_data;
if (compressible) {
@@ -74,7 +70,9 @@
part_data.push_back(dis(gen));
}
ASSERT_EQ(part_size, part_data.size());
- ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
+ test_utils::ScopedTempFile part_file(
+ "SplitReplaceOrReplaceBzTest_part.XXXXXX");
+ ASSERT_TRUE(test_utils::WriteFileVector(part_file.path(), part_data));
// Create original operation and blob data.
const size_t op_ex1_offset = op_ex1_start_block * kBlockSize;
@@ -109,15 +107,12 @@
aop.name = "SplitTestOp";
// Create the data file.
- string data_path;
- EXPECT_TRUE(utils::MakeTempFile(
- "SplitReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr));
- ScopedPathUnlinker data_path_unlinker(data_path);
- int data_fd = open(data_path.c_str(), O_RDWR, 000);
+ test_utils::ScopedTempFile data_file(
+ "SplitReplaceOrReplaceBzTest_data.XXXXXX");
+ EXPECT_TRUE(test_utils::WriteFileVector(data_file.path(), op_blob));
+ int data_fd = open(data_file.path().c_str(), O_RDWR, 000);
EXPECT_GE(data_fd, 0);
ScopedFdCloser data_fd_closer(&data_fd);
- EXPECT_TRUE(utils::WriteFile(data_path.c_str(), op_blob.data(),
- op_blob.size()));
off_t data_file_size = op_blob.size();
BlobFileWriter blob_file(data_fd, &data_file_size);
@@ -126,7 +121,7 @@
PayloadVersion version(kChromeOSMajorPayloadVersion,
kSourceMinorPayloadVersion);
ASSERT_TRUE(ABGenerator::SplitAReplaceOp(
- version, aop, part_path, &result_ops, &blob_file));
+ version, aop, part_file.path(), &result_ops, &blob_file));
// Check the result.
InstallOperation_Type expected_type =
@@ -212,10 +207,6 @@
const size_t part_num_blocks = total_op_num_blocks + 2;
// Create the target partition data.
- string part_path;
- EXPECT_TRUE(utils::MakeTempFile(
- "MergeReplaceOrReplaceBzTest_part.XXXXXX", &part_path, nullptr));
- ScopedPathUnlinker part_path_unlinker(part_path);
const size_t part_size = part_num_blocks * kBlockSize;
brillo::Blob part_data;
if (compressible) {
@@ -228,7 +219,9 @@
part_data.push_back(dis(gen));
}
ASSERT_EQ(part_size, part_data.size());
- ASSERT_TRUE(utils::WriteFile(part_path.c_str(), part_data.data(), part_size));
+ test_utils::ScopedTempFile part_file(
+ "MergeReplaceOrReplaceBzTest_part.XXXXXX");
+ ASSERT_TRUE(test_utils::WriteFileVector(part_file.path(), part_data));
// Create original operations and blob data.
vector<AnnotatedOperation> aops;
@@ -277,23 +270,20 @@
aops.push_back(second_aop);
// Create the data file.
- string data_path;
- EXPECT_TRUE(utils::MakeTempFile(
- "MergeReplaceOrReplaceBzTest_data.XXXXXX", &data_path, nullptr));
- ScopedPathUnlinker data_path_unlinker(data_path);
- int data_fd = open(data_path.c_str(), O_RDWR, 000);
+ test_utils::ScopedTempFile data_file(
+ "MergeReplaceOrReplaceBzTest_data.XXXXXX");
+ EXPECT_TRUE(test_utils::WriteFileVector(data_file.path(), blob_data));
+ int data_fd = open(data_file.path().c_str(), O_RDWR, 000);
EXPECT_GE(data_fd, 0);
ScopedFdCloser data_fd_closer(&data_fd);
- EXPECT_TRUE(utils::WriteFile(data_path.c_str(), blob_data.data(),
- blob_data.size()));
off_t data_file_size = blob_data.size();
BlobFileWriter blob_file(data_fd, &data_file_size);
// Merge the operations.
PayloadVersion version(kChromeOSMajorPayloadVersion,
kSourceMinorPayloadVersion);
- EXPECT_TRUE(
- ABGenerator::MergeOperations(&aops, version, 5, part_path, &blob_file));
+ EXPECT_TRUE(ABGenerator::MergeOperations(
+ &aops, version, 5, part_file.path(), &blob_file));
// Check the result.
InstallOperation_Type expected_op_type =
@@ -570,16 +560,12 @@
second_aop.op = second_op;
aops.push_back(second_aop);
- string src_part_path;
- EXPECT_TRUE(utils::MakeTempFile("AddSourceHashTest_src_part.XXXXXX",
- &src_part_path, nullptr));
- ScopedPathUnlinker src_part_path_unlinker(src_part_path);
+ test_utils::ScopedTempFile src_part_file("AddSourceHashTest_src_part.XXXXXX");
brillo::Blob src_data(kBlockSize);
test_utils::FillWithData(&src_data);
- ASSERT_TRUE(utils::WriteFile(src_part_path.c_str(), src_data.data(),
- src_data.size()));
+ ASSERT_TRUE(test_utils::WriteFileVector(src_part_file.path(), src_data));
- EXPECT_TRUE(ABGenerator::AddSourceHash(&aops, src_part_path));
+ EXPECT_TRUE(ABGenerator::AddSourceHash(&aops, src_part_file.path()));
EXPECT_TRUE(aops[0].op.has_src_sha256_hash());
EXPECT_FALSE(aops[1].op.has_src_sha256_hash());
diff --git a/payload_generator/block_mapping_unittest.cc b/payload_generator/block_mapping_unittest.cc
index 4d09710..e1870ec 100644
--- a/payload_generator/block_mapping_unittest.cc
+++ b/payload_generator/block_mapping_unittest.cc
@@ -39,23 +39,9 @@
class BlockMappingTest : public ::testing::Test {
protected:
- void SetUp() override {
- EXPECT_TRUE(utils::MakeTempFile("BlockMappingTest_old.XXXXXX",
- &old_part_path_,
- nullptr));
- EXPECT_TRUE(utils::MakeTempFile("BlockMappingTest_new.XXXXXX",
- &new_part_path_,
- nullptr));
-
- old_part_unlinker_.reset(new ScopedPathUnlinker(old_part_path_));
- new_part_unlinker_.reset(new ScopedPathUnlinker(new_part_path_));
- }
-
// Old new partition files used in testing.
- string old_part_path_;
- string new_part_path_;
- std::unique_ptr<ScopedPathUnlinker> old_part_unlinker_;
- std::unique_ptr<ScopedPathUnlinker> new_part_unlinker_;
+ test_utils::ScopedTempFile old_part_{"BlockMappingTest_old.XXXXXX"};
+ test_utils::ScopedTempFile new_part_{"BlockMappingTest_new.XXXXXX"};
size_t block_size_{1024};
BlockMapping bm_{block_size_}; // BlockMapping under test.
@@ -72,8 +58,8 @@
}
TEST_F(BlockMappingTest, BlocksAreNotKeptInMemory) {
- test_utils::WriteFileString(old_part_path_, string(block_size_, 'a'));
- int old_fd = HANDLE_EINTR(open(old_part_path_.c_str(), O_RDONLY));
+ test_utils::WriteFileString(old_part_.path(), string(block_size_, 'a'));
+ int old_fd = HANDLE_EINTR(open(old_part_.path().c_str(), O_RDONLY));
ScopedFdCloser old_fd_closer(&old_fd);
EXPECT_EQ(0, bm_.AddDiskBlock(old_fd, 0));
@@ -107,18 +93,18 @@
string old_contents(10 * block_size_, '\0');
for (size_t i = 0; i < old_contents.size(); ++i)
old_contents[i] = 4 + i / block_size_;
- test_utils::WriteFileString(old_part_path_, old_contents);
+ test_utils::WriteFileString(old_part_.path(), old_contents);
// A string including the block with all zeros and overlapping some of the
// other blocks in old_contents.
string new_contents(6 * block_size_, '\0');
for (size_t i = 0; i < new_contents.size(); ++i)
new_contents[i] = i / block_size_;
- test_utils::WriteFileString(new_part_path_, new_contents);
+ test_utils::WriteFileString(new_part_.path(), new_contents);
vector<BlockMapping::BlockId> old_ids, new_ids;
- EXPECT_TRUE(MapPartitionBlocks(old_part_path_,
- new_part_path_,
+ EXPECT_TRUE(MapPartitionBlocks(old_part_.path(),
+ new_part_.path(),
old_contents.size(),
new_contents.size(),
block_size_,
diff --git a/payload_generator/boot_img_filesystem.cc b/payload_generator/boot_img_filesystem.cc
new file mode 100644
index 0000000..90be966
--- /dev/null
+++ b/payload_generator/boot_img_filesystem.cc
@@ -0,0 +1,110 @@
+//
+// Copyright (C) 2018 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/payload_generator/boot_img_filesystem.h"
+
+#include <base/logging.h>
+#include <brillo/secure_blob.h>
+#include <puffin/utils.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+unique_ptr<BootImgFilesystem> BootImgFilesystem::CreateFromFile(
+ const string& filename) {
+ if (filename.empty())
+ return nullptr;
+
+ brillo::Blob header;
+ if (!utils::ReadFileChunk(filename, 0, sizeof(boot_img_hdr), &header) ||
+ header.size() != sizeof(boot_img_hdr) ||
+ memcmp(header.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE) != 0) {
+ return nullptr;
+ }
+
+ unique_ptr<BootImgFilesystem> result(new BootImgFilesystem());
+ result->filename_ = filename;
+ memcpy(&result->hdr_, header.data(), header.size());
+ return result;
+}
+
+size_t BootImgFilesystem::GetBlockSize() const {
+ // Page size may not be 4K, but we currently only support 4K block size.
+ return kBlockSize;
+}
+
+size_t BootImgFilesystem::GetBlockCount() const {
+ return utils::DivRoundUp(utils::FileSize(filename_), kBlockSize);
+}
+
+FilesystemInterface::File BootImgFilesystem::GetFile(const string& name,
+ uint64_t offset,
+ uint64_t size) const {
+ File file;
+ file.name = name;
+ file.extents = {ExtentForBytes(kBlockSize, offset, size)};
+
+ brillo::Blob data;
+ if (utils::ReadFileChunk(filename_, offset, size, &data)) {
+ constexpr size_t kGZipHeaderSize = 10;
+ // Check GZip header magic.
+ if (data.size() > kGZipHeaderSize && data[0] == 0x1F && data[1] == 0x8B) {
+ if (!puffin::LocateDeflatesInGzip(data, &file.deflates)) {
+ // We still use the deflates found even if LocateDeflatesInGzip() fails,
+ // if any deflates are returned, they should be correct, it's possible
+ // something went wrong later but it shouldn't stop us from using the
+ // previous deflates. Another common case is if there's more data after
+ // the gzip, the function will try to parse that as another gzip and
+ // will fail, but we still want the deflates from the first gzip.
+ LOG(WARNING) << "Error occurred parsing gzip " << name << " at offset "
+ << offset << " of " << filename_ << ", found "
+ << file.deflates.size() << " deflates.";
+ }
+ for (auto& deflate : file.deflates) {
+ deflate.offset += offset * 8;
+ }
+ }
+ }
+ return file;
+}
+
+bool BootImgFilesystem::GetFiles(vector<File>* files) const {
+ files->clear();
+ const uint64_t file_size = utils::FileSize(filename_);
+ // The first page is header.
+ uint64_t offset = hdr_.page_size;
+ if (hdr_.kernel_size > 0 && offset + hdr_.kernel_size <= file_size) {
+ files->emplace_back(GetFile("<kernel>", offset, hdr_.kernel_size));
+ }
+ offset += utils::RoundUp(hdr_.kernel_size, hdr_.page_size);
+ if (hdr_.ramdisk_size > 0 && offset + hdr_.ramdisk_size <= file_size) {
+ files->emplace_back(GetFile("<ramdisk>", offset, hdr_.ramdisk_size));
+ }
+ return true;
+}
+
+bool BootImgFilesystem::LoadSettings(brillo::KeyValueStore* store) const {
+ return false;
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_generator/boot_img_filesystem.h b/payload_generator/boot_img_filesystem.h
new file mode 100644
index 0000000..87725d4
--- /dev/null
+++ b/payload_generator/boot_img_filesystem.h
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2018 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_PAYLOAD_GENERATOR_BOOT_IMG_FILESYSTEM_H_
+#define UPDATE_ENGINE_PAYLOAD_GENERATOR_BOOT_IMG_FILESYSTEM_H_
+
+#include "update_engine/payload_generator/filesystem_interface.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace chromeos_update_engine {
+
+class BootImgFilesystem : public FilesystemInterface {
+ public:
+ // Creates an BootImgFilesystem from an Android boot.img file.
+ static std::unique_ptr<BootImgFilesystem> CreateFromFile(
+ const std::string& filename);
+ ~BootImgFilesystem() override = default;
+
+ // FilesystemInterface overrides.
+ size_t GetBlockSize() const override;
+ size_t GetBlockCount() const override;
+
+ // GetFiles will return one FilesystemInterface::File for kernel and one for
+ // ramdisk.
+ bool GetFiles(std::vector<File>* files) const override;
+
+ bool LoadSettings(brillo::KeyValueStore* store) const override;
+
+ private:
+ friend class BootImgFilesystemTest;
+
+ BootImgFilesystem() = default;
+
+ File GetFile(const std::string& name, uint64_t offset, uint64_t size) const;
+
+ // The boot.img file path.
+ std::string filename_;
+
+// https://android.googlesource.com/platform/system/core/+/master/mkbootimg/include/bootimg/bootimg.h
+#define BOOT_MAGIC "ANDROID!"
+#define BOOT_MAGIC_SIZE 8
+ struct boot_img_hdr {
+ // Must be BOOT_MAGIC.
+ uint8_t magic[BOOT_MAGIC_SIZE];
+ uint32_t kernel_size; /* size in bytes */
+ uint32_t kernel_addr; /* physical load addr */
+ uint32_t ramdisk_size; /* size in bytes */
+ uint32_t ramdisk_addr; /* physical load addr */
+ uint32_t second_size; /* size in bytes */
+ uint32_t second_addr; /* physical load addr */
+ uint32_t tags_addr; /* physical addr for kernel tags */
+ uint32_t page_size; /* flash page size we assume */
+ } __attribute__((packed));
+ // The boot image header.
+ boot_img_hdr hdr_;
+
+ DISALLOW_COPY_AND_ASSIGN(BootImgFilesystem);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_PAYLOAD_GENERATOR_BOOT_IMG_FILESYSTEM_H_
diff --git a/payload_generator/boot_img_filesystem_unittest.cc b/payload_generator/boot_img_filesystem_unittest.cc
new file mode 100644
index 0000000..b1e0d99
--- /dev/null
+++ b/payload_generator/boot_img_filesystem_unittest.cc
@@ -0,0 +1,117 @@
+//
+// Copyright (C) 2018 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/payload_generator/boot_img_filesystem.h"
+
+#include <vector>
+
+#include <brillo/secure_blob.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/utils.h"
+
+namespace chromeos_update_engine {
+
+using std::unique_ptr;
+using std::vector;
+
+class BootImgFilesystemTest : public ::testing::Test {
+ protected:
+ brillo::Blob GetBootImg(const brillo::Blob& kernel,
+ const brillo::Blob& ramdisk) {
+ brillo::Blob boot_img(16 * 1024);
+ BootImgFilesystem::boot_img_hdr hdr;
+ memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
+ hdr.kernel_size = kernel.size();
+ hdr.ramdisk_size = ramdisk.size();
+ hdr.page_size = 4096;
+ size_t offset = 0;
+ memcpy(boot_img.data() + offset, &hdr, sizeof(hdr));
+ offset += utils::RoundUp(sizeof(hdr), hdr.page_size);
+ memcpy(boot_img.data() + offset, kernel.data(), kernel.size());
+ offset += utils::RoundUp(kernel.size(), hdr.page_size);
+ memcpy(boot_img.data() + offset, ramdisk.data(), ramdisk.size());
+ return boot_img;
+ }
+
+ test_utils::ScopedTempFile boot_file_;
+};
+
+TEST_F(BootImgFilesystemTest, SimpleTest) {
+ test_utils::WriteFileVector(
+ boot_file_.path(),
+ GetBootImg(brillo::Blob(1234, 'k'), brillo::Blob(5678, 'r')));
+ unique_ptr<BootImgFilesystem> fs =
+ BootImgFilesystem::CreateFromFile(boot_file_.path());
+ EXPECT_NE(nullptr, fs);
+
+ vector<FilesystemInterface::File> files;
+ EXPECT_TRUE(fs->GetFiles(&files));
+ ASSERT_EQ(2u, files.size());
+
+ EXPECT_EQ("<kernel>", files[0].name);
+ EXPECT_EQ(1u, files[0].extents.size());
+ EXPECT_EQ(1u, files[0].extents[0].start_block());
+ EXPECT_EQ(1u, files[0].extents[0].num_blocks());
+ EXPECT_TRUE(files[0].deflates.empty());
+
+ EXPECT_EQ("<ramdisk>", files[1].name);
+ EXPECT_EQ(1u, files[1].extents.size());
+ EXPECT_EQ(2u, files[1].extents[0].start_block());
+ EXPECT_EQ(2u, files[1].extents[0].num_blocks());
+ EXPECT_TRUE(files[1].deflates.empty());
+}
+
+TEST_F(BootImgFilesystemTest, BadImageTest) {
+ brillo::Blob boot_img = GetBootImg({}, {});
+ boot_img[7] = '?';
+ test_utils::WriteFileVector(boot_file_.path(), boot_img);
+ unique_ptr<BootImgFilesystem> fs =
+ BootImgFilesystem::CreateFromFile(boot_file_.path());
+ EXPECT_EQ(nullptr, fs);
+}
+
+TEST_F(BootImgFilesystemTest, GZipRamdiskTest) {
+ // echo ramdisk | gzip | hexdump -v -e '/1 "0x%02x, "'
+ const brillo::Blob ramdisk = {0x1f, 0x8b, 0x08, 0x00, 0x3a, 0x83, 0x35,
+ 0x5b, 0x00, 0x03, 0x2b, 0x4a, 0xcc, 0x4d,
+ 0xc9, 0x2c, 0xce, 0xe6, 0x02, 0x00, 0x2e,
+ 0xf6, 0x0b, 0x08, 0x08, 0x00, 0x00, 0x00};
+ test_utils::WriteFileVector(boot_file_.path(),
+ GetBootImg(brillo::Blob(5678, 'k'), ramdisk));
+ unique_ptr<BootImgFilesystem> fs =
+ BootImgFilesystem::CreateFromFile(boot_file_.path());
+ EXPECT_NE(nullptr, fs);
+
+ vector<FilesystemInterface::File> files;
+ EXPECT_TRUE(fs->GetFiles(&files));
+ ASSERT_EQ(2u, files.size());
+
+ EXPECT_EQ("<kernel>", files[0].name);
+ EXPECT_EQ(1u, files[0].extents.size());
+ EXPECT_EQ(1u, files[0].extents[0].start_block());
+ EXPECT_EQ(2u, files[0].extents[0].num_blocks());
+ EXPECT_TRUE(files[0].deflates.empty());
+
+ EXPECT_EQ("<ramdisk>", files[1].name);
+ EXPECT_EQ(1u, files[1].extents.size());
+ EXPECT_EQ(3u, files[1].extents[0].start_block());
+ EXPECT_EQ(1u, files[1].extents[0].num_blocks());
+ EXPECT_EQ(1u, files[1].deflates.size());
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_generator/extent_ranges.cc b/payload_generator/extent_ranges.cc
index c1d3d63..41e8f76 100644
--- a/payload_generator/extent_ranges.cc
+++ b/payload_generator/extent_ranges.cc
@@ -227,6 +227,14 @@
return ret;
}
+Extent ExtentForBytes(uint64_t block_size,
+ uint64_t start_bytes,
+ uint64_t size_bytes) {
+ uint64_t start_block = start_bytes / block_size;
+ uint64_t end_block = utils::DivRoundUp(start_bytes + size_bytes, block_size);
+ return ExtentForRange(start_block, end_block - start_block);
+}
+
vector<Extent> ExtentRanges::GetExtentsForBlockCount(
uint64_t count) const {
vector<Extent> out;
diff --git a/payload_generator/extent_ranges.h b/payload_generator/extent_ranges.h
index 198c834..02cf8fc 100644
--- a/payload_generator/extent_ranges.h
+++ b/payload_generator/extent_ranges.h
@@ -41,6 +41,9 @@
};
Extent ExtentForRange(uint64_t start_block, uint64_t num_blocks);
+Extent ExtentForBytes(uint64_t block_size,
+ uint64_t start_bytes,
+ uint64_t size_bytes);
class ExtentRanges {
public:
diff --git a/payload_generator/full_update_generator.cc b/payload_generator/full_update_generator.cc
index 482a789..98bb0f3 100644
--- a/payload_generator/full_update_generator.cc
+++ b/payload_generator/full_update_generator.cc
@@ -152,7 +152,7 @@
// We potentially have all the ChunkProcessors in memory but only
// |max_threads| will actually hold a block in memory while we process.
size_t partition_blocks = new_part.size / config.block_size;
- size_t num_chunks = (partition_blocks + chunk_blocks - 1) / chunk_blocks;
+ size_t num_chunks = utils::DivRoundUp(partition_blocks, chunk_blocks);
aops->resize(num_chunks);
vector<ChunkProcessor> chunk_processors;
chunk_processors.reserve(num_chunks);
diff --git a/payload_generator/full_update_generator_unittest.cc b/payload_generator/full_update_generator_unittest.cc
index 6da4d10..e398125 100644
--- a/payload_generator/full_update_generator_unittest.cc
+++ b/payload_generator/full_update_generator_unittest.cc
@@ -40,15 +40,11 @@
config_.hard_chunk_size = 128 * 1024;
config_.block_size = 4096;
- EXPECT_TRUE(utils::MakeTempFile("FullUpdateTest_partition.XXXXXX",
- &new_part_conf.path,
- nullptr));
- EXPECT_TRUE(utils::MakeTempFile("FullUpdateTest_blobs.XXXXXX",
- &out_blobs_path_,
- &out_blobs_fd_));
+ new_part_conf.path = part_file_.path();
+ EXPECT_TRUE(utils::MakeTempFile(
+ "FullUpdateTest_blobs.XXXXXX", &out_blobs_path_, &out_blobs_fd_));
blob_file_.reset(new BlobFileWriter(out_blobs_fd_, &out_blobs_length_));
- part_path_unlinker_.reset(new ScopedPathUnlinker(new_part_conf.path));
out_blobs_unlinker_.reset(new ScopedPathUnlinker(out_blobs_path_));
}
@@ -62,9 +58,9 @@
int out_blobs_fd_{-1};
off_t out_blobs_length_{0};
ScopedFdCloser out_blobs_fd_closer_{&out_blobs_fd_};
+ test_utils::ScopedTempFile part_file_{"FullUpdateTest_partition.XXXXXX"};
std::unique_ptr<BlobFileWriter> blob_file_;
- std::unique_ptr<ScopedPathUnlinker> part_path_unlinker_;
std::unique_ptr<ScopedPathUnlinker> out_blobs_unlinker_;
// FullUpdateGenerator under test.
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index cd08118..b842f33 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -339,6 +339,10 @@
DEFINE_string(properties_file, "",
"If passed, dumps the payload properties of the payload passed "
"in --in_file and exits.");
+ DEFINE_int64(max_timestamp,
+ 0,
+ "The maximum timestamp of the OS allowed to apply this "
+ "payload.");
DEFINE_string(old_channel, "",
"The channel for the old image. 'dev-channel', 'npo-channel', "
@@ -583,6 +587,8 @@
LOG(INFO) << "Using provided minor_version=" << FLAGS_minor_version;
}
+ payload_config.max_timestamp = FLAGS_max_timestamp;
+
LOG(INFO) << "Generating " << (payload_config.is_delta ? "delta" : "full")
<< " update";
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index a9e32a3..d5c59ce 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -73,6 +73,7 @@
*(manifest_.mutable_new_image_info()) = config.target.image_info;
manifest_.set_block_size(config.block_size);
+ manifest_.set_max_timestamp(config.max_timestamp);
return true;
}
diff --git a/payload_generator/payload_file_unittest.cc b/payload_generator/payload_file_unittest.cc
index e8e7e14..45faebb9 100644
--- a/payload_generator/payload_file_unittest.cc
+++ b/payload_generator/payload_file_unittest.cc
@@ -36,23 +36,16 @@
};
TEST_F(PayloadFileTest, ReorderBlobsTest) {
- string orig_blobs;
- EXPECT_TRUE(utils::MakeTempFile("ReorderBlobsTest.orig.XXXXXX", &orig_blobs,
- nullptr));
- ScopedPathUnlinker orig_blobs_unlinker(orig_blobs);
+ test_utils::ScopedTempFile orig_blobs("ReorderBlobsTest.orig.XXXXXX");
// The operations have three blob and one gap (the whitespace):
// Rootfs operation 1: [8, 3] bcd
// Rootfs operation 2: [7, 1] a
// Kernel operation 1: [0, 6] kernel
string orig_data = "kernel abcd";
- EXPECT_TRUE(
- utils::WriteFile(orig_blobs.c_str(), orig_data.data(), orig_data.size()));
+ EXPECT_TRUE(test_utils::WriteFileString(orig_blobs.path(), orig_data));
- string new_blobs;
- EXPECT_TRUE(
- utils::MakeTempFile("ReorderBlobsTest.new.XXXXXX", &new_blobs, nullptr));
- ScopedPathUnlinker new_blobs_unlinker(new_blobs);
+ test_utils::ScopedTempFile new_blobs("ReorderBlobsTest.new.XXXXXX");
payload_.part_vec_.resize(2);
@@ -71,12 +64,12 @@
aop.op.set_data_length(6);
payload_.part_vec_[1].aops = {aop};
- EXPECT_TRUE(payload_.ReorderDataBlobs(orig_blobs, new_blobs));
+ EXPECT_TRUE(payload_.ReorderDataBlobs(orig_blobs.path(), new_blobs.path()));
const vector<AnnotatedOperation>& part0_aops = payload_.part_vec_[0].aops;
const vector<AnnotatedOperation>& part1_aops = payload_.part_vec_[1].aops;
string new_data;
- EXPECT_TRUE(utils::ReadFile(new_blobs, &new_data));
+ EXPECT_TRUE(utils::ReadFile(new_blobs.path(), &new_data));
// Kernel blobs should appear at the end.
EXPECT_EQ("bcdakernel", new_data);
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index 1f65b24..5fe56b5 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -20,6 +20,7 @@
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/delta_performer.h"
+#include "update_engine/payload_generator/boot_img_filesystem.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
#include "update_engine/payload_generator/delta_diff_utils.h"
#include "update_engine/payload_generator/ext2_filesystem.h"
@@ -64,6 +65,12 @@
}
}
+ fs_interface = BootImgFilesystem::CreateFromFile(path);
+ if (fs_interface) {
+ TEST_AND_RETURN_FALSE(fs_interface->GetBlockSize() == kBlockSize);
+ return true;
+ }
+
// Fall back to a RAW filesystem.
TEST_AND_RETURN_FALSE(size % kBlockSize == 0);
fs_interface = RawFilesystem::Create(
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index d64bf35..358a76d 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -186,6 +186,9 @@
// The block size used for all the operations in the manifest.
size_t block_size = 4096;
+
+ // The maximum timestamp of the OS allowed to apply this payload.
+ int64_t max_timestamp = 0;
};
} // namespace chromeos_update_engine
diff --git a/payload_generator/payload_signer.cc b/payload_generator/payload_signer.cc
index 0b47dd4..8eba2dc 100644
--- a/payload_generator/payload_signer.cc
+++ b/payload_generator/payload_signer.cc
@@ -231,8 +231,8 @@
Extent* dummy_extent = dummy_op->add_dst_extents();
// Tell the dummy op to write this data to a big sparse hole
dummy_extent->set_start_block(kSparseHole);
- dummy_extent->set_num_blocks((signature_blob_length + kBlockSize - 1) /
- kBlockSize);
+ dummy_extent->set_num_blocks(
+ utils::DivRoundUp(signature_blob_length, kBlockSize));
}
}
diff --git a/payload_generator/payload_signer_unittest.cc b/payload_generator/payload_signer_unittest.cc
index 62b6e7a..fc0925a 100644
--- a/payload_generator/payload_signer_unittest.cc
+++ b/payload_generator/payload_signer_unittest.cc
@@ -127,16 +127,14 @@
void DoWriteAndLoadPayloadTest(const PayloadGenerationConfig& config) {
PayloadFile payload;
payload.Init(config);
- string payload_path;
- EXPECT_TRUE(utils::MakeTempFile("payload.XXXXXX", &payload_path, nullptr));
- ScopedPathUnlinker payload_path_unlinker(payload_path);
+ test_utils::ScopedTempFile payload_file("payload.XXXXXX");
uint64_t metadata_size;
- EXPECT_TRUE(
- payload.WritePayload(payload_path, "/dev/null", "", &metadata_size));
+ EXPECT_TRUE(payload.WritePayload(
+ payload_file.path(), "/dev/null", "", &metadata_size));
brillo::Blob payload_metadata_blob;
DeltaArchiveManifest manifest;
uint64_t load_metadata_size, load_major_version;
- EXPECT_TRUE(PayloadSigner::LoadPayloadMetadata(payload_path,
+ EXPECT_TRUE(PayloadSigner::LoadPayloadMetadata(payload_file.path(),
&payload_metadata_blob,
&manifest,
&load_major_version,
@@ -215,50 +213,46 @@
}
TEST_F(PayloadSignerTest, SkipMetadataSignatureTest) {
- string payload_path;
- EXPECT_TRUE(utils::MakeTempFile("payload.XXXXXX", &payload_path, nullptr));
- ScopedPathUnlinker payload_path_unlinker(payload_path);
-
+ test_utils::ScopedTempFile payload_file("payload.XXXXXX");
PayloadGenerationConfig config;
config.version.major = kBrilloMajorPayloadVersion;
PayloadFile payload;
EXPECT_TRUE(payload.Init(config));
uint64_t metadata_size;
- EXPECT_TRUE(
- payload.WritePayload(payload_path, "/dev/null", "", &metadata_size));
+ EXPECT_TRUE(payload.WritePayload(
+ payload_file.path(), "/dev/null", "", &metadata_size));
const vector<int> sizes = {256};
brillo::Blob unsigned_payload_hash, unsigned_metadata_hash;
- EXPECT_TRUE(PayloadSigner::HashPayloadForSigning(
- payload_path, sizes, &unsigned_payload_hash, &unsigned_metadata_hash));
+ EXPECT_TRUE(PayloadSigner::HashPayloadForSigning(payload_file.path(),
+ sizes,
+ &unsigned_payload_hash,
+ &unsigned_metadata_hash));
EXPECT_TRUE(
- payload.WritePayload(payload_path,
+ payload.WritePayload(payload_file.path(),
"/dev/null",
GetBuildArtifactsPath(kUnittestPrivateKeyPath),
&metadata_size));
brillo::Blob signed_payload_hash, signed_metadata_hash;
EXPECT_TRUE(PayloadSigner::HashPayloadForSigning(
- payload_path, sizes, &signed_payload_hash, &signed_metadata_hash));
+ payload_file.path(), sizes, &signed_payload_hash, &signed_metadata_hash));
EXPECT_EQ(unsigned_payload_hash, signed_payload_hash);
EXPECT_EQ(unsigned_metadata_hash, signed_metadata_hash);
}
TEST_F(PayloadSignerTest, VerifySignedPayloadTest) {
- string payload_path;
- EXPECT_TRUE(utils::MakeTempFile("payload.XXXXXX", &payload_path, nullptr));
- ScopedPathUnlinker payload_path_unlinker(payload_path);
-
+ test_utils::ScopedTempFile payload_file("payload.XXXXXX");
PayloadGenerationConfig config;
config.version.major = kBrilloMajorPayloadVersion;
PayloadFile payload;
EXPECT_TRUE(payload.Init(config));
uint64_t metadata_size;
EXPECT_TRUE(
- payload.WritePayload(payload_path,
+ payload.WritePayload(payload_file.path(),
"/dev/null",
GetBuildArtifactsPath(kUnittestPrivateKeyPath),
&metadata_size));
EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
- payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
+ payload_file.path(), GetBuildArtifactsPath(kUnittestPublicKeyPath)));
}
} // namespace chromeos_update_engine
diff --git a/payload_generator/squashfs_filesystem.cc b/payload_generator/squashfs_filesystem.cc
index c98ad12..6c892f5 100644
--- a/payload_generator/squashfs_filesystem.cc
+++ b/payload_generator/squashfs_filesystem.cc
@@ -44,14 +44,6 @@
namespace {
-Extent ExtentForBytes(uint64_t block_size,
- uint64_t start_bytes,
- uint64_t size_bytes) {
- uint64_t start_block = start_bytes / block_size;
- uint64_t end_block = (start_bytes + size_bytes + block_size - 1) / block_size;
- return ExtentForRange(start_block, end_block - start_block);
-}
-
// The size of the squashfs super block.
constexpr size_t kSquashfsSuperBlockSize = 96;
constexpr uint64_t kSquashfsCompressedBit = 1 << 24;
@@ -192,8 +184,7 @@
for (const auto& file : files_) {
file_extents.AddExtents(file.extents);
}
- vector<Extent> full = {
- ExtentForRange(0, (size_ + kBlockSize - 1) / kBlockSize)};
+ vector<Extent> full = {ExtentForBytes(kBlockSize, 0, size_)};
auto metadata_extents = FilterExtentRanges(full, file_extents);
// For now there should be at most two extents. One for superblock and one for
// metadata at the end. Just create appropriate files with <metadata-i> name.
diff --git a/payload_generator/xz_android.cc b/payload_generator/xz_android.cc
index b2b74b1..41c55f7 100644
--- a/payload_generator/xz_android.cc
+++ b/payload_generator/xz_android.cc
@@ -16,12 +16,14 @@
#include "update_engine/payload_generator/xz.h"
-#include <7zCrc.h>
-#include <Xz.h>
-#include <XzEnc.h>
+#include <elf.h>
+#include <endian.h>
#include <algorithm>
+#include <7zCrc.h>
+#include <Xz.h>
+#include <XzEnc.h>
#include <base/logging.h>
namespace {
@@ -67,6 +69,37 @@
brillo::Blob* data_;
};
+// Returns the filter id to be used to compress |data|.
+// Only BCJ filter for x86 and ARM ELF file are supported, returns 0 otherwise.
+int GetFilterID(const brillo::Blob& data) {
+ if (data.size() < sizeof(Elf32_Ehdr) ||
+ memcmp(data.data(), ELFMAG, SELFMAG) != 0)
+ return 0;
+
+ const Elf32_Ehdr* header = reinterpret_cast<const Elf32_Ehdr*>(data.data());
+
+ // Only little-endian is supported.
+ if (header->e_ident[EI_DATA] != ELFDATA2LSB)
+ return 0;
+
+ switch (le16toh(header->e_machine)) {
+ case EM_386:
+ case EM_X86_64:
+ return XZ_ID_X86;
+ case EM_ARM:
+ // Both ARM and ARM Thumb instructions could be found in the same ARM ELF
+ // file. We choose to use the ARM Thumb filter here because testing shows
+ // that it usually works better than the ARM filter.
+ return XZ_ID_ARMT;
+#ifdef EM_AARCH64
+ case EM_AARCH64:
+ // Neither the ARM nor the ARM Thumb filter works well with AArch64.
+ return 0;
+#endif
+ }
+ return 0;
+}
+
} // namespace
namespace chromeos_update_engine {
@@ -107,6 +140,8 @@
Lzma2EncProps_Normalize(&lzma2Props);
props.lzma2Props = lzma2Props;
+ props.filterProps.id = GetFilterID(in);
+
BlobWriterStream out_writer(out);
BlobReaderStream in_reader(in);
SRes res = Xz_Encode(&out_writer, &in_reader, &props, nullptr /* progress */);
diff --git a/payload_generator/zip_unittest.cc b/payload_generator/zip_unittest.cc
index 5b0d5da..29f16d3 100644
--- a/payload_generator/zip_unittest.cc
+++ b/payload_generator/zip_unittest.cc
@@ -135,7 +135,7 @@
brillo::Blob decompressed;
EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
EXPECT_EQ(in.size(), decompressed.size());
- EXPECT_TRUE(!memcmp(in.data(), decompressed.data(), in.size()));
+ EXPECT_EQ(0, memcmp(in.data(), decompressed.data(), in.size()));
}
TYPED_TEST(ZipTest, PoorCompressionTest) {
@@ -165,4 +165,18 @@
EXPECT_EQ(0U, out.size());
}
+TYPED_TEST(ZipTest, CompressELFTest) {
+ string path = test_utils::GetBuildArtifactsPath("delta_generator");
+ brillo::Blob in;
+ utils::ReadFile(path, &in);
+ brillo::Blob out;
+ EXPECT_TRUE(this->ZipCompress(in, &out));
+ EXPECT_LT(out.size(), in.size());
+ EXPECT_GT(out.size(), 0U);
+ brillo::Blob decompressed;
+ EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
+ EXPECT_EQ(in.size(), decompressed.size());
+ EXPECT_EQ(0, memcmp(in.data(), decompressed.data(), in.size()));
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_state.cc b/payload_state.cc
index 4670b14..c4eb950 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -304,6 +304,7 @@
case ErrorCode::kPayloadMismatchedType:
case ErrorCode::kUnsupportedMajorPayloadVersion:
case ErrorCode::kUnsupportedMinorPayloadVersion:
+ case ErrorCode::kPayloadTimestampError:
IncrementUrlIndex();
break;
diff --git a/proxy_resolver_unittest.cc b/proxy_resolver_unittest.cc
index 070b361..484aae1 100644
--- a/proxy_resolver_unittest.cc
+++ b/proxy_resolver_unittest.cc
@@ -22,7 +22,6 @@
#include <gtest/gtest.h>
#include <base/bind.h>
-#include <brillo/bind_lambda.h>
#include <brillo/message_loops/fake_message_loop.h>
using std::deque;
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index b256b36..531a1bd 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -178,6 +178,10 @@
"Optional: Path to a source image. If specified, this makes a delta update."
DEFINE_string metadata_size_file "" \
"Optional: Path to output metadata size."
+ DEFINE_string max_timestamp "" \
+ "Optional: The maximum unix timestamp of the OS allowed to apply this \
+payload, should be set to a number higher than the build timestamp of the \
+system running on the device, 0 if not specified."
fi
if [[ "${COMMAND}" == "hash" || "${COMMAND}" == "sign" ]]; then
DEFINE_string unsigned_payload "" "Path to the input unsigned payload."
@@ -604,6 +608,10 @@
GENERATOR_ARGS+=( --out_metadata_size_file="${FLAGS_metadata_size_file}" )
fi
+ if [[ -n "${FLAGS_max_timestamp}" ]]; then
+ GENERATOR_ARGS+=( --max_timestamp="${FLAGS_max_timestamp}" )
+ fi
+
if [[ -n "${POSTINSTALL_CONFIG_FILE}" ]]; then
GENERATOR_ARGS+=(
--new_postinstall_config_file="${POSTINSTALL_CONFIG_FILE}"
diff --git a/test_http_server.cc b/test_http_server.cc
index 39a12ed..cf15672 100644
--- a/test_http_server.cc
+++ b/test_http_server.cc
@@ -98,9 +98,11 @@
request->raw_headers = headers;
// Break header into lines.
- vector<string> lines;
- base::SplitStringUsingSubstr(
- headers.substr(0, headers.length() - strlen(EOL EOL)), EOL, &lines);
+ vector<string> lines = base::SplitStringUsingSubstr(
+ headers.substr(0, headers.length() - strlen(EOL EOL)),
+ EOL,
+ base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL);
// Decode URL line.
vector<string> terms = base::SplitString(lines[0], base::kWhitespaceASCII,
diff --git a/update_attempter.cc b/update_attempter.cc
index 71a4ae1..db373ab 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -31,7 +31,6 @@
#include <base/rand_util.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
-#include <brillo/bind_lambda.h>
#include <brillo/data_encoding.h>
#include <brillo/errors/error_codes.h>
#include <brillo/message_loops/message_loop.h>
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 9b0b42a..9443869 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -29,6 +29,7 @@
#include <brillo/data_encoding.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/strings/string_utils.h>
+#include <log/log_safetynet.h>
#include "update_engine/common/constants.h"
#include "update_engine/common/error_code_utils.h"
@@ -138,7 +139,7 @@
return LogAndSetError(
error, FROM_HERE, "An update already applied, waiting for reboot");
}
- if (ongoing_update_) {
+ if (processor_->IsRunning()) {
return LogAndSetError(
error, FROM_HERE, "Already processing an update, cancel it first.");
}
@@ -269,7 +270,6 @@
BuildUpdateActions(fetcher);
SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
- ongoing_update_ = true;
UpdatePrefsOnUpdateStart(install_plan_.is_resume);
// TODO(xunchang) report the metrics for unresumable updates
@@ -279,21 +279,21 @@
}
bool UpdateAttempterAndroid::SuspendUpdate(brillo::ErrorPtr* error) {
- if (!ongoing_update_)
+ if (!processor_->IsRunning())
return LogAndSetError(error, FROM_HERE, "No ongoing update to suspend.");
processor_->SuspendProcessing();
return true;
}
bool UpdateAttempterAndroid::ResumeUpdate(brillo::ErrorPtr* error) {
- if (!ongoing_update_)
+ if (!processor_->IsRunning())
return LogAndSetError(error, FROM_HERE, "No ongoing update to resume.");
processor_->ResumeProcessing();
return true;
}
bool UpdateAttempterAndroid::CancelUpdate(brillo::ErrorPtr* error) {
- if (!ongoing_update_)
+ if (!processor_->IsRunning())
return LogAndSetError(error, FROM_HERE, "No ongoing update to cancel.");
processor_->StopProcessing();
return true;
@@ -457,6 +457,11 @@
LOG(INFO) << "Resetting update progress.";
break;
+ case ErrorCode::kPayloadTimestampError:
+ // SafetyNet logging, b/36232423
+ android_errorWriteLog(0x534e4554, "36232423");
+ break;
+
default:
// Ignore all other error codes.
break;
@@ -558,7 +563,6 @@
(error_code == ErrorCode::kSuccess ? UpdateStatus::UPDATED_NEED_REBOOT
: UpdateStatus::IDLE);
SetStatusAndNotify(new_status);
- ongoing_update_ = false;
// The network id is only applicable to one download attempt and once it's
// done the network id should not be re-used anymore.
diff --git a/update_attempter_android.h b/update_attempter_android.h
index cad89dc..3faeac9 100644
--- a/update_attempter_android.h
+++ b/update_attempter_android.h
@@ -175,11 +175,6 @@
// The processor for running Actions.
std::unique_ptr<ActionProcessor> processor_;
- // Whether there is an ongoing update. This implies that an update was started
- // but not finished yet. This value will be true even if the update was
- // suspended.
- bool ongoing_update_{false};
-
// The InstallPlan used during the ongoing update.
InstallPlan install_plan_;
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 93fcef1..fb9f7bc 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -22,7 +22,6 @@
#include <base/files/file_util.h>
#include <base/message_loop/message_loop.h>
-#include <brillo/bind_lambda.h>
#include <brillo/message_loops/base_message_loop.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/message_loops/message_loop_utils.h>
diff --git a/update_engine.gyp b/update_engine.gyp
index cbdce2b..ee2471a 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -395,6 +395,7 @@
'payload_generator/annotated_operation.cc',
'payload_generator/blob_file_writer.cc',
'payload_generator/block_mapping.cc',
+ 'payload_generator/boot_img_filesystem.cc',
'payload_generator/bzip.cc',
'payload_generator/cycle_breaker.cc',
'payload_generator/deflate_utils.cc',
@@ -548,6 +549,7 @@
'payload_generator/ab_generator_unittest.cc',
'payload_generator/blob_file_writer_unittest.cc',
'payload_generator/block_mapping_unittest.cc',
+ 'payload_generator/boot_img_filesystem_unittest.cc',
'payload_generator/cycle_breaker_unittest.cc',
'payload_generator/deflate_utils_unittest.cc',
'payload_generator/delta_diff_utils_unittest.cc',
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
index abb06c7..71fec40 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -86,6 +86,7 @@
case ErrorCode::kPayloadMismatchedType:
case ErrorCode::kUnsupportedMajorPayloadVersion:
case ErrorCode::kUnsupportedMinorPayloadVersion:
+ case ErrorCode::kPayloadTimestampError:
LOG(INFO) << "Advancing download URL due to error "
<< chromeos_update_engine::utils::ErrorCodeToString(err_code)
<< " (" << static_cast<int>(err_code) << ")";
diff --git a/update_manager/real_shill_provider_unittest.cc b/update_manager/real_shill_provider_unittest.cc
index af674d0..6506923 100644
--- a/update_manager/real_shill_provider_unittest.cc
+++ b/update_manager/real_shill_provider_unittest.cc
@@ -94,7 +94,9 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- return Time::FromLocalExploded(now_exp);
+ Time time;
+ ignore_result(Time::FromLocalExploded(now_exp, &time));
+ return time;
}
Time ConnChangedTime() {
diff --git a/update_manager/real_time_provider.cc b/update_manager/real_time_provider.cc
index 92f985f..baa8ae3 100644
--- a/update_manager/real_time_provider.cc
+++ b/update_manager/real_time_provider.cc
@@ -43,7 +43,10 @@
Time::Exploded now_exp;
clock_->GetWallclockTime().LocalExplode(&now_exp);
now_exp.hour = now_exp.minute = now_exp.second = now_exp.millisecond = 0;
- return new Time(Time::FromLocalExploded(now_exp));
+ Time* now = new Time();
+ bool success = Time::FromLocalExploded(now_exp, now);
+ DCHECK(success);
+ return now;
}
private:
diff --git a/update_manager/real_time_provider_unittest.cc b/update_manager/real_time_provider_unittest.cc
index 093b158..ce2a718 100644
--- a/update_manager/real_time_provider_unittest.cc
+++ b/update_manager/real_time_provider_unittest.cc
@@ -51,7 +51,9 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- return Time::FromLocalExploded(now_exp);
+ Time time;
+ ignore_result(Time::FromLocalExploded(now_exp, &time));
+ return time;
}
FakeClock fake_clock_;
@@ -66,7 +68,8 @@
exploded.minute = 0;
exploded.second = 0;
exploded.millisecond = 0;
- const Time expected = Time::FromLocalExploded(exploded);
+ Time expected;
+ ignore_result(Time::FromLocalExploded(exploded, &expected));
fake_clock_.SetWallclockTime(now);
UmTestUtils::ExpectVariableHasValue(expected, provider_->var_curr_date());
diff --git a/update_manager/real_updater_provider_unittest.cc b/update_manager/real_updater_provider_unittest.cc
index efe042c..b653885 100644
--- a/update_manager/real_updater_provider_unittest.cc
+++ b/update_manager/real_updater_provider_unittest.cc
@@ -57,7 +57,9 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- return Time::FromLocalExploded(now_exp);
+ Time time;
+ ignore_result(Time::FromLocalExploded(now_exp, &time));
+ return time;
}
// Rounds down a timestamp to the nearest second. This is useful when faking
@@ -66,7 +68,9 @@
Time::Exploded exp;
time.LocalExplode(&exp);
exp.millisecond = 0;
- return Time::FromLocalExploded(exp);
+ Time rounded_time;
+ ignore_result(Time::FromLocalExploded(exp, &rounded_time));
+ return rounded_time;
}
ACTION_P(ActionSetUpdateEngineStatusLastCheckedTime, time) {
diff --git a/update_manager/update_manager_unittest.cc b/update_manager/update_manager_unittest.cc
index 9625b53..125a60c 100644
--- a/update_manager/update_manager_unittest.cc
+++ b/update_manager/update_manager_unittest.cc
@@ -67,7 +67,9 @@
now_exp.minute = 5;
now_exp.second = 33;
now_exp.millisecond = 675;
- return Time::FromLocalExploded(now_exp);
+ Time time;
+ ignore_result(Time::FromLocalExploded(now_exp, &time));
+ return time;
}
} // namespace
diff --git a/update_manager/update_time_restrictions_policy_impl_unittest.cc b/update_manager/update_time_restrictions_policy_impl_unittest.cc
index ac4e0e9..74e7f3c 100644
--- a/update_manager/update_time_restrictions_policy_impl_unittest.cc
+++ b/update_manager/update_time_restrictions_policy_impl_unittest.cc
@@ -57,7 +57,10 @@
fake_state_.device_policy_provider()
->var_auto_launched_kiosk_app_id()
->reset(new string("myapp"));
- fake_clock_.SetWallclockTime(Time::FromLocalExploded(exploded));
+
+ Time time;
+ EXPECT_TRUE(Time::FromLocalExploded(exploded, &time));
+ fake_clock_.SetWallclockTime(time);
SetUpDefaultTimeProvider();
fake_state_.device_policy_provider()
->var_disallowed_time_intervals()
diff --git a/update_metadata.proto b/update_metadata.proto
index fe81efb..a0f278b 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -290,4 +290,8 @@
// array can have more than two partitions if needed, and they are identified
// by the partition name.
repeated PartitionUpdate partitions = 13;
+
+ // The maximum timestamp of the OS allowed to apply this payload.
+ // Can be used to prevent downgrading the OS.
+ optional int64 max_timestamp = 14;
}