Add UpdateAttempterIntegrationTesting
Test: th
Bug: 201099341
Change-Id: I46d5ad86e238d28b7c20ef6768ffadf0e6ab9177
diff --git a/Android.bp b/Android.bp
index cbd87bc..ac94229 100644
--- a/Android.bp
+++ b/Android.bp
@@ -850,6 +850,7 @@
"aosp/apex_handler_android_unittest.cc",
"aosp/cleanup_previous_update_action_unittest.cc",
"aosp/dynamic_partition_control_android_unittest.cc",
+ "aosp/update_attempter_android_integration_test.cc",
"aosp/update_attempter_android_unittest.cc",
"certificate_checker_unittest.cc",
"common/http_fetcher_unittest.cc",
diff --git a/aosp/boot_control_android.h b/aosp/boot_control_android.h
index a65aa2e..9012032 100644
--- a/aosp/boot_control_android.h
+++ b/aosp/boot_control_android.h
@@ -23,6 +23,7 @@
#include <android/hardware/boot/1.0/IBootControl.h>
#include <liblp/builder.h>
+#include <gtest/gtest_prod.h>
#include "update_engine/aosp/dynamic_partition_control_android.h"
#include "update_engine/common/boot_control.h"
@@ -32,7 +33,7 @@
// The Android implementation of the BootControlInterface. This implementation
// uses the libhardware's boot_control HAL to access the bootloader.
-class BootControlAndroid : public BootControlInterface {
+class BootControlAndroid final : public BootControlInterface {
public:
BootControlAndroid() = default;
~BootControlAndroid() = default;
@@ -70,6 +71,7 @@
std::unique_ptr<DynamicPartitionControlAndroid> dynamic_control_;
friend class BootControlAndroidTest;
+ friend class UpdateAttempterAndroidIntegrationTest;
DISALLOW_COPY_AND_ASSIGN(BootControlAndroid);
};
diff --git a/aosp/dynamic_partition_control_android.h b/aosp/dynamic_partition_control_android.h
index df91401..ad3e056 100644
--- a/aosp/dynamic_partition_control_android.h
+++ b/aosp/dynamic_partition_control_android.h
@@ -114,6 +114,8 @@
bool UpdateUsesSnapshotCompression() override;
+ std::optional<base::FilePath> GetSuperDevice();
+
protected:
// These functions are exposed for testing.
@@ -234,8 +236,6 @@
friend class DynamicPartitionControlAndroidTest;
friend class SnapshotPartitionTestP;
- std::optional<base::FilePath> GetSuperDevice();
-
bool MapPartitionInternal(const std::string& super_device,
const std::string& target_partition_name,
uint32_t slot,
diff --git a/aosp/update_attempter_android_integration_test.cc b/aosp/update_attempter_android_integration_test.cc
new file mode 100644
index 0000000..de42623
--- /dev/null
+++ b/aosp/update_attempter_android_integration_test.cc
@@ -0,0 +1,266 @@
+//
+// Copyright (C) 2021 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 <memory>
+#include <string>
+#include <utility>
+
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#include <brillo/data_encoding.h>
+#include <brillo/message_loops/fake_message_loop.h>
+#include <gtest/gtest.h>
+#include <liblp/builder.h>
+#include <fs_mgr.h>
+#include <liblp/liblp.h>
+
+#include "update_engine/aosp/boot_control_android.h"
+#include "update_engine/aosp/daemon_state_android.h"
+#include "update_engine/aosp/update_attempter_android.h"
+#include "update_engine/common/constants.h"
+#include "update_engine/common/prefs.h"
+#include "update_engine/common/testing_constants.h"
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/common/fake_boot_control.h"
+#include "update_engine/common/fake_hardware.h"
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/payload_file.h"
+#include "update_engine/payload_generator/payload_signer.h"
+#include "update_engine/update_metadata.pb.h"
+#include "update_engine/update_status_utils.h"
+
+namespace chromeos_update_engine {
+
+class UpdateAttempterAndroidIntegrationTest : public ::testing::Test,
+ public ServiceObserverInterface {
+ void AddFakePartitionGroup() {
+ dynamic_control_ = boot_control_.dynamic_control_.get();
+ auto super_device = dynamic_control_->GetSuperDevice();
+ ASSERT_TRUE(super_device.has_value());
+ super_device_ = super_device->value();
+ builder_ = android::fs_mgr::MetadataBuilder::New(
+ super_device->value(), boot_control_.GetCurrentSlot());
+ ASSERT_NE(builder_, nullptr);
+
+ // Remove dangling fake partitions, if test crashed before they might not
+ // get cleaned up properly.
+ RemoveFakePartitionGroup();
+ ASSERT_TRUE(builder_->AddGroup("fake_group", kFakePartitionSize * 2));
+ ExportPartitionTable();
+ }
+ void RemoveFakePartitionGroup() {
+ builder_->RemovePartition("fake_a");
+ builder_->RemovePartition("fake_b");
+ builder_->RemoveGroupAndPartitions("fake_group");
+ }
+ void SetUp() override {
+ ASSERT_TRUE(boot_control_.Init());
+ if (!DynamicPartitionEnabled()) {
+ return;
+ }
+ ASSERT_NO_FATAL_FAILURE(AddFakePartitionGroup());
+ message_loop_.SetAsCurrent();
+ // Set official build to false so that hash checks are non-mandatory
+ hardware_.SetIsOfficialBuild(false);
+ truncate64(blob_file_.path().c_str(), 0);
+
+ update_attempter_android_.set_update_certificates_path(
+ test_utils::GetBuildArtifactsPath(kUnittestOTACertsPath));
+
+ // Basic setup to create VABC OTA
+ manifest_.set_partial_update(true);
+ manifest_.set_minor_version(kPartialUpdateMinorPayloadVersion);
+ auto dap_group =
+ manifest_.mutable_dynamic_partition_metadata()->add_groups();
+ dap_group->set_name("fake_group");
+ dap_group->add_partition_names("fake");
+
+ manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
+ manifest_.mutable_dynamic_partition_metadata()->set_vabc_enabled(true);
+ manifest_.mutable_dynamic_partition_metadata()->set_cow_version(
+ android::snapshot::kCowVersionMajor);
+ }
+ void TearDown() override {
+ if (!builder_ || !DynamicPartitionEnabled()) {
+ return;
+ }
+ auto dynamic_control = boot_control_.GetDynamicPartitionControl();
+ if (dynamic_control) {
+ dynamic_control->UnmapAllPartitions();
+ dynamic_control->ResetUpdate(&prefs_);
+ }
+ RemoveFakePartitionGroup();
+ ExportPartitionTable();
+ }
+
+ void CreateFakePartition() {
+ // Create a fake partition for testing purposes
+ auto partition_a = builder_->AddPartition("fake_a", "fake_group", 0);
+ ASSERT_NE(partition_a, nullptr);
+ ASSERT_TRUE(builder_->ResizePartition(partition_a, kFakePartitionSize));
+ ExportPartitionTable();
+ }
+
+ void SendStatusUpdate(
+ const update_engine::UpdateEngineStatus& update_engine_status) override {
+ LOG(INFO) << UpdateStatusToString(update_engine_status.status) << ", "
+ << update_engine_status.progress;
+ }
+
+ // Called whenever an update attempt is completed.
+ void SendPayloadApplicationComplete(ErrorCode error_code) override {
+ completion_code_ = error_code;
+ }
+
+ void ExportPartitionTable() {
+ auto metadata = builder_->Export();
+ ASSERT_NE(metadata, nullptr);
+ android::fs_mgr::UpdatePartitionTable(
+ super_device_, *metadata, boot_control_.GetCurrentSlot());
+ }
+
+ public:
+ bool DynamicPartitionEnabled() {
+ auto dynamic_control = boot_control_.GetDynamicPartitionControl();
+ return dynamic_control &&
+ dynamic_control->GetDynamicPartitionsFeatureFlag().IsEnabled();
+ }
+ void AddSignatureInfoToPayload(DeltaArchiveManifest* manifest,
+ const std::string& private_key_path) {
+ size_t total_blob_size = 0;
+ for (const auto& part : manifest->partitions()) {
+ for (const auto& op : part.operations()) {
+ if (!op.has_data_offset())
+ continue;
+ ASSERT_EQ(total_blob_size, op.data_offset())
+ << "Ops not ordered by blob isze";
+ total_blob_size += op.data_length();
+ }
+ }
+ // Signatures appear at the end of the blobs. Note the offset in the
+ // |manifest_|.
+ uint64_t signature_blob_length = 0;
+ if (!private_key_path.empty()) {
+ ASSERT_TRUE(PayloadSigner::SignatureBlobLength({private_key_path},
+ &signature_blob_length));
+ PayloadSigner::AddSignatureToManifest(
+ total_blob_size, signature_blob_length, manifest);
+ }
+ }
+ void ApplyPayload(DeltaArchiveManifest* manifest) {
+ ASSERT_FALSE(manifest->partitions().empty());
+ if (manifest->partitions().begin()->has_old_partition_info()) {
+ // Only create fake partition if the update is incremental
+ LOG(INFO) << "Creating fake partition";
+ ASSERT_NO_FATAL_FAILURE(CreateFakePartition());
+ }
+ const auto private_key_path =
+ test_utils::GetBuildArtifactsPath(kUnittestPrivateKeyPath);
+ ASSERT_NO_FATAL_FAILURE(
+ AddSignatureInfoToPayload(manifest, private_key_path));
+
+ brillo::Blob hash;
+ HashCalculator::RawHashOfFile(new_part_.path(), &hash);
+ auto partition = &manifest->mutable_partitions()->at(0);
+ partition->mutable_new_partition_info()->set_size(kFakePartitionSize);
+ partition->mutable_new_partition_info()->set_hash(hash.data(), hash.size());
+ uint64_t metadata_size = 0;
+ ASSERT_TRUE(PayloadFile::WritePayload(payload_file_.path(),
+ blob_file_.path(),
+ private_key_path,
+ kBrilloMajorPayloadVersion,
+ *manifest,
+ &metadata_size));
+ LOG(INFO) << "Signature offset: " << manifest->signatures_offset()
+ << ", Signature size: " << manifest->signatures_size();
+ brillo::ErrorPtr error;
+ HashCalculator::RawHashOfFile(payload_file_.path(), &hash);
+ daemon_state_.AddObserver(this);
+ ASSERT_TRUE(update_attempter_android_.ApplyPayload(
+ "file://" + payload_file_.path(),
+ 0,
+ utils::FileSize(payload_file_.path()),
+ {kPayloadPropertyMetadataSize + ("=" + std::to_string(metadata_size)),
+ kPayloadPropertyFileHash +
+ ("=" + brillo::data_encoding::Base64Encode(hash))},
+ &error));
+ brillo::MessageLoop::current()->Run();
+ if (error) {
+ LOG(ERROR) << error->GetMessage();
+ }
+ ASSERT_EQ(error, nullptr);
+ ASSERT_EQ(completion_code_, ErrorCode::kSuccess);
+ }
+ // use 25MB max to avoid super not having enough space
+ static constexpr size_t kFakePartitionSize = 1024 * 1024 * 25;
+ static_assert(kFakePartitionSize % kBlockSize == 0);
+ BootControlAndroid boot_control_;
+
+ std::unique_ptr<android::fs_mgr::MetadataBuilder> builder_;
+ std::string super_device_;
+ FakeHardware hardware_;
+ ScopedTempFile payload_file_;
+ ScopedTempFile blob_file_;
+ // Contains expected data for old and new partition
+ ScopedTempFile old_part_{"old_part.XXXXXX", true, kFakePartitionSize};
+ ScopedTempFile new_part_{"new_part.XXXXXX", true, kFakePartitionSize};
+ DaemonStateAndroid daemon_state_;
+ MemoryPrefs prefs_;
+ ErrorCode completion_code_;
+ DynamicPartitionControlAndroid* dynamic_control_{nullptr};
+ brillo::FakeMessageLoop message_loop_{nullptr};
+
+ DeltaArchiveManifest manifest_;
+ UpdateAttempterAndroid update_attempter_android_{
+ &daemon_state_, &prefs_, &boot_control_, &hardware_, nullptr};
+};
+
+namespace {
+
+TEST_F(UpdateAttempterAndroidIntegrationTest, NewPartitionTest) {
+ if (!DynamicPartitionEnabled()) {
+ return;
+ }
+ auto partition = manifest_.add_partitions();
+ partition->set_partition_name("fake");
+ partition->set_estimate_cow_size(kFakePartitionSize);
+ {
+ auto op = partition->add_operations();
+ op->set_type(InstallOperation::REPLACE);
+ *op->add_dst_extents() = ExtentForRange(0, 1);
+ op->set_data_offset(0);
+ op->set_data_length(kBlockSize);
+ truncate(blob_file_.path().c_str(), kBlockSize);
+ }
+ {
+ auto op = partition->add_operations();
+ op->set_type(InstallOperation::ZERO);
+ *op->add_dst_extents() =
+ ExtentForRange(1, kFakePartitionSize / kBlockSize - 1);
+ }
+
+ ApplyPayload(&manifest_);
+}
+
+} // namespace
+
+} // namespace chromeos_update_engine
diff --git a/aosp/update_attempter_android_unittest.cc b/aosp/update_attempter_android_unittest.cc
index 969f191..81a3230 100644
--- a/aosp/update_attempter_android_unittest.cc
+++ b/aosp/update_attempter_android_unittest.cc
@@ -20,12 +20,25 @@
#include <string>
#include <utility>
+#include <sys/fcntl.h>
+#include <sys/sendfile.h>
+#include <unistd.h>
+
#include <android-base/properties.h>
#include <base/time/time.h>
+#include <brillo/data_encoding.h>
+#include <brillo/message_loops/fake_message_loop.h>
#include <gtest/gtest.h>
+#include <liblp/builder.h>
+#include <fs_mgr.h>
+#include <liblp/liblp.h>
-#include "common/constants.h"
+#include "update_engine/aosp/boot_control_android.h"
#include "update_engine/aosp/daemon_state_android.h"
+#include "update_engine/common/constants.h"
+#include "update_engine/common/prefs.h"
+#include "update_engine/common/testing_constants.h"
+#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/fake_boot_control.h"
#include "update_engine/common/fake_clock.h"
#include "update_engine/common/fake_hardware.h"
@@ -34,6 +47,14 @@
#include "update_engine/common/mock_metrics_reporter.h"
#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/payload_file.h"
+#include "update_engine/payload_generator/payload_signer.h"
+#include "update_engine/update_metadata.pb.h"
+#include "update_engine/update_status_utils.h"
using base::Time;
using base::TimeDelta;
diff --git a/common/testing_constants.h b/common/testing_constants.h
index 1367ce6..60a7ad8 100644
--- a/common/testing_constants.h
+++ b/common/testing_constants.h
@@ -17,23 +17,22 @@
#ifndef UPDATE_ENGINE_COMMON_TESTING_CONSTANTS_H_
#define UPDATE_ENGINE_COMMON_TESTING_CONSTANTS_H_
-[[maybe_unused]]
-static constexpr auto&& kUnittestPrivateKeyPath = "unittest_key.pem";
-[[maybe_unused]]
-static constexpr auto&& kUnittestPublicKeyPath = "unittest_key.pub.pem";
-[[maybe_unused]]
-static constexpr auto&& kUnittestPrivateKey2Path = "unittest_key2.pem";
-[[maybe_unused]]
-static constexpr auto&& kUnittestPublicKey2Path = "unittest_key2.pub.pem";
-[[maybe_unused]]
-static constexpr auto&& kUnittestPrivateKeyRSA4096Path =
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKeyPath =
+ "unittest_key.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestOTACertsPath = "otacerts.zip";
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKeyPath =
+ "unittest_key.pub.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKey2Path =
+ "unittest_key2.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKey2Path =
+ "unittest_key2.pub.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKeyRSA4096Path =
"unittest_key_RSA4096.pem";
-[[maybe_unused]]
-static constexpr auto&& kUnittestPublicKeyRSA4096Path =
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKeyRSA4096Path =
"unittest_key_RSA4096.pub.pem";
-[[maybe_unused]]
-static constexpr auto&& kUnittestPrivateKeyECPath = "unittest_key_EC.pem";
-[[maybe_unused]]
-static constexpr auto&& kUnittestPublicKeyECPath = "unittest_key_EC.pub.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKeyECPath =
+ "unittest_key_EC.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKeyECPath =
+ "unittest_key_EC.pub.pem";
#endif // UPDATE_ENGINE_COMMON_TESTING_CONSTANTS_H_
diff --git a/common/utils.cc b/common/utils.cc
index 45ad425..7a4a836 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -1045,10 +1045,24 @@
return android::base::MappedFile::FromFd(fd, 0, size, PROT_READ);
}
+std::string_view GetReadonlyZeroString(size_t size) {
+ // Reserve 512MB of Virtual Address Space. No actual memory will be used.
+ static auto zero_block = GetReadonlyZeroBlock(1024 * 1024 * 512);
+ if (size > zero_block->size()) {
+ auto larger_block = GetReadonlyZeroBlock(size);
+ zero_block = std::move(larger_block);
+ }
+ return {zero_block->data(), size};
+}
+
} // namespace utils
std::string HexEncode(const brillo::Blob& blob) noexcept {
return base::HexEncode(blob.data(), blob.size());
}
+std::string HexEncode(const std::string_view blob) noexcept {
+ return base::HexEncode(blob.data(), blob.size());
+}
+
} // namespace chromeos_update_engine
diff --git a/common/utils.h b/common/utils.h
index 003455d..50b6cb1 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -361,6 +361,8 @@
std::unique_ptr<android::base::MappedFile> GetReadonlyZeroBlock(size_t size);
+std::string_view GetReadonlyZeroString(size_t size);
+
} // namespace utils
// Utility class to close a file descriptor
@@ -481,6 +483,7 @@
};
std::string HexEncode(const brillo::Blob& blob) noexcept;
+std::string HexEncode(const std::string_view blob) noexcept;
} // namespace chromeos_update_engine
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index a383bf6..cc36a4e 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -265,7 +265,7 @@
namespace {
void LogPartitionInfoHash(const PartitionInfo& info, const string& tag) {
- string sha256 = brillo::data_encoding::Base64Encode(info.hash());
+ string sha256 = HexEncode(info.hash());
LOG(INFO) << "PartitionInfo " << tag << " sha256: " << sha256
<< " size: " << info.size();
}
@@ -892,6 +892,7 @@
if (public_key.empty()) {
return {nullptr, false};
}
+ LOG(INFO) << "Verifing using public key: " << public_key;
return {PayloadVerifier::CreateInstance(public_key), true};
}
diff --git a/payload_consumer/filesystem_verifier_action.cc b/payload_consumer/filesystem_verifier_action.cc
index 8b39f6d..0da3fba 100644
--- a/payload_consumer/filesystem_verifier_action.cc
+++ b/payload_consumer/filesystem_verifier_action.cc
@@ -434,7 +434,7 @@
InstallPlan::Partition& partition =
install_plan_.partitions[partition_index_];
LOG(INFO) << "Hash of " << partition.name << ": "
- << Base64Encode(hasher_->raw_hash());
+ << HexEncode(hasher_->raw_hash());
switch (verifier_step_) {
case VerifierStep::kVerifyTargetHash:
diff --git a/payload_generator/delta_diff_utils.cc b/payload_generator/delta_diff_utils.cc
index 5ccdf0b..781b33b 100644
--- a/payload_generator/delta_diff_utils.cc
+++ b/payload_generator/delta_diff_utils.cc
@@ -354,7 +354,10 @@
".so",
".art",
".odex",
- ".vdex" /*, ".capex",".jar", ".apk", ".apex"*/})) {
+ ".vdex",
+ "<kernel>",
+ "<modem-partition>",
+ /*, ".capex",".jar", ".apk", ".apex"*/})) {
return true;
}
zucchini::ConstBufferView src_bytes(old_data_.data(), old_data_.size());