summaryrefslogtreecommitdiffstats
path: root/tests/component
diff options
context:
space:
mode:
Diffstat (limited to 'tests/component')
-rw-r--r--tests/component/applypatch_modes_test.cpp1
-rw-r--r--tests/component/bootloader_message_test.cpp2
-rw-r--r--tests/component/imgdiff_test.cpp1
-rw-r--r--tests/component/install_test.cpp440
-rw-r--r--tests/component/resources_test.cpp2
-rw-r--r--tests/component/sideload_test.cpp1
-rw-r--r--tests/component/uncrypt_test.cpp1
-rw-r--r--tests/component/update_verifier_test.cpp136
-rw-r--r--tests/component/updater_test.cpp140
-rw-r--r--tests/component/verifier_test.cpp316
10 files changed, 736 insertions, 304 deletions
diff --git a/tests/component/applypatch_modes_test.cpp b/tests/component/applypatch_modes_test.cpp
index ce01f4fd5..08414b796 100644
--- a/tests/component/applypatch_modes_test.cpp
+++ b/tests/component/applypatch_modes_test.cpp
@@ -23,7 +23,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <bsdiff/bsdiff.h>
#include <gtest/gtest.h>
#include <openssl/sha.h>
diff --git a/tests/component/bootloader_message_test.cpp b/tests/component/bootloader_message_test.cpp
index 6cc59a495..b005d199c 100644
--- a/tests/component/bootloader_message_test.cpp
+++ b/tests/component/bootloader_message_test.cpp
@@ -17,8 +17,8 @@
#include <string>
#include <vector>
+#include <android-base/file.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <bootloader_message/bootloader_message.h>
#include <gtest/gtest.h>
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index cb4868a4a..e76ccbdfb 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -25,7 +25,6 @@
#include <android-base/memory.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <applypatch/imgdiff.h>
#include <applypatch/imgdiff_image.h>
#include <applypatch/imgpatch.h>
diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp
index 08b429000..969805b42 100644
--- a/tests/component/install_test.cpp
+++ b/tests/component/install_test.cpp
@@ -20,13 +20,13 @@
#include <unistd.h>
#include <algorithm>
+#include <random>
#include <string>
#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include <vintf/VintfObjectRecovery.h>
#include <ziparchive/zip_archive.h>
@@ -36,15 +36,23 @@
#include "otautil/paths.h"
#include "private/install.h"
-TEST(InstallTest, verify_package_compatibility_no_entry) {
- TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
+static void BuildZipArchive(const std::map<std::string, std::string>& file_map, int fd,
+ int compression_type) {
+ FILE* zip_file = fdopen(fd, "w");
ZipWriter writer(zip_file);
- // The archive must have something to be opened correctly.
- ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
- ASSERT_EQ(0, writer.FinishEntry());
+ for (const auto& [name, content] : file_map) {
+ ASSERT_EQ(0, writer.StartEntry(name.c_str(), compression_type));
+ ASSERT_EQ(0, writer.WriteBytes(content.data(), content.size()));
+ ASSERT_EQ(0, writer.FinishEntry());
+ }
ASSERT_EQ(0, writer.Finish());
ASSERT_EQ(0, fclose(zip_file));
+}
+
+TEST(InstallTest, verify_package_compatibility_no_entry) {
+ TemporaryFile temp_file;
+ // The archive must have something to be opened correctly.
+ BuildZipArchive({ { "dummy_entry", "" } }, temp_file.release(), kCompressStored);
// Doesn't contain compatibility zip entry.
ZipArchiveHandle zip;
@@ -55,12 +63,7 @@ TEST(InstallTest, verify_package_compatibility_no_entry) {
TEST(InstallTest, verify_package_compatibility_invalid_entry) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
- ASSERT_EQ(0, writer.StartEntry("compatibility.zip", 0));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ BuildZipArchive({ { "compatibility.zip", "" } }, temp_file.release(), kCompressStored);
// Empty compatibility zip entry.
ZipArchiveHandle zip;
@@ -71,77 +74,77 @@ TEST(InstallTest, verify_package_compatibility_invalid_entry) {
TEST(InstallTest, read_metadata_from_package_smoke) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
- ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
- const std::string content("abcdefg");
- ASSERT_EQ(0, writer.WriteBytes(content.data(), content.size()));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ const std::string content("abc=defg");
+ BuildZipArchive({ { "META-INF/com/android/metadata", content } }, temp_file.release(),
+ kCompressStored);
ZipArchiveHandle zip;
ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
- std::string metadata;
- ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
- ASSERT_EQ(content, metadata);
+ std::map<std::string, std::string> metadata;
+ ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
+ ASSERT_EQ("defg", metadata["abc"]);
CloseArchive(zip);
TemporaryFile temp_file2;
- FILE* zip_file2 = fdopen(temp_file2.release(), "w");
- ZipWriter writer2(zip_file2);
- ASSERT_EQ(0, writer2.StartEntry("META-INF/com/android/metadata", kCompressDeflated));
- ASSERT_EQ(0, writer2.WriteBytes(content.data(), content.size()));
- ASSERT_EQ(0, writer2.FinishEntry());
- ASSERT_EQ(0, writer2.Finish());
- ASSERT_EQ(0, fclose(zip_file2));
+ BuildZipArchive({ { "META-INF/com/android/metadata", content } }, temp_file2.release(),
+ kCompressDeflated);
ASSERT_EQ(0, OpenArchive(temp_file2.path, &zip));
metadata.clear();
- ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
- ASSERT_EQ(content, metadata);
+ ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
+ ASSERT_EQ("defg", metadata["abc"]);
CloseArchive(zip);
}
TEST(InstallTest, read_metadata_from_package_no_entry) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
- ASSERT_EQ(0, writer.StartEntry("dummy_entry", kCompressStored));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ BuildZipArchive({ { "dummy_entry", "" } }, temp_file.release(), kCompressStored);
ZipArchiveHandle zip;
ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
- std::string metadata;
- ASSERT_FALSE(read_metadata_from_package(zip, &metadata));
+ std::map<std::string, std::string> metadata;
+ ASSERT_FALSE(ReadMetadataFromPackage(zip, &metadata));
CloseArchive(zip);
}
+TEST(InstallTest, read_wipe_ab_partition_list) {
+ std::vector<std::string> partition_list = {
+ "/dev/block/bootdevice/by-name/system_a", "/dev/block/bootdevice/by-name/system_b",
+ "/dev/block/bootdevice/by-name/vendor_a", "/dev/block/bootdevice/by-name/vendor_b",
+ "/dev/block/bootdevice/by-name/userdata", "# Wipe the boot partitions last",
+ "/dev/block/bootdevice/by-name/boot_a", "/dev/block/bootdevice/by-name/boot_b",
+ };
+ TemporaryFile temp_file;
+ BuildZipArchive({ { "recovery.wipe", android::base::Join(partition_list, '\n') } },
+ temp_file.release(), kCompressDeflated);
+ std::string wipe_package;
+ ASSERT_TRUE(android::base::ReadFileToString(temp_file.path, &wipe_package));
+
+ auto package = Package::CreateMemoryPackage(
+ std::vector<uint8_t>(wipe_package.begin(), wipe_package.end()), nullptr);
+
+ auto read_partition_list = GetWipePartitionList(package.get());
+ std::vector<std::string> expected = {
+ "/dev/block/bootdevice/by-name/system_a", "/dev/block/bootdevice/by-name/system_b",
+ "/dev/block/bootdevice/by-name/vendor_a", "/dev/block/bootdevice/by-name/vendor_b",
+ "/dev/block/bootdevice/by-name/userdata", "/dev/block/bootdevice/by-name/boot_a",
+ "/dev/block/bootdevice/by-name/boot_b",
+ };
+ ASSERT_EQ(expected, read_partition_list);
+}
+
TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) {
TemporaryFile compatibility_zip_file;
- FILE* compatibility_zip = fdopen(compatibility_zip_file.release(), "w");
- ZipWriter compatibility_zip_writer(compatibility_zip);
- ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
std::string malformed_xml = "malformed";
- ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(malformed_xml.data(), malformed_xml.size()));
- ASSERT_EQ(0, compatibility_zip_writer.FinishEntry());
- ASSERT_EQ(0, compatibility_zip_writer.Finish());
- ASSERT_EQ(0, fclose(compatibility_zip));
+ BuildZipArchive({ { "system_manifest.xml", malformed_xml } }, compatibility_zip_file.release(),
+ kCompressDeflated);
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
- ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
std::string compatibility_zip_content;
ASSERT_TRUE(
android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
- ASSERT_EQ(0,
- writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size()));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ BuildZipArchive({ { "compatibility.zip", compatibility_zip_content } }, temp_file.release(),
+ kCompressStored);
ZipArchiveHandle zip;
ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
@@ -166,27 +169,15 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml
ASSERT_TRUE(
android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content));
TemporaryFile compatibility_zip_file;
- FILE* compatibility_zip = fdopen(compatibility_zip_file.release(), "w");
- ZipWriter compatibility_zip_writer(compatibility_zip);
- ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
- ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(system_manifest_xml_content.data(),
- system_manifest_xml_content.size()));
- ASSERT_EQ(0, compatibility_zip_writer.FinishEntry());
- ASSERT_EQ(0, compatibility_zip_writer.Finish());
- ASSERT_EQ(0, fclose(compatibility_zip));
+ BuildZipArchive({ { "system_manifest.xml", system_manifest_xml_content } },
+ compatibility_zip_file.release(), kCompressDeflated);
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
- ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
std::string compatibility_zip_content;
ASSERT_TRUE(
android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
- ASSERT_EQ(0,
- writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size()));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ BuildZipArchive({ { "compatibility.zip", compatibility_zip_content } }, temp_file.release(),
+ kCompressStored);
ZipArchiveHandle zip;
ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
@@ -202,13 +193,8 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml
TEST(InstallTest, SetUpNonAbUpdateCommands) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
- ASSERT_EQ(0, writer.StartEntry(UPDATE_BINARY_NAME, kCompressStored));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ BuildZipArchive({ { UPDATE_BINARY_NAME, "" } }, temp_file.release(), kCompressStored);
ZipArchiveHandle zip;
ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
@@ -246,13 +232,8 @@ TEST(InstallTest, SetUpNonAbUpdateCommands) {
TEST(InstallTest, SetUpNonAbUpdateCommands_MissingUpdateBinary) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
// The archive must have something to be opened correctly.
- ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ BuildZipArchive({ { "dummy_entry", "" } }, temp_file.release(), kCompressStored);
// Missing update binary.
ZipArchiveHandle zip;
@@ -268,16 +249,8 @@ TEST(InstallTest, SetUpNonAbUpdateCommands_MissingUpdateBinary) {
static void VerifyAbUpdateCommands(const std::string& serialno, bool success = true) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
- ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.StartEntry("payload_properties.txt", kCompressStored));
+
const std::string properties = "some_properties";
- ASSERT_EQ(0, writer.WriteBytes(properties.data(), properties.size()));
- ASSERT_EQ(0, writer.FinishEntry());
- // A metadata entry is mandatory.
- ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
std::string device = android::base::GetProperty("ro.product.device", "");
ASSERT_NE("", device);
std::string timestamp = android::base::GetProperty("ro.build.date.utc", "");
@@ -288,21 +261,27 @@ static void VerifyAbUpdateCommands(const std::string& serialno, bool success = t
if (!serialno.empty()) {
meta.push_back("serialno=" + serialno);
}
- std::string metadata = android::base::Join(meta, "\n");
- ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size()));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+ std::string metadata_string = android::base::Join(meta, "\n");
+
+ BuildZipArchive({ { "payload.bin", "" },
+ { "payload_properties.txt", properties },
+ { "META-INF/com/android/metadata", metadata_string } },
+ temp_file.release(), kCompressStored);
ZipArchiveHandle zip;
ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
ZipString payload_name("payload.bin");
ZipEntry payload_entry;
ASSERT_EQ(0, FindEntry(zip, payload_name, &payload_entry));
- int status_fd = 10;
- std::string package = "/path/to/update.zip";
- std::vector<std::string> cmd;
+
+ std::map<std::string, std::string> metadata;
+ ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
if (success) {
+ ASSERT_EQ(0, CheckPackageMetadata(metadata, OtaType::AB));
+
+ int status_fd = 10;
+ std::string package = "/path/to/update.zip";
+ std::vector<std::string> cmd;
ASSERT_EQ(0, SetUpAbUpdateCommands(package, zip, status_fd, &cmd));
ASSERT_EQ(5U, cmd.size());
ASSERT_EQ("/system/bin/update_engine_sideload", cmd[0]);
@@ -311,7 +290,7 @@ static void VerifyAbUpdateCommands(const std::string& serialno, bool success = t
ASSERT_EQ("--headers=" + properties, cmd[3]);
ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]);
} else {
- ASSERT_EQ(INSTALL_ERROR, SetUpAbUpdateCommands(package, zip, status_fd, &cmd));
+ ASSERT_EQ(INSTALL_ERROR, CheckPackageMetadata(metadata, OtaType::AB));
}
CloseArchive(zip);
}
@@ -323,13 +302,7 @@ TEST(InstallTest, SetUpAbUpdateCommands) {
TEST(InstallTest, SetUpAbUpdateCommands_MissingPayloadPropertiesTxt) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.release(), "w");
- ZipWriter writer(zip_file);
- // Missing payload_properties.txt.
- ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
- ASSERT_EQ(0, writer.FinishEntry());
- // A metadata entry is mandatory.
- ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
+
std::string device = android::base::GetProperty("ro.product.device", "");
ASSERT_NE("", device);
std::string timestamp = android::base::GetProperty("ro.build.date.utc", "");
@@ -339,10 +312,13 @@ TEST(InstallTest, SetUpAbUpdateCommands_MissingPayloadPropertiesTxt) {
"ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp,
},
"\n");
- ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size()));
- ASSERT_EQ(0, writer.FinishEntry());
- ASSERT_EQ(0, writer.Finish());
- ASSERT_EQ(0, fclose(zip_file));
+
+ BuildZipArchive(
+ {
+ { "payload.bin", "" },
+ { "META-INF/com/android/metadata", metadata },
+ },
+ temp_file.release(), kCompressStored);
ZipArchiveHandle zip;
ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
@@ -381,3 +357,241 @@ TEST(InstallTest, SetUpAbUpdateCommands_MultipleSerialnos) {
// String with the matching serialno should pass the verification.
VerifyAbUpdateCommands(long_serialno);
}
+
+static void test_check_package_metadata(const std::string& metadata_string, OtaType ota_type,
+ int exptected_result) {
+ TemporaryFile temp_file;
+ BuildZipArchive(
+ {
+ { "META-INF/com/android/metadata", metadata_string },
+ },
+ temp_file.release(), kCompressStored);
+
+ ZipArchiveHandle zip;
+ ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
+
+ std::map<std::string, std::string> metadata;
+ ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
+ ASSERT_EQ(exptected_result, CheckPackageMetadata(metadata, ota_type));
+ CloseArchive(zip);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ota_type) {
+ std::string device = android::base::GetProperty("ro.product.device", "");
+ ASSERT_NE("", device);
+
+ // ota-type must be present
+ std::string metadata = android::base::Join(
+ std::vector<std::string>{
+ "pre-device=" + device,
+ "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+ // Checks if ota-type matches
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, 0);
+
+ test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_device_type) {
+ // device type can not be empty
+ std::string metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=BRICK",
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+
+ // device type mismatches
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=BRICK",
+ "pre-device=dummy_device_type",
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_serial_number_smoke) {
+ std::string device = android::base::GetProperty("ro.product.device", "");
+ ASSERT_NE("", device);
+
+ // Serial number doesn't need to exist
+ std::string metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=BRICK",
+ "pre-device=" + device,
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::BRICK, 0);
+
+ // Serial number mismatches
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=BRICK",
+ "pre-device=" + device,
+ "serialno=dummy_serial",
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+
+ std::string serialno = android::base::GetProperty("ro.serialno", "");
+ ASSERT_NE("", serialno);
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=BRICK",
+ "pre-device=" + device,
+ "serialno=" + serialno,
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::BRICK, 0);
+}
+
+TEST(InstallTest, CheckPackageMetadata_multiple_serial_number) {
+ std::string device = android::base::GetProperty("ro.product.device", "");
+ ASSERT_NE("", device);
+
+ std::string serialno = android::base::GetProperty("ro.serialno", "");
+ ASSERT_NE("", serialno);
+
+ std::vector<std::string> serial_numbers;
+ // Creates a dummy serial number string.
+ for (char c = 'a'; c <= 'z'; c++) {
+ serial_numbers.emplace_back(serialno.size(), c);
+ }
+
+ // No matched serialno found.
+ std::string metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=BRICK",
+ "pre-device=" + device,
+ "serialno=" + android::base::Join(serial_numbers, '|'),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+
+ serial_numbers.emplace_back(serialno);
+ std::shuffle(serial_numbers.begin(), serial_numbers.end(), std::default_random_engine());
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=BRICK",
+ "pre-device=" + device,
+ "serialno=" + android::base::Join(serial_numbers, '|'),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::BRICK, 0);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ab_build_version) {
+ std::string device = android::base::GetProperty("ro.product.device", "");
+ ASSERT_NE("", device);
+
+ std::string build_version = android::base::GetProperty("ro.build.version.incremental", "");
+ ASSERT_NE("", build_version);
+
+ std::string metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "pre-build-incremental=" + build_version,
+ "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, 0);
+
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "pre-build-incremental=dummy_build",
+ "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ab_fingerprint) {
+ std::string device = android::base::GetProperty("ro.product.device", "");
+ ASSERT_NE("", device);
+
+ std::string finger_print = android::base::GetProperty("ro.build.fingerprint", "");
+ ASSERT_NE("", finger_print);
+
+ std::string metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "pre-build=" + finger_print,
+ "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, 0);
+
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "pre-build=dummy_build_fingerprint",
+ "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) {
+ std::string device = android::base::GetProperty("ro.product.device", "");
+ ASSERT_NE("", device);
+
+ // post timestamp is required for upgrade.
+ std::string metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+ // post timestamp should be larger than the timestamp on device.
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "post-timestamp=0",
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+ // fingerprint is required for downgrade
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "post-timestamp=0",
+ "ota-downgrade=yes",
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+ std::string finger_print = android::base::GetProperty("ro.build.fingerprint", "");
+ ASSERT_NE("", finger_print);
+
+ metadata = android::base::Join(
+ std::vector<std::string>{
+ "ota-type=AB",
+ "pre-device=" + device,
+ "post-timestamp=0",
+ "pre-build=" + finger_print,
+ "ota-downgrade=yes",
+ },
+ "\n");
+ test_check_package_metadata(metadata, OtaType::AB, 0);
+}
diff --git a/tests/component/resources_test.cpp b/tests/component/resources_test.cpp
index 54329db22..d7fdb8fa0 100644
--- a/tests/component/resources_test.cpp
+++ b/tests/component/resources_test.cpp
@@ -101,7 +101,7 @@ TEST_P(ResourcesTest, ValidateLocale) {
EXPECT_LT(0, len) << "Locale string should be non-empty.";
EXPECT_NE(0, row[5]) << "Locale string is missing.";
- ASSERT_GT(png_->height(), y + 1 + h) << "Locale: " << kLocale << " is not found in the file.";
+ ASSERT_GE(png_->height(), y + 1 + h) << "Locale: " << kLocale << " is not found in the file.";
char* loc = reinterpret_cast<char*>(&row[5]);
if (matches_locale(loc, kLocale.c_str())) {
EXPECT_TRUE(android::base::StartsWith(loc, kLocale));
diff --git a/tests/component/sideload_test.cpp b/tests/component/sideload_test.cpp
index b7109fcc2..d5e074c63 100644
--- a/tests/component/sideload_test.cpp
+++ b/tests/component/sideload_test.cpp
@@ -21,7 +21,6 @@
#include <android-base/file.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include "fuse_sideload.h"
diff --git a/tests/component/uncrypt_test.cpp b/tests/component/uncrypt_test.cpp
index 55baca2e3..e97d589a6 100644
--- a/tests/component/uncrypt_test.cpp
+++ b/tests/component/uncrypt_test.cpp
@@ -26,7 +26,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <bootloader_message/bootloader_message.h>
#include <gtest/gtest.h>
diff --git a/tests/component/update_verifier_test.cpp b/tests/component/update_verifier_test.cpp
index a97071635..e27e58c22 100644
--- a/tests/component/update_verifier_test.cpp
+++ b/tests/component/update_verifier_test.cpp
@@ -16,6 +16,7 @@
#include <update_verifier/update_verifier.h>
+#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
@@ -23,31 +24,54 @@
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <google/protobuf/repeated_field.h>
#include <gtest/gtest.h>
#include "care_map.pb.h"
+using namespace std::string_literals;
+
class UpdateVerifierTest : public ::testing::Test {
protected:
void SetUp() override {
std::string verity_mode = android::base::GetProperty("ro.boot.veritymode", "");
verity_supported = android::base::EqualsIgnoreCase(verity_mode, "enforcing");
+
+ care_map_prefix_ = care_map_dir_.path + "/care_map"s;
+ care_map_pb_ = care_map_dir_.path + "/care_map.pb"s;
+ care_map_txt_ = care_map_dir_.path + "/care_map.txt"s;
+ // Overrides the the care_map_prefix.
+ verifier_.set_care_map_prefix(care_map_prefix_);
+
+ property_id_ = "ro.build.fingerprint";
+ fingerprint_ = android::base::GetProperty(property_id_, "");
+ // Overrides the property_reader if we cannot read the given property on the device.
+ if (fingerprint_.empty()) {
+ fingerprint_ = "mock_fingerprint";
+ verifier_.set_property_reader([](const std::string& /* id */) { return "mock_fingerprint"; });
+ }
+ }
+
+ void TearDown() override {
+ unlink(care_map_pb_.c_str());
+ unlink(care_map_txt_.c_str());
}
// Returns a serialized string of the proto3 message according to the given partition info.
std::string ConstructProto(
std::vector<std::unordered_map<std::string, std::string>>& partitions) {
- UpdateVerifier::CareMap result;
+ recovery_update_verifier::CareMap result;
for (const auto& partition : partitions) {
- UpdateVerifier::CareMap::PartitionInfo info;
+ recovery_update_verifier::CareMap::PartitionInfo info;
if (partition.find("name") != partition.end()) {
info.set_name(partition.at("name"));
}
if (partition.find("ranges") != partition.end()) {
info.set_ranges(partition.at("ranges"));
}
+ if (partition.find("id") != partition.end()) {
+ info.set_id(partition.at("id"));
+ }
if (partition.find("fingerprint") != partition.end()) {
info.set_fingerprint(partition.at("fingerprint"));
}
@@ -59,15 +83,22 @@ class UpdateVerifierTest : public ::testing::Test {
}
bool verity_supported;
- TemporaryFile care_map_file;
+ UpdateVerifier verifier_;
+
+ TemporaryDir care_map_dir_;
+ std::string care_map_prefix_;
+ std::string care_map_pb_;
+ std::string care_map_txt_;
+
+ std::string property_id_;
+ std::string fingerprint_;
};
TEST_F(UpdateVerifierTest, verify_image_no_care_map) {
- // Non-existing care_map is allowed.
- ASSERT_TRUE(verify_image("/doesntexist"));
+ ASSERT_FALSE(verifier_.ParseCareMap());
}
-TEST_F(UpdateVerifierTest, verify_image_smoke) {
+TEST_F(UpdateVerifierTest, verify_image_text_format) {
// This test relies on dm-verity support.
if (!verity_supported) {
GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
@@ -75,52 +106,58 @@ TEST_F(UpdateVerifierTest, verify_image_smoke) {
}
std::string content = "system\n2,0,1";
- ASSERT_TRUE(android::base::WriteStringToFile(content, care_map_file.path));
- ASSERT_TRUE(verify_image(care_map_file.path));
-
- // Leading and trailing newlines should be accepted.
- ASSERT_TRUE(android::base::WriteStringToFile("\n" + content + "\n\n", care_map_file.path));
- ASSERT_TRUE(verify_image(care_map_file.path));
+ ASSERT_TRUE(android::base::WriteStringToFile(content, care_map_txt_));
+ // CareMap in text format is no longer supported.
+ ASSERT_FALSE(verifier_.ParseCareMap());
}
TEST_F(UpdateVerifierTest, verify_image_empty_care_map) {
- ASSERT_FALSE(verify_image(care_map_file.path));
-}
-
-TEST_F(UpdateVerifierTest, verify_image_wrong_lines) {
- // The care map file can have only 2 / 4 / 6 lines.
- ASSERT_TRUE(android::base::WriteStringToFile("line1", care_map_file.path));
- ASSERT_FALSE(verify_image(care_map_file.path));
-
- ASSERT_TRUE(android::base::WriteStringToFile("line1\nline2\nline3", care_map_file.path));
- ASSERT_FALSE(verify_image(care_map_file.path));
+ ASSERT_FALSE(verifier_.ParseCareMap());
}
-TEST_F(UpdateVerifierTest, verify_image_malformed_care_map) {
+TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_smoke) {
// This test relies on dm-verity support.
if (!verity_supported) {
GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
return;
}
- std::string content = "system\n2,1,0";
- ASSERT_TRUE(android::base::WriteStringToFile(content, care_map_file.path));
- ASSERT_FALSE(verify_image(care_map_file.path));
+ std::vector<std::unordered_map<std::string, std::string>> partitions = {
+ {
+ { "name", "system" },
+ { "ranges", "2,0,1" },
+ { "id", property_id_ },
+ { "fingerprint", fingerprint_ },
+ },
+ };
+
+ std::string proto = ConstructProto(partitions);
+ ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
+ ASSERT_TRUE(verifier_.ParseCareMap());
+ ASSERT_TRUE(verifier_.VerifyPartitions());
}
-TEST_F(UpdateVerifierTest, verify_image_legacy_care_map) {
+TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_missing_name) {
// This test relies on dm-verity support.
if (!verity_supported) {
GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
return;
}
- std::string content = "/dev/block/bootdevice/by-name/system\n2,1,0";
- ASSERT_TRUE(android::base::WriteStringToFile(content, care_map_file.path));
- ASSERT_TRUE(verify_image(care_map_file.path));
+ std::vector<std::unordered_map<std::string, std::string>> partitions = {
+ {
+ { "ranges", "2,0,1" },
+ { "id", property_id_ },
+ { "fingerprint", fingerprint_ },
+ },
+ };
+
+ std::string proto = ConstructProto(partitions);
+ ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
+ ASSERT_FALSE(verifier_.ParseCareMap());
}
-TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_smoke) {
+TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_bad_ranges) {
// This test relies on dm-verity support.
if (!verity_supported) {
GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
@@ -128,15 +165,20 @@ TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_smoke) {
}
std::vector<std::unordered_map<std::string, std::string>> partitions = {
- { { "name", "system" }, { "ranges", "2,0,1" } },
+ {
+ { "name", "system" },
+ { "ranges", "3,0,1" },
+ { "id", property_id_ },
+ { "fingerprint", fingerprint_ },
+ },
};
std::string proto = ConstructProto(partitions);
- ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_file.path));
- ASSERT_TRUE(verify_image(care_map_file.path));
+ ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
+ ASSERT_FALSE(verifier_.ParseCareMap());
}
-TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_missing_name) {
+TEST_F(UpdateVerifierTest, verify_image_protobuf_empty_fingerprint) {
// This test relies on dm-verity support.
if (!verity_supported) {
GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
@@ -144,15 +186,18 @@ TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_missing_name) {
}
std::vector<std::unordered_map<std::string, std::string>> partitions = {
- { { "ranges", "2,0,1" } },
+ {
+ { "name", "system" },
+ { "ranges", "2,0,1" },
+ },
};
std::string proto = ConstructProto(partitions);
- ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_file.path));
- ASSERT_FALSE(verify_image(care_map_file.path));
+ ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
+ ASSERT_FALSE(verifier_.ParseCareMap());
}
-TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_bad_ranges) {
+TEST_F(UpdateVerifierTest, verify_image_protobuf_fingerprint_mismatch) {
// This test relies on dm-verity support.
if (!verity_supported) {
GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
@@ -160,10 +205,15 @@ TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_bad_ranges) {
}
std::vector<std::unordered_map<std::string, std::string>> partitions = {
- { { "name", "system" }, { "ranges", "3,0,1" } },
+ {
+ { "name", "system" },
+ { "ranges", "2,0,1" },
+ { "id", property_id_ },
+ { "fingerprint", "unsupported_fingerprint" },
+ },
};
std::string proto = ConstructProto(partitions);
- ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_file.path));
- ASSERT_FALSE(verify_image(care_map_file.path));
+ ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
+ ASSERT_FALSE(verifier_.ParseCareMap());
}
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 24c63e776..a0a7b66ab 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -23,6 +23,7 @@
#include <algorithm>
#include <memory>
#include <string>
+#include <string_view>
#include <unordered_map>
#include <vector>
@@ -32,7 +33,6 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <bootloader_message/bootloader_message.h>
#include <brotli/encode.h>
#include <bsdiff/bsdiff.h>
@@ -134,9 +134,9 @@ static void RunBlockImageUpdate(bool is_verify, const PackageEntries& entries,
CloseArchive(handle);
}
-static std::string get_sha1(const std::string& content) {
+static std::string GetSha1(std::string_view content) {
uint8_t digest[SHA_DIGEST_LENGTH];
- SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest);
+ SHA1(reinterpret_cast<const uint8_t*>(content.data()), content.size(), digest);
return print_sha1(digest);
}
@@ -187,7 +187,7 @@ class UpdaterTest : public ::testing::Test {
// Clear partition updated marker if any.
std::string updated_marker{ temp_stash_base_.path };
- updated_marker += "/" + get_sha1(image_temp_file_.path) + ".UPDATED";
+ updated_marker += "/" + GetSha1(image_temp_file_.path) + ".UPDATED";
ASSERT_TRUE(android::base::RemoveFileIfExists(updated_marker));
}
@@ -223,14 +223,14 @@ TEST_F(UpdaterTest, patch_partition_check) {
std::string source_content;
ASSERT_TRUE(android::base::ReadFileToString(source_file, &source_content));
size_t source_size = source_content.size();
- std::string source_hash = get_sha1(source_content);
+ std::string source_hash = GetSha1(source_content);
Partition source(source_file, source_size, source_hash);
std::string target_file = from_testdata_base("recovery.img");
std::string target_content;
ASSERT_TRUE(android::base::ReadFileToString(target_file, &target_content));
size_t target_size = target_content.size();
- std::string target_hash = get_sha1(target_content);
+ std::string target_hash = GetSha1(target_content);
Partition target(target_file, target_size, target_hash);
// One argument is not valid.
@@ -619,54 +619,100 @@ TEST_F(UpdaterTest, block_image_update_parsing_error) {
RunBlockImageUpdate(false, entries, image_file_, "", kArgsParsingFailure);
}
-TEST_F(UpdaterTest, block_image_update_patch_data) {
- std::string src_content = std::string(4096, 'a') + std::string(4096, 'c');
- std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd');
-
+// Generates the bsdiff of the given source and target images, and writes the result entries.
+// target_blocks specifies the block count to be written into the `bsdiff` command, which may be
+// different from the given target size in order to trigger overrun / underrun paths.
+static void GetEntriesForBsdiff(std::string_view source, std::string_view target,
+ size_t target_blocks, PackageEntries* entries) {
// Generate the patch data.
TemporaryFile patch_file;
- ASSERT_EQ(0,
- bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), src_content.size(),
- reinterpret_cast<const uint8_t*>(tgt_content.data()), tgt_content.size(),
- patch_file.path, nullptr));
+ ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(source.data()), source.size(),
+ reinterpret_cast<const uint8_t*>(target.data()), target.size(),
+ patch_file.path, nullptr));
std::string patch_content;
ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content));
// Create the transfer list that contains a bsdiff.
- std::string src_hash = get_sha1(src_content);
- std::string tgt_hash = get_sha1(tgt_content);
+ std::string src_hash = GetSha1(source);
+ std::string tgt_hash = GetSha1(target);
+ size_t source_blocks = source.size() / 4096;
std::vector<std::string> transfer_list{
// clang-format off
"4",
- "2",
+ std::to_string(target_blocks),
"0",
- "2",
- "stash " + src_hash + " 2,0,2",
- android::base::StringPrintf("bsdiff 0 %zu %s %s 2,0,2 2 - %s:2,0,2", patch_content.size(),
- src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()),
- "free " + src_hash,
+ "0",
+ // bsdiff patch_offset patch_length source_hash target_hash target_range source_block_count
+ // source_range
+ android::base::StringPrintf("bsdiff 0 %zu %s %s 2,0,%zu %zu 2,0,%zu", patch_content.size(),
+ src_hash.c_str(), tgt_hash.c_str(), target_blocks, source_blocks,
+ source_blocks),
// clang-format on
};
- PackageEntries entries{
+ *entries = {
{ "new_data", "" },
{ "patch_data", patch_content },
{ "transfer_list", android::base::Join(transfer_list, '\n') },
};
+}
- ASSERT_TRUE(android::base::WriteStringToFile(src_content, image_file_));
-
+TEST_F(UpdaterTest, block_image_update_patch_data) {
+ // Both source and target images have 10 blocks.
+ std::string source =
+ std::string(4096, 'a') + std::string(4096, 'c') + std::string(4096 * 3, '\0');
+ std::string target =
+ std::string(4096, 'b') + std::string(4096, 'd') + std::string(4096 * 3, '\0');
+ ASSERT_TRUE(android::base::WriteStringToFile(source, image_file_));
+
+ PackageEntries entries;
+ GetEntriesForBsdiff(std::string_view(source).substr(0, 4096 * 2),
+ std::string_view(target).substr(0, 4096 * 2), 2, &entries);
RunBlockImageUpdate(false, entries, image_file_, "t");
// The update_file should be patched correctly.
- std::string updated_content;
- ASSERT_TRUE(android::base::ReadFileToString(image_file_, &updated_content));
- ASSERT_EQ(tgt_content, updated_content);
+ std::string updated;
+ ASSERT_TRUE(android::base::ReadFileToString(image_file_, &updated));
+ ASSERT_EQ(target, updated);
+}
+
+TEST_F(UpdaterTest, block_image_update_patch_overrun) {
+ // Both source and target images have 10 blocks.
+ std::string source =
+ std::string(4096, 'a') + std::string(4096, 'c') + std::string(4096 * 3, '\0');
+ std::string target =
+ std::string(4096, 'b') + std::string(4096, 'd') + std::string(4096 * 3, '\0');
+ ASSERT_TRUE(android::base::WriteStringToFile(source, image_file_));
+
+ // Provide one less block to trigger the overrun path.
+ PackageEntries entries;
+ GetEntriesForBsdiff(std::string_view(source).substr(0, 4096 * 2),
+ std::string_view(target).substr(0, 4096 * 2), 1, &entries);
+
+ // The update should fail due to overrun.
+ RunBlockImageUpdate(false, entries, image_file_, "", kPatchApplicationFailure);
+}
+
+TEST_F(UpdaterTest, block_image_update_patch_underrun) {
+ // Both source and target images have 10 blocks.
+ std::string source =
+ std::string(4096, 'a') + std::string(4096, 'c') + std::string(4096 * 3, '\0');
+ std::string target =
+ std::string(4096, 'b') + std::string(4096, 'd') + std::string(4096 * 3, '\0');
+ ASSERT_TRUE(android::base::WriteStringToFile(source, image_file_));
+
+ // Provide one more block to trigger the overrun path.
+ PackageEntries entries;
+ GetEntriesForBsdiff(std::string_view(source).substr(0, 4096 * 2),
+ std::string_view(target).substr(0, 4096 * 2), 3, &entries);
+
+ // The update should fail due to underrun.
+ RunBlockImageUpdate(false, entries, image_file_, "", kPatchApplicationFailure);
}
TEST_F(UpdaterTest, block_image_update_fail) {
std::string src_content(4096 * 2, 'e');
- std::string src_hash = get_sha1(src_content);
+ std::string src_hash = GetSha1(src_content);
// Stash and free some blocks, then fail the update intentionally.
std::vector<std::string> transfer_list{
// clang-format off
@@ -692,7 +738,7 @@ TEST_F(UpdaterTest, block_image_update_fail) {
RunBlockImageUpdate(false, entries, image_file_, "");
// Updater generates the stash name based on the input file name.
- std::string name_digest = get_sha1(image_file_);
+ std::string name_digest = GetSha1(image_file_);
std::string stash_base = std::string(temp_stash_base_.path) + "/" + name_digest;
ASSERT_EQ(0, access(stash_base.c_str(), F_OK));
// Expect the stashed blocks to be freed.
@@ -796,9 +842,9 @@ TEST_F(UpdaterTest, last_command_update) {
std::string block1(4096, '1');
std::string block2(4096, '2');
std::string block3(4096, '3');
- std::string block1_hash = get_sha1(block1);
- std::string block2_hash = get_sha1(block2);
- std::string block3_hash = get_sha1(block3);
+ std::string block1_hash = GetSha1(block1);
+ std::string block2_hash = GetSha1(block2);
+ std::string block3_hash = GetSha1(block3);
// Compose the transfer list to fail the first update.
std::vector<std::string> transfer_list_fail{
@@ -864,8 +910,8 @@ TEST_F(UpdaterTest, last_command_update) {
TEST_F(UpdaterTest, last_command_update_unresumable) {
std::string block1(4096, '1');
std::string block2(4096, '2');
- std::string block1_hash = get_sha1(block1);
- std::string block2_hash = get_sha1(block2);
+ std::string block1_hash = GetSha1(block1);
+ std::string block2_hash = GetSha1(block2);
// Construct an unresumable update with source blocks mismatch.
std::vector<std::string> transfer_list_unresumable{
@@ -901,9 +947,9 @@ TEST_F(UpdaterTest, last_command_verify) {
std::string block1(4096, '1');
std::string block2(4096, '2');
std::string block3(4096, '3');
- std::string block1_hash = get_sha1(block1);
- std::string block2_hash = get_sha1(block2);
- std::string block3_hash = get_sha1(block3);
+ std::string block1_hash = GetSha1(block1);
+ std::string block2_hash = GetSha1(block2);
+ std::string block3_hash = GetSha1(block3);
std::vector<std::string> transfer_list_verify{
// clang-format off
@@ -972,7 +1018,7 @@ class ResumableUpdaterTest : public testing::TestWithParam<size_t> {
// Clear partition updated marker if any.
std::string updated_marker{ temp_stash_base_.path };
- updated_marker += "/" + get_sha1(image_temp_file_.path) + ".UPDATED";
+ updated_marker += "/" + GetSha1(image_temp_file_.path) + ".UPDATED";
ASSERT_TRUE(android::base::RemoveFileIfExists(updated_marker));
}
@@ -1003,10 +1049,10 @@ static std::vector<std::string> GenerateTransferList() {
std::string i(4096, 'i');
std::string zero(4096, '\0');
- std::string a_hash = get_sha1(a);
- std::string b_hash = get_sha1(b);
- std::string c_hash = get_sha1(c);
- std::string e_hash = get_sha1(e);
+ std::string a_hash = GetSha1(a);
+ std::string b_hash = GetSha1(b);
+ std::string c_hash = GetSha1(c);
+ std::string e_hash = GetSha1(e);
auto loc = [](const std::string& range_text) {
std::vector<std::string> pieces = android::base::Split(range_text, "-");
@@ -1027,8 +1073,8 @@ static std::vector<std::string> GenerateTransferList() {
// patch 1: "b d c" -> "g"
TemporaryFile patch_file_bdc_g;
std::string bdc = b + d + c;
- std::string bdc_hash = get_sha1(bdc);
- std::string g_hash = get_sha1(g);
+ std::string bdc_hash = GetSha1(bdc);
+ std::string g_hash = GetSha1(g);
CHECK_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(bdc.data()), bdc.size(),
reinterpret_cast<const uint8_t*>(g.data()), g.size(),
patch_file_bdc_g.path, nullptr));
@@ -1038,9 +1084,9 @@ static std::vector<std::string> GenerateTransferList() {
// patch 2: "a b c d" -> "d c b"
TemporaryFile patch_file_abcd_dcb;
std::string abcd = a + b + c + d;
- std::string abcd_hash = get_sha1(abcd);
+ std::string abcd_hash = GetSha1(abcd);
std::string dcb = d + c + b;
- std::string dcb_hash = get_sha1(dcb);
+ std::string dcb_hash = GetSha1(dcb);
CHECK_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(abcd.data()), abcd.size(),
reinterpret_cast<const uint8_t*>(dcb.data()), dcb.size(),
patch_file_abcd_dcb.path, nullptr));
diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp
index 3246ecdbc..c26d76d73 100644
--- a/tests/component/verifier_test.cpp
+++ b/tests/component/verifier_test.cpp
@@ -26,32 +26,232 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/nid.h>
+#include <ziparchive/zip_writer.h>
#include "common/test_constants.h"
#include "otautil/sysutil.h"
+#include "package.h"
#include "verifier.h"
using namespace std::string_literals;
+static void LoadKeyFromFile(const std::string& file_name, Certificate* cert) {
+ std::string testkey_string;
+ ASSERT_TRUE(android::base::ReadFileToString(file_name, &testkey_string));
+ ASSERT_TRUE(LoadCertificateFromBuffer(
+ std::vector<uint8_t>(testkey_string.begin(), testkey_string.end()), cert));
+}
+
+static void VerifyFile(const std::string& content, const std::vector<Certificate>& keys,
+ int expected) {
+ auto package =
+ Package::CreateMemoryPackage(std::vector<uint8_t>(content.begin(), content.end()), nullptr);
+ ASSERT_NE(nullptr, package);
+
+ ASSERT_EQ(expected, verify_file(package.get(), keys));
+}
+
+static void VerifyPackageWithCertificates(const std::string& name,
+ const std::vector<Certificate>& certs) {
+ std::string path = from_testdata_base(name);
+ auto package = Package::CreateMemoryPackage(path, nullptr);
+ ASSERT_NE(nullptr, package);
+
+ ASSERT_EQ(VERIFY_SUCCESS, verify_file(package.get(), certs));
+}
+
+static void VerifyPackageWithSingleCertificate(const std::string& name, Certificate&& cert) {
+ std::vector<Certificate> certs;
+ certs.emplace_back(std::move(cert));
+ VerifyPackageWithCertificates(name, certs);
+}
+
+static void BuildCertificateArchive(const std::vector<std::string>& file_names, int fd) {
+ FILE* zip_file_ptr = fdopen(fd, "wb");
+ ZipWriter zip_writer(zip_file_ptr);
+
+ for (const auto& name : file_names) {
+ std::string content;
+ ASSERT_TRUE(android::base::ReadFileToString(name, &content));
+
+ // Makes sure the zip entry name has the correct suffix.
+ std::string entry_name = name;
+ if (!android::base::EndsWith(entry_name, "x509.pem")) {
+ entry_name += "x509.pem";
+ }
+ ASSERT_EQ(0, zip_writer.StartEntry(entry_name.c_str(), ZipWriter::kCompress));
+ ASSERT_EQ(0, zip_writer.WriteBytes(content.data(), content.size()));
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+ }
+
+ ASSERT_EQ(0, zip_writer.Finish());
+ ASSERT_EQ(0, fclose(zip_file_ptr));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_failure) {
+ Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ std::string testkey_string;
+ ASSERT_TRUE(
+ android::base::ReadFileToString(from_testdata_base("testkey_v1.txt"), &testkey_string));
+ ASSERT_FALSE(LoadCertificateFromBuffer(
+ std::vector<uint8_t>(testkey_string.begin(), testkey_string.end()), &cert));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_sha1_exponent3) {
+ Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v1.x509.pem"), &cert);
+
+ ASSERT_EQ(SHA_DIGEST_LENGTH, cert.hash_len);
+ ASSERT_EQ(Certificate::KEY_TYPE_RSA, cert.key_type);
+ ASSERT_EQ(nullptr, cert.ec);
+
+ VerifyPackageWithSingleCertificate("otasigned_v1.zip", std::move(cert));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_sha1_exponent65537) {
+ Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v2.x509.pem"), &cert);
+
+ ASSERT_EQ(SHA_DIGEST_LENGTH, cert.hash_len);
+ ASSERT_EQ(Certificate::KEY_TYPE_RSA, cert.key_type);
+ ASSERT_EQ(nullptr, cert.ec);
+
+ VerifyPackageWithSingleCertificate("otasigned_v2.zip", std::move(cert));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_sha256_exponent3) {
+ Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v3.x509.pem"), &cert);
+
+ ASSERT_EQ(SHA256_DIGEST_LENGTH, cert.hash_len);
+ ASSERT_EQ(Certificate::KEY_TYPE_RSA, cert.key_type);
+ ASSERT_EQ(nullptr, cert.ec);
+
+ VerifyPackageWithSingleCertificate("otasigned_v3.zip", std::move(cert));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_sha256_exponent65537) {
+ Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v4.x509.pem"), &cert);
+
+ ASSERT_EQ(SHA256_DIGEST_LENGTH, cert.hash_len);
+ ASSERT_EQ(Certificate::KEY_TYPE_RSA, cert.key_type);
+ ASSERT_EQ(nullptr, cert.ec);
+
+ VerifyPackageWithSingleCertificate("otasigned_v4.zip", std::move(cert));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_sha256_ec256bits) {
+ Certificate cert(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v5.x509.pem"), &cert);
+
+ ASSERT_EQ(SHA256_DIGEST_LENGTH, cert.hash_len);
+ ASSERT_EQ(Certificate::KEY_TYPE_EC, cert.key_type);
+ ASSERT_EQ(nullptr, cert.rsa);
+
+ VerifyPackageWithSingleCertificate("otasigned_v5.zip", std::move(cert));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_check_rsa_keys) {
+ std::unique_ptr<RSA, RSADeleter> rsa(RSA_new());
+ std::unique_ptr<BIGNUM, decltype(&BN_free)> exponent(BN_new(), BN_free);
+ BN_set_word(exponent.get(), 3);
+ RSA_generate_key_ex(rsa.get(), 2048, exponent.get(), nullptr);
+ ASSERT_TRUE(CheckRSAKey(rsa));
+
+ // Exponent is expected to be 3 or 65537
+ BN_set_word(exponent.get(), 17);
+ RSA_generate_key_ex(rsa.get(), 2048, exponent.get(), nullptr);
+ ASSERT_FALSE(CheckRSAKey(rsa));
+
+ // Modulus is expected to be 2048.
+ BN_set_word(exponent.get(), 3);
+ RSA_generate_key_ex(rsa.get(), 1024, exponent.get(), nullptr);
+ ASSERT_FALSE(CheckRSAKey(rsa));
+}
+
+TEST(VerifierTest, LoadCertificateFromBuffer_check_ec_keys) {
+ std::unique_ptr<EC_KEY, ECKEYDeleter> ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+ ASSERT_EQ(1, EC_KEY_generate_key(ec.get()));
+ ASSERT_TRUE(CheckECKey(ec));
+
+ // Expects 256-bit EC key with curve NIST P-256
+ ec.reset(EC_KEY_new_by_curve_name(NID_secp224r1));
+ ASSERT_EQ(1, EC_KEY_generate_key(ec.get()));
+ ASSERT_FALSE(CheckECKey(ec));
+}
+
+TEST(VerifierTest, LoadKeysFromZipfile_empty_archive) {
+ TemporaryFile otacerts;
+ BuildCertificateArchive({}, otacerts.release());
+ std::vector<Certificate> certs = LoadKeysFromZipfile(otacerts.path);
+ ASSERT_TRUE(certs.empty());
+}
+
+TEST(VerifierTest, LoadKeysFromZipfile_single_key) {
+ TemporaryFile otacerts;
+ BuildCertificateArchive({ from_testdata_base("testkey_v1.x509.pem") }, otacerts.release());
+ std::vector<Certificate> certs = LoadKeysFromZipfile(otacerts.path);
+ ASSERT_EQ(1, certs.size());
+
+ VerifyPackageWithCertificates("otasigned_v1.zip", certs);
+}
+
+TEST(VerifierTest, LoadKeysFromZipfile_corrupted_key) {
+ TemporaryFile corrupted_key;
+ std::string content;
+ ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v1.x509.pem"), &content));
+ content = "random-contents" + content;
+ ASSERT_TRUE(android::base::WriteStringToFd(content, corrupted_key.release()));
+
+ TemporaryFile otacerts;
+ BuildCertificateArchive({ from_testdata_base("testkey_v2.x509.pem"), corrupted_key.path },
+ otacerts.release());
+ std::vector<Certificate> certs = LoadKeysFromZipfile(otacerts.path);
+ ASSERT_EQ(0, certs.size());
+}
+
+TEST(VerifierTest, LoadKeysFromZipfile_multiple_key) {
+ TemporaryFile otacerts;
+ BuildCertificateArchive(
+ {
+ from_testdata_base("testkey_v3.x509.pem"),
+ from_testdata_base("testkey_v4.x509.pem"),
+ from_testdata_base("testkey_v5.x509.pem"),
+
+ },
+ otacerts.release());
+ std::vector<Certificate> certs = LoadKeysFromZipfile(otacerts.path);
+ ASSERT_EQ(3, certs.size());
+
+ VerifyPackageWithCertificates("otasigned_v3.zip", certs);
+ VerifyPackageWithCertificates("otasigned_v4.zip", certs);
+ VerifyPackageWithCertificates("otasigned_v5.zip", certs);
+}
+
class VerifierTest : public testing::TestWithParam<std::vector<std::string>> {
protected:
void SetUp() override {
std::vector<std::string> args = GetParam();
- std::string package = from_testdata_base(args[0]);
- if (!memmap.MapFile(package)) {
- FAIL() << "Failed to mmap " << package << ": " << strerror(errno) << "\n";
- }
+ std::string path = from_testdata_base(args[0]);
+ package_ = Package::CreateMemoryPackage(path, nullptr);
+ ASSERT_NE(nullptr, package_);
for (auto it = ++args.cbegin(); it != args.cend(); ++it) {
- std::string public_key_file = from_testdata_base("testkey_" + *it + ".txt");
- ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
+ std::string public_key_file = from_testdata_base("testkey_" + *it + ".x509.pem");
+ certs_.emplace_back(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(public_key_file, &certs_.back());
}
}
- MemMapping memmap;
- std::vector<Certificate> certs;
+ std::unique_ptr<Package> package_;
+ std::vector<Certificate> certs_;
};
class VerifierSuccessTest : public VerifierTest {
@@ -60,70 +260,10 @@ class VerifierSuccessTest : public VerifierTest {
class VerifierFailureTest : public VerifierTest {
};
-TEST(VerifierTest, load_keys_multiple_keys) {
- std::string testkey_v4;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4));
-
- std::string testkey_v3;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3));
-
- std::string keys = testkey_v4 + "," + testkey_v3 + "," + testkey_v4;
- TemporaryFile key_file1;
- ASSERT_TRUE(android::base::WriteStringToFile(keys, key_file1.path));
- std::vector<Certificate> certs;
- ASSERT_TRUE(load_keys(key_file1.path, certs));
- ASSERT_EQ(3U, certs.size());
-}
-
-TEST(VerifierTest, load_keys_invalid_keys) {
- std::vector<Certificate> certs;
- ASSERT_FALSE(load_keys("/doesntexist", certs));
-
- // Empty file.
- TemporaryFile key_file1;
- ASSERT_FALSE(load_keys(key_file1.path, certs));
-
- // Invalid contents.
- ASSERT_TRUE(android::base::WriteStringToFile("invalid", key_file1.path));
- ASSERT_FALSE(load_keys(key_file1.path, certs));
-
- std::string testkey_v4;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v4.txt"), &testkey_v4));
-
- // Invalid key version: "v4 ..." => "v6 ...".
- std::string invalid_key2(testkey_v4);
- invalid_key2[1] = '6';
- TemporaryFile key_file2;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key2, key_file2.path));
- ASSERT_FALSE(load_keys(key_file2.path, certs));
-
- // Invalid key content: inserted extra bytes ",2209831334".
- std::string invalid_key3(testkey_v4);
- invalid_key3.insert(invalid_key2.size() - 2, ",2209831334");
- TemporaryFile key_file3;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key3, key_file3.path));
- ASSERT_FALSE(load_keys(key_file3.path, certs));
-
- // Invalid key: the last key must not end with an extra ','.
- std::string invalid_key4 = testkey_v4 + ",";
- TemporaryFile key_file4;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key4, key_file4.path));
- ASSERT_FALSE(load_keys(key_file4.path, certs));
-
- // Invalid key separator.
- std::string invalid_key5 = testkey_v4 + ";" + testkey_v4;
- TemporaryFile key_file5;
- ASSERT_TRUE(android::base::WriteStringToFile(invalid_key5, key_file5.path));
- ASSERT_FALSE(load_keys(key_file5.path, certs));
-}
-
TEST(VerifierTest, BadPackage_AlteredFooter) {
- std::string testkey_v3;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3));
- TemporaryFile key_file1;
- ASSERT_TRUE(android::base::WriteStringToFile(testkey_v3, key_file1.path));
std::vector<Certificate> certs;
- ASSERT_TRUE(load_keys(key_file1.path, certs));
+ certs.emplace_back(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v3.x509.pem"), &certs.back());
std::string package;
ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("otasigned_v3.zip"), &package));
@@ -131,18 +271,13 @@ TEST(VerifierTest, BadPackage_AlteredFooter) {
// Alter the footer.
package[package.size() - 5] = '\x05';
- ASSERT_EQ(VERIFY_FAILURE,
- verify_file(reinterpret_cast<const unsigned char*>(package.data()), package.size(),
- certs));
+ VerifyFile(package, certs, VERIFY_FAILURE);
}
TEST(VerifierTest, BadPackage_AlteredContent) {
- std::string testkey_v3;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3));
- TemporaryFile key_file1;
- ASSERT_TRUE(android::base::WriteStringToFile(testkey_v3, key_file1.path));
std::vector<Certificate> certs;
- ASSERT_TRUE(load_keys(key_file1.path, certs));
+ certs.emplace_back(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v3.x509.pem"), &certs.back());
std::string package;
ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("otasigned_v3.zip"), &package));
@@ -151,38 +286,29 @@ TEST(VerifierTest, BadPackage_AlteredContent) {
// Alter the content.
std::string altered1(package);
altered1[50] += 1;
- ASSERT_EQ(VERIFY_FAILURE,
- verify_file(reinterpret_cast<const unsigned char*>(altered1.data()), altered1.size(),
- certs));
+ VerifyFile(altered1, certs, VERIFY_FAILURE);
std::string altered2(package);
altered2[10] += 1;
- ASSERT_EQ(VERIFY_FAILURE,
- verify_file(reinterpret_cast<const unsigned char*>(altered2.data()), altered2.size(),
- certs));
+ VerifyFile(altered2, certs, VERIFY_FAILURE);
}
TEST(VerifierTest, BadPackage_SignatureStartOutOfBounds) {
- std::string testkey_v3;
- ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3));
-
- TemporaryFile key_file;
- ASSERT_TRUE(android::base::WriteStringToFile(testkey_v3, key_file.path));
std::vector<Certificate> certs;
- ASSERT_TRUE(load_keys(key_file.path, certs));
+ certs.emplace_back(0, Certificate::KEY_TYPE_RSA, nullptr, nullptr);
+ LoadKeyFromFile(from_testdata_base("testkey_v3.x509.pem"), &certs.back());
// Signature start is 65535 (0xffff) while comment size is 0 (Bug: 31914369).
std::string package = "\x50\x4b\x05\x06"s + std::string(12, '\0') + "\xff\xff\xff\xff\x00\x00"s;
- ASSERT_EQ(VERIFY_FAILURE, verify_file(reinterpret_cast<const unsigned char*>(package.data()),
- package.size(), certs));
+ VerifyFile(package, certs, VERIFY_FAILURE);
}
TEST_P(VerifierSuccessTest, VerifySucceed) {
- ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_SUCCESS);
+ ASSERT_EQ(VERIFY_SUCCESS, verify_file(package_.get(), certs_));
}
TEST_P(VerifierFailureTest, VerifyFailure) {
- ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs, nullptr), VERIFY_FAILURE);
+ ASSERT_EQ(VERIFY_FAILURE, verify_file(package_.get(), certs_));
}
INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest,