From 62e0bc7586077b3bde82759fb34b51b982cea20f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 10 Apr 2017 16:55:57 -0700 Subject: Verify the package compatibility with libvintf. verify_package_compatibility() is added to parse the compatibility entry (compatibility.zip) in a given OTA package. If entry is present, the information is sent to libvintf to check the compatibility. This CL doesn't actually call libvintf, since the API there is not available yet. Bug: 36597505 Test: Doesn't break the install with existing packages (i.e. w/o the compatibility entry). Test: recovery_component_test Change-Id: I3903ffa5f6ba33a5c0d761602ade6290c6752596 --- tests/component/install_test.cpp | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/component/install_test.cpp (limited to 'tests/component/install_test.cpp') diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp new file mode 100644 index 000000000..3b6fbc301 --- /dev/null +++ b/tests/component/install_test.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 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 agree 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 + +#include +#include +#include +#include + +#include "install.h" + +TEST(InstallTest, verify_package_compatibility_no_entry) { + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.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()); + ASSERT_EQ(0, writer.Finish()); + ASSERT_EQ(0, fclose(zip_file)); + + // Doesn't contain compatibility zip entry. + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + ASSERT_TRUE(verify_package_compatibility(zip)); + CloseArchive(zip); +} + +TEST(InstallTest, verify_package_compatibility_invalid_entry) { + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "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)); + + // Empty compatibility zip entry. + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + ASSERT_FALSE(verify_package_compatibility(zip)); + CloseArchive(zip); +} -- cgit v1.2.3 From a233a89d99b673eccaf072f9d0f452afa1c725c7 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 17 Apr 2017 16:46:05 -0700 Subject: Add tests for update_binary_command(). Expose update_binary_command() through private/install.h for testing purpose. Also make minor clean-ups to install.cpp: a) adding more verbose logging on ExtractToMemory failures; b) update_binary_command() taking std::string instead of const char*; c) moving a few macro and global constants into update_binary_command(). Bug: 37300957 Test: recovery_component_test on marlin Test: Build new recovery and adb sideload on angler and sailfish. Change-Id: Ib2d9068af3fee038f01c90940ccaeb0a7da374fc Merged-In: Ib2d9068af3fee038f01c90940ccaeb0a7da374fc (cherry picked from commit bc4b1fe4c4305ebf0fbfc891b9b508c14b5c8ef8) --- tests/component/install_test.cpp | 87 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'tests/component/install_test.cpp') diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp index 3b6fbc301..fd3b28b07 100644 --- a/tests/component/install_test.cpp +++ b/tests/component/install_test.cpp @@ -16,12 +16,18 @@ #include +#include +#include + +#include +#include #include #include #include #include #include "install.h" +#include "private/install.h" TEST(InstallTest, verify_package_compatibility_no_entry) { TemporaryFile temp_file; @@ -55,3 +61,84 @@ TEST(InstallTest, verify_package_compatibility_invalid_entry) { ASSERT_FALSE(verify_package_compatibility(zip)); CloseArchive(zip); } + +TEST(InstallTest, update_binary_command_smoke) { +#ifdef AB_OTA_UPDATER + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "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", ""); + ASSERT_NE("", timestamp); + std::string metadata = android::base::Join( + std::vector{ + "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)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + int status_fd = 10; + std::string path = "/path/to/update.zip"; + std::vector cmd; + ASSERT_EQ(0, update_binary_command(path, zip, 0, status_fd, &cmd)); + ASSERT_EQ("/sbin/update_engine_sideload", cmd[0]); + ASSERT_EQ("--payload=file://" + path, cmd[1]); + ASSERT_EQ("--headers=" + properties, cmd[3]); + ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]); + CloseArchive(zip); +#else + // Cannot test update_binary_command() because it tries to extract update-binary to /tmp. + GTEST_LOG_(INFO) << "Test skipped on non-A/B device."; +#endif // AB_OTA_UPDATER +} + +TEST(InstallTest, update_binary_command_invalid) { +#ifdef AB_OTA_UPDATER + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "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", ""); + ASSERT_NE("", timestamp); + std::string metadata = android::base::Join( + std::vector{ + "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)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + int status_fd = 10; + std::string path = "/path/to/update.zip"; + std::vector cmd; + ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(path, zip, 0, status_fd, &cmd)); + CloseArchive(zip); +#else + // Cannot test update_binary_command() because it tries to extract update-binary to /tmp. + GTEST_LOG_(INFO) << "Test skipped on non-A/B device."; +#endif // AB_OTA_UPDATER +} -- cgit v1.2.3 From b4c0de6c7bcd738e40dc4921d01b534d928e4f4f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 19 Apr 2017 12:37:12 -0700 Subject: Add more tests for verify_package_compatibility(). This now covers the actual calls to libvintf, and asserts we're getting identical results through verify_package_compatibility() and by calling libvintf directly. We were missing the coverage and introduced the double free bug (fixed by commit f978278995d02a58e311fe017bdbb2c3702dd3bc). Bug: 37413730 Test: recovery_component_test passes. Test: recovery_component_test fails w/o commit f978278995d02a58e311fe017bdbb2c3702dd3bc. Change-Id: If5195ea1c583fd7c440a1de289da82145e80e23c (cherry picked from commit f2784b6a43e54ed67bc30ac456f66f11bd16bc74) --- tests/component/install_test.cpp | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) (limited to 'tests/component/install_test.cpp') diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp index fd3b28b07..a5c0c1025 100644 --- a/tests/component/install_test.cpp +++ b/tests/component/install_test.cpp @@ -15,14 +15,17 @@ */ #include +#include #include #include +#include #include #include #include #include +#include #include #include @@ -62,6 +65,87 @@ TEST(InstallTest, verify_package_compatibility_invalid_entry) { CloseArchive(zip); } +TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) { + TemporaryFile compatibility_zip_file; + FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "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)); + + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "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)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + std::vector compatibility_info; + compatibility_info.push_back(malformed_xml); + // Malformed compatibility zip is expected to be rejected by libvintf. But we defer that to + // libvintf. + std::string err; + bool result = + android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0; + ASSERT_EQ(result, verify_package_compatibility(zip)); + CloseArchive(zip); +} + +TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml) { + static constexpr const char* system_manifest_xml_path = "/system/manifest.xml"; + if (access(system_manifest_xml_path, R_OK) == -1) { + GTEST_LOG_(INFO) << "Test skipped on devices w/o /system/manifest.xml."; + return; + } + std::string system_manifest_xml_content; + ASSERT_TRUE( + android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content)); + TemporaryFile compatibility_zip_file; + FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "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)); + + TemporaryFile temp_file; + FILE* zip_file = fdopen(temp_file.fd, "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)); + + ZipArchiveHandle zip; + ASSERT_EQ(0, OpenArchive(temp_file.path, &zip)); + std::vector compatibility_info; + compatibility_info.push_back(system_manifest_xml_content); + std::string err; + bool result = + android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0; + // Make sure the result is consistent with libvintf library. + ASSERT_EQ(result, verify_package_compatibility(zip)); + CloseArchive(zip); +} + TEST(InstallTest, update_binary_command_smoke) { #ifdef AB_OTA_UPDATER TemporaryFile temp_file; -- cgit v1.2.3