blob: 08414b7961f031fb03e99cfa7502c43622d8997a [file] [log] [blame]
Tao Baob8cb2e62018-07-06 12:14:36 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agree to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19
20#include <string>
21#include <vector>
22
23#include <android-base/file.h>
Tao Baod34e6bc2018-07-13 13:11:09 -070024#include <android-base/logging.h>
25#include <android-base/strings.h>
Tao Baob8cb2e62018-07-06 12:14:36 -070026#include <bsdiff/bsdiff.h>
27#include <gtest/gtest.h>
28#include <openssl/sha.h>
Tao Baob8cb2e62018-07-06 12:14:36 -070029
30#include "applypatch/applypatch_modes.h"
31#include "common/test_constants.h"
32#include "otautil/paths.h"
33#include "otautil/print_sha1.h"
Tao Baod34e6bc2018-07-13 13:11:09 -070034#include "otautil/sysutil.h"
Tao Baob8cb2e62018-07-06 12:14:36 -070035
36using namespace std::string_literals;
37
Tao Baod34e6bc2018-07-13 13:11:09 -070038// Loads a given partition and returns a string of form "EMMC:name:size:hash".
39static std::string GetEmmcTargetString(const std::string& filename,
40 const std::string& display_name = "") {
Tao Baob8cb2e62018-07-06 12:14:36 -070041 std::string data;
Tao Baod34e6bc2018-07-13 13:11:09 -070042 if (!android::base::ReadFileToString(filename, &data)) {
43 PLOG(ERROR) << "Failed to read " << filename;
44 return {};
Tao Baob8cb2e62018-07-06 12:14:36 -070045 }
46
47 uint8_t digest[SHA_DIGEST_LENGTH];
48 SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest);
Tao Baod34e6bc2018-07-13 13:11:09 -070049
50 return "EMMC:"s + (display_name.empty() ? filename : display_name) + ":" +
51 std::to_string(data.size()) + ":" + print_sha1(digest);
Tao Baob8cb2e62018-07-06 12:14:36 -070052}
53
Tao Baob8cb2e62018-07-06 12:14:36 -070054class ApplyPatchModesTest : public ::testing::Test {
55 protected:
56 void SetUp() override {
Tao Baod34e6bc2018-07-13 13:11:09 -070057 source = GetEmmcTargetString(from_testdata_base("boot.img"));
58 ASSERT_FALSE(source.empty());
59
60 std::string recovery_file = from_testdata_base("recovery.img");
61 recovery = GetEmmcTargetString(recovery_file);
62 ASSERT_FALSE(recovery.empty());
63
64 ASSERT_TRUE(android::base::WriteStringToFile("", patched_file_.path));
65 target = GetEmmcTargetString(recovery_file, patched_file_.path);
66 ASSERT_FALSE(target.empty());
67
68 Paths::Get().set_cache_temp_source(cache_source_.path);
Tao Baob8cb2e62018-07-06 12:14:36 -070069 }
70
Tao Baod34e6bc2018-07-13 13:11:09 -070071 std::string source;
72 std::string target;
73 std::string recovery;
74
75 private:
76 TemporaryFile cache_source_;
77 TemporaryFile patched_file_;
Tao Baob8cb2e62018-07-06 12:14:36 -070078};
79
Tao Baod34e6bc2018-07-13 13:11:09 -070080static int InvokeApplyPatchModes(const std::vector<std::string>& args) {
81 auto args_to_call = StringVectorToNullTerminatedArray(args);
82 return applypatch_modes(args_to_call.size() - 1, args_to_call.data());
83}
84
85static void VerifyPatchedTarget(const std::string& target) {
86 std::vector<std::string> pieces = android::base::Split(target, ":");
87 ASSERT_EQ(4, pieces.size());
88 ASSERT_EQ("EMMC", pieces[0]);
89
90 std::string patched_emmc = GetEmmcTargetString(pieces[1]);
91 ASSERT_FALSE(patched_emmc.empty());
92 ASSERT_EQ(target, patched_emmc);
93}
94
Tao Baob8cb2e62018-07-06 12:14:36 -070095TEST_F(ApplyPatchModesTest, InvalidArgs) {
96 // At least two args (including the filename).
Tao Baod34e6bc2018-07-13 13:11:09 -070097 ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch" }));
Tao Baob8cb2e62018-07-06 12:14:36 -070098
99 // Unrecognized args.
Tao Baod34e6bc2018-07-13 13:11:09 -0700100 ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch", "-x" }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700101}
102
Kelvin Zhang07ba4482021-01-12 16:48:12 -0500103TEST_F(ApplyPatchModesTest, PatchModeEmmcTarget) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700104 std::vector<std::string> args{
105 "applypatch",
106 "--bonus",
107 from_testdata_base("bonus.file"),
108 "--patch",
109 from_testdata_base("recovery-from-boot.p"),
110 "--target",
111 target,
112 "--source",
113 source,
114 };
115 ASSERT_EQ(0, InvokeApplyPatchModes(args));
116 VerifyPatchedTarget(target);
Tao Baob8cb2e62018-07-06 12:14:36 -0700117}
118
Tao Baod34e6bc2018-07-13 13:11:09 -0700119// Tests patching an eMMC target without a separate bonus file (i.e. recovery-from-boot patch has
Tao Baob8cb2e62018-07-06 12:14:36 -0700120// everything).
Kelvin Zhang07ba4482021-01-12 16:48:12 -0500121TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithoutBonusFile) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700122 std::vector<std::string> args{
123 "applypatch", "--patch", from_testdata_base("recovery-from-boot-with-bonus.p"),
124 "--target", target, "--source",
125 source,
126 };
Tao Baob8cb2e62018-07-06 12:14:36 -0700127
Tao Baod34e6bc2018-07-13 13:11:09 -0700128 ASSERT_EQ(0, InvokeApplyPatchModes(args));
129 VerifyPatchedTarget(target);
Tao Baob8cb2e62018-07-06 12:14:36 -0700130}
131
132// Ensures that applypatch works with a bsdiff based recovery-from-boot.p.
133TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithBsdiffPatch) {
Tao Baob8cb2e62018-07-06 12:14:36 -0700134 // Generate the bsdiff patch of recovery-from-boot.p.
135 std::string src_content;
Tao Baod34e6bc2018-07-13 13:11:09 -0700136 ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("boot.img"), &src_content));
Tao Baob8cb2e62018-07-06 12:14:36 -0700137
138 std::string tgt_content;
Tao Baod34e6bc2018-07-13 13:11:09 -0700139 ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("recovery.img"), &tgt_content));
Tao Baob8cb2e62018-07-06 12:14:36 -0700140
141 TemporaryFile patch_file;
142 ASSERT_EQ(0,
143 bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), src_content.size(),
144 reinterpret_cast<const uint8_t*>(tgt_content.data()), tgt_content.size(),
145 patch_file.path, nullptr));
146
Tao Baod34e6bc2018-07-13 13:11:09 -0700147 std::vector<std::string> args{
148 "applypatch", "--patch", patch_file.path, "--target", target, "--source", source,
149 };
150 ASSERT_EQ(0, InvokeApplyPatchModes(args));
151 VerifyPatchedTarget(target);
Tao Baob8cb2e62018-07-06 12:14:36 -0700152}
153
154TEST_F(ApplyPatchModesTest, PatchModeInvalidArgs) {
155 // Invalid bonus file.
Tao Baod34e6bc2018-07-13 13:11:09 -0700156 std::vector<std::string> args{
157 "applypatch", "--bonus", "/doesntexist", "--patch", from_testdata_base("recovery-from-boot.p"),
158 "--target", target, "--source", source,
159 };
160 ASSERT_NE(0, InvokeApplyPatchModes(args));
Tao Baob8cb2e62018-07-06 12:14:36 -0700161
Tao Baob8cb2e62018-07-06 12:14:36 -0700162 // With bonus file, but missing args.
Tao Baod34e6bc2018-07-13 13:11:09 -0700163 ASSERT_NE(0,
164 InvokeApplyPatchModes({ "applypatch", "--bonus", from_testdata_base("bonus.file") }));
165}
Tao Baob8cb2e62018-07-06 12:14:36 -0700166
Tao Baod34e6bc2018-07-13 13:11:09 -0700167TEST_F(ApplyPatchModesTest, FlashMode) {
168 std::vector<std::string> args{
169 "applypatch", "--flash", from_testdata_base("recovery.img"), "--target", target,
Tao Baob8cb2e62018-07-06 12:14:36 -0700170 };
Tao Baod34e6bc2018-07-13 13:11:09 -0700171 ASSERT_EQ(0, InvokeApplyPatchModes(args));
172 VerifyPatchedTarget(target);
173}
Tao Baob8cb2e62018-07-06 12:14:36 -0700174
Tao Baod34e6bc2018-07-13 13:11:09 -0700175TEST_F(ApplyPatchModesTest, FlashModeInvalidArgs) {
176 std::vector<std::string> args{
177 "applypatch", "--bonus", from_testdata_base("bonus.file"), "--flash", source,
178 "--target", target,
Tao Baob8cb2e62018-07-06 12:14:36 -0700179 };
Tao Baod34e6bc2018-07-13 13:11:09 -0700180 ASSERT_NE(0, InvokeApplyPatchModes(args));
181}
Tao Baob8cb2e62018-07-06 12:14:36 -0700182
Tao Baod34e6bc2018-07-13 13:11:09 -0700183TEST_F(ApplyPatchModesTest, CheckMode) {
184 ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--check", recovery }));
185 ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--check", source }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700186}
187
188TEST_F(ApplyPatchModesTest, CheckModeInvalidArgs) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700189 ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch", "--check" }));
190}
191
192TEST_F(ApplyPatchModesTest, CheckModeNonEmmcTarget) {
193 ASSERT_NE(0, InvokeApplyPatchModes({ "applypatch", "--check", from_testdata_base("boot.img") }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700194}
195
196TEST_F(ApplyPatchModesTest, ShowLicenses) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700197 ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--license" }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700198}