From d34e6bc44b0e58a3261cd7070a1525099932f205 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 13 Jul 2018 13:11:09 -0700 Subject: applypatch: Change applypatch command-line arguments. This applies to the standalone applypatch executable (/system/bin/applypatch on device). This executable is only used when installing (via patching or flashing) a recovery image on non-A/B device. This CL removes the support for patching non-eMMC targets from applypatch that has been deprecated as part of file-based OTA. For patching eMMC targets, it also drops the support for accepting multiple patches (not useful, since the source file must be fixed). This CL needs the matching change in the same topic, which writes the script of "/system/bin/install-recovery.sh". Note that this CL doesn't chanage the applypatch API signatures, in order to minimize the CL size. *BEFORE* usage: /system/bin/applypatch [-b ] [: ...] or /system/bin/applypatch -c [ ...] or /system/bin/applypatch -l Filenames may be of the form EMMC::::::... to specify reading from or writing to an EMMC partition. *AFTER* Usage: check mode applypatch --check EMMC::: flash mode applypatch --flash --target EMMC::: patch mode applypatch [--bonus ] --patch --target EMMC::: --source EMMC::: show license applypatch --license Bug: 110106408 Test: Run recovery_component_test and recovery_unit_test on marlin. Test: Build a non-A/B target that has /system/bin/install-recovery.sh. Verify that it installs recovery image successfully. Test: Build a non-A/B target that has /system/bin/install-recovery.sh in flashing mode. Verify that it installs recovery image successfully. Change-Id: I71f9a71fb457e6f663e0b5511946949e65b4b78c --- tests/component/applypatch_modes_test.cpp | 298 +++++++++++------------------- 1 file changed, 107 insertions(+), 191 deletions(-) (limited to 'tests') diff --git a/tests/component/applypatch_modes_test.cpp b/tests/component/applypatch_modes_test.cpp index bfdc9cabd..ce01f4fd5 100644 --- a/tests/component/applypatch_modes_test.cpp +++ b/tests/component/applypatch_modes_test.cpp @@ -21,7 +21,8 @@ #include #include -#include +#include +#include #include #include #include @@ -31,160 +32,112 @@ #include "common/test_constants.h" #include "otautil/paths.h" #include "otautil/print_sha1.h" +#include "otautil/sysutil.h" using namespace std::string_literals; -static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) { - ASSERT_TRUE(sha1 != nullptr); - +// Loads a given partition and returns a string of form "EMMC:name:size:hash". +static std::string GetEmmcTargetString(const std::string& filename, + const std::string& display_name = "") { std::string data; - ASSERT_TRUE(android::base::ReadFileToString(fname, &data)); - - if (fsize != nullptr) { - *fsize = data.size(); + if (!android::base::ReadFileToString(filename, &data)) { + PLOG(ERROR) << "Failed to read " << filename; + return {}; } uint8_t digest[SHA_DIGEST_LENGTH]; SHA1(reinterpret_cast(data.c_str()), data.size(), digest); - *sha1 = print_sha1(digest); + + return "EMMC:"s + (display_name.empty() ? filename : display_name) + ":" + + std::to_string(data.size()) + ":" + print_sha1(digest); } class ApplyPatchModesTest : public ::testing::Test { protected: void SetUp() override { - Paths::Get().set_cache_temp_source(cache_source.path); + source = GetEmmcTargetString(from_testdata_base("boot.img")); + ASSERT_FALSE(source.empty()); + + std::string recovery_file = from_testdata_base("recovery.img"); + recovery = GetEmmcTargetString(recovery_file); + ASSERT_FALSE(recovery.empty()); + + ASSERT_TRUE(android::base::WriteStringToFile("", patched_file_.path)); + target = GetEmmcTargetString(recovery_file, patched_file_.path); + ASSERT_FALSE(target.empty()); + + Paths::Get().set_cache_temp_source(cache_source_.path); } - TemporaryFile cache_source; + std::string source; + std::string target; + std::string recovery; + + private: + TemporaryFile cache_source_; + TemporaryFile patched_file_; }; +static int InvokeApplyPatchModes(const std::vector& args) { + auto args_to_call = StringVectorToNullTerminatedArray(args); + return applypatch_modes(args_to_call.size() - 1, args_to_call.data()); +} + +static void VerifyPatchedTarget(const std::string& target) { + std::vector pieces = android::base::Split(target, ":"); + ASSERT_EQ(4, pieces.size()); + ASSERT_EQ("EMMC", pieces[0]); + + std::string patched_emmc = GetEmmcTargetString(pieces[1]); + ASSERT_FALSE(patched_emmc.empty()); + ASSERT_EQ(target, patched_emmc); +} + TEST_F(ApplyPatchModesTest, InvalidArgs) { // At least two args (including the filename). - ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" })); + ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch" })); // Unrecognized args. - ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" })); + ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch", "-x" })); } TEST_F(ApplyPatchModesTest, PatchModeEmmcTarget) { - std::string boot_img = from_testdata_base("boot.img"); - size_t boot_img_size; - std::string boot_img_sha1; - sha1sum(boot_img, &boot_img_sha1, &boot_img_size); - - std::string recovery_img = from_testdata_base("recovery.img"); - size_t recovery_img_size; - std::string recovery_img_sha1; - sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size); - std::string recovery_img_size_arg = std::to_string(recovery_img_size); - - std::string bonus_file = from_testdata_base("bonus.file"); - - // applypatch -b : - std::string src_file_arg = - "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1; - TemporaryFile tgt_file; - std::string tgt_file_arg = "EMMC:"s + tgt_file.path; - std::string patch_arg = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); - std::vector args = { "applypatch", - "-b", - bonus_file.c_str(), - src_file_arg.c_str(), - tgt_file_arg.c_str(), - recovery_img_sha1.c_str(), - recovery_img_size_arg.c_str(), - patch_arg.c_str() }; - ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); + std::vector args{ + "applypatch", + "--bonus", + from_testdata_base("bonus.file"), + "--patch", + from_testdata_base("recovery-from-boot.p"), + "--target", + target, + "--source", + source, + }; + ASSERT_EQ(0, InvokeApplyPatchModes(args)); + VerifyPatchedTarget(target); } -// Tests patching the EMMC target without a separate bonus file (i.e. recovery-from-boot patch has +// Tests patching an eMMC target without a separate bonus file (i.e. recovery-from-boot patch has // everything). TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithoutBonusFile) { - std::string boot_img = from_testdata_base("boot.img"); - size_t boot_img_size; - std::string boot_img_sha1; - sha1sum(boot_img, &boot_img_sha1, &boot_img_size); - - std::string recovery_img = from_testdata_base("recovery.img"); - size_t recovery_img_size; - std::string recovery_img_sha1; - sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size); - std::string recovery_img_size_arg = std::to_string(recovery_img_size); - - // applypatch : - std::string src_file_arg = - "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1; - TemporaryFile tgt_file; - std::string tgt_file_arg = "EMMC:"s + tgt_file.path; - std::string patch_arg = - boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); - std::vector args = { "applypatch", - src_file_arg.c_str(), - tgt_file_arg.c_str(), - recovery_img_sha1.c_str(), - recovery_img_size_arg.c_str(), - patch_arg.c_str() }; - - ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); -} + std::vector args{ + "applypatch", "--patch", from_testdata_base("recovery-from-boot-with-bonus.p"), + "--target", target, "--source", + source, + }; -TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithMultiplePatches) { - std::string boot_img = from_testdata_base("boot.img"); - size_t boot_img_size; - std::string boot_img_sha1; - sha1sum(boot_img, &boot_img_sha1, &boot_img_size); - - std::string recovery_img = from_testdata_base("recovery.img"); - size_t recovery_img_size; - std::string recovery_img_sha1; - sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size); - std::string recovery_img_size_arg = std::to_string(recovery_img_size); - - std::string bonus_file = from_testdata_base("bonus.file"); - - // applypatch -b \ - // : : : - std::string src_file_arg = - "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1; - TemporaryFile tgt_file; - std::string tgt_file_arg = "EMMC:"s + tgt_file.path; - std::string bad_sha1_a = android::base::StringPrintf("%040x", rand()); - std::string bad_sha1_b = android::base::StringPrintf("%040x", rand()); - std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p"); - std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); - std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p"); - std::vector args = { "applypatch", - "-b", - bonus_file.c_str(), - src_file_arg.c_str(), - tgt_file_arg.c_str(), - recovery_img_sha1.c_str(), - recovery_img_size_arg.c_str(), - patch1.c_str(), - patch2.c_str(), - patch3.c_str() }; - - ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); + ASSERT_EQ(0, InvokeApplyPatchModes(args)); + VerifyPatchedTarget(target); } // Ensures that applypatch works with a bsdiff based recovery-from-boot.p. TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithBsdiffPatch) { - std::string boot_img_file = from_testdata_base("boot.img"); - std::string boot_img_sha1; - size_t boot_img_size; - sha1sum(boot_img_file, &boot_img_sha1, &boot_img_size); - - std::string recovery_img_file = from_testdata_base("recovery.img"); - std::string recovery_img_sha1; - size_t recovery_img_size; - sha1sum(recovery_img_file, &recovery_img_sha1, &recovery_img_size); - // Generate the bsdiff patch of recovery-from-boot.p. std::string src_content; - ASSERT_TRUE(android::base::ReadFileToString(boot_img_file, &src_content)); + ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("boot.img"), &src_content)); std::string tgt_content; - ASSERT_TRUE(android::base::ReadFileToString(recovery_img_file, &tgt_content)); + ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("recovery.img"), &tgt_content)); TemporaryFile patch_file; ASSERT_EQ(0, @@ -192,92 +145,55 @@ TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithBsdiffPatch) { reinterpret_cast(tgt_content.data()), tgt_content.size(), patch_file.path, nullptr)); - // applypatch : - std::string src_file_arg = - "EMMC:" + boot_img_file + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1; - TemporaryFile tgt_file; - std::string tgt_file_arg = "EMMC:"s + tgt_file.path; - std::string recovery_img_size_arg = std::to_string(recovery_img_size); - std::string patch_arg = boot_img_sha1 + ":" + patch_file.path; - std::vector args = { "applypatch", - src_file_arg.c_str(), - tgt_file_arg.c_str(), - recovery_img_sha1.c_str(), - recovery_img_size_arg.c_str(), - patch_arg.c_str() }; - ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); - - // Double check the patched recovery image. - std::string tgt_file_sha1; - size_t tgt_file_size; - sha1sum(tgt_file.path, &tgt_file_sha1, &tgt_file_size); - ASSERT_EQ(recovery_img_size, tgt_file_size); - ASSERT_EQ(recovery_img_sha1, tgt_file_sha1); + std::vector args{ + "applypatch", "--patch", patch_file.path, "--target", target, "--source", source, + }; + ASSERT_EQ(0, InvokeApplyPatchModes(args)); + VerifyPatchedTarget(target); } TEST_F(ApplyPatchModesTest, PatchModeInvalidArgs) { // Invalid bonus file. - ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" })); + std::vector args{ + "applypatch", "--bonus", "/doesntexist", "--patch", from_testdata_base("recovery-from-boot.p"), + "--target", target, "--source", source, + }; + ASSERT_NE(0, InvokeApplyPatchModes(args)); - std::string bonus_file = from_testdata_base("bonus.file"); // With bonus file, but missing args. - ASSERT_EQ(2, applypatch_modes(3, (const char* []){ "applypatch", "-b", bonus_file.c_str() })); - - std::string boot_img = from_testdata_base("boot.img"); - size_t boot_img_size; - std::string boot_img_sha1; - sha1sum(boot_img, &boot_img_sha1, &boot_img_size); - - std::string recovery_img = from_testdata_base("recovery.img"); - size_t size; - std::string recovery_img_sha1; - sha1sum(recovery_img, &recovery_img_sha1, &size); - std::string recovery_img_size = std::to_string(size); - - // Bonus file is not supported in flash mode. - // applypatch -b - TemporaryFile tmp4; - std::vector args4 = { - "applypatch", - "-b", - bonus_file.c_str(), - boot_img.c_str(), - tmp4.path, - recovery_img_sha1.c_str(), - recovery_img_size.c_str(), - }; - ASSERT_NE(0, applypatch_modes(args4.size(), args4.data())); + ASSERT_NE(0, + InvokeApplyPatchModes({ "applypatch", "--bonus", from_testdata_base("bonus.file") })); +} - // Failed to parse patch args. - TemporaryFile tmp5; - std::string bad_arg1 = - "invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p"); - std::vector args5 = { - "applypatch", - boot_img.c_str(), - tmp5.path, - recovery_img_sha1.c_str(), - recovery_img_size.c_str(), - bad_arg1.c_str(), +TEST_F(ApplyPatchModesTest, FlashMode) { + std::vector args{ + "applypatch", "--flash", from_testdata_base("recovery.img"), "--target", target, }; - ASSERT_NE(0, applypatch_modes(args5.size(), args5.data())); - - // Target size cannot be zero. - TemporaryFile tmp6; - std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); - std::vector args6 = { - "applypatch", boot_img.c_str(), tmp6.path, recovery_img_sha1.c_str(), - "0", // target size - patch.c_str(), + ASSERT_EQ(0, InvokeApplyPatchModes(args)); + VerifyPatchedTarget(target); +} + +TEST_F(ApplyPatchModesTest, FlashModeInvalidArgs) { + std::vector args{ + "applypatch", "--bonus", from_testdata_base("bonus.file"), "--flash", source, + "--target", target, }; - ASSERT_NE(0, applypatch_modes(args6.size(), args6.data())); + ASSERT_NE(0, InvokeApplyPatchModes(args)); +} + +TEST_F(ApplyPatchModesTest, CheckMode) { + ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--check", recovery })); + ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--check", source })); } TEST_F(ApplyPatchModesTest, CheckModeInvalidArgs) { - // Insufficient args. - ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" })); + ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch", "--check" })); +} + +TEST_F(ApplyPatchModesTest, CheckModeNonEmmcTarget) { + ASSERT_NE(0, InvokeApplyPatchModes({ "applypatch", "--check", from_testdata_base("boot.img") })); } TEST_F(ApplyPatchModesTest, ShowLicenses) { - ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" })); + ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--license" })); } -- cgit v1.2.3