blob: ce01f4fd58ec237e5487ca4003dc7bf70d815a4d [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 <android-base/test_utils.h>
27#include <bsdiff/bsdiff.h>
28#include <gtest/gtest.h>
29#include <openssl/sha.h>
Tao Baob8cb2e62018-07-06 12:14:36 -070030
31#include "applypatch/applypatch_modes.h"
32#include "common/test_constants.h"
33#include "otautil/paths.h"
34#include "otautil/print_sha1.h"
Tao Baod34e6bc2018-07-13 13:11:09 -070035#include "otautil/sysutil.h"
Tao Baob8cb2e62018-07-06 12:14:36 -070036
37using namespace std::string_literals;
38
Tao Baod34e6bc2018-07-13 13:11:09 -070039// Loads a given partition and returns a string of form "EMMC:name:size:hash".
40static std::string GetEmmcTargetString(const std::string& filename,
41 const std::string& display_name = "") {
Tao Baob8cb2e62018-07-06 12:14:36 -070042 std::string data;
Tao Baod34e6bc2018-07-13 13:11:09 -070043 if (!android::base::ReadFileToString(filename, &data)) {
44 PLOG(ERROR) << "Failed to read " << filename;
45 return {};
Tao Baob8cb2e62018-07-06 12:14:36 -070046 }
47
48 uint8_t digest[SHA_DIGEST_LENGTH];
49 SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest);
Tao Baod34e6bc2018-07-13 13:11:09 -070050
51 return "EMMC:"s + (display_name.empty() ? filename : display_name) + ":" +
52 std::to_string(data.size()) + ":" + print_sha1(digest);
Tao Baob8cb2e62018-07-06 12:14:36 -070053}
54
Tao Baob8cb2e62018-07-06 12:14:36 -070055class ApplyPatchModesTest : public ::testing::Test {
56 protected:
57 void SetUp() override {
Tao Baod34e6bc2018-07-13 13:11:09 -070058 source = GetEmmcTargetString(from_testdata_base("boot.img"));
59 ASSERT_FALSE(source.empty());
60
61 std::string recovery_file = from_testdata_base("recovery.img");
62 recovery = GetEmmcTargetString(recovery_file);
63 ASSERT_FALSE(recovery.empty());
64
65 ASSERT_TRUE(android::base::WriteStringToFile("", patched_file_.path));
66 target = GetEmmcTargetString(recovery_file, patched_file_.path);
67 ASSERT_FALSE(target.empty());
68
69 Paths::Get().set_cache_temp_source(cache_source_.path);
Tao Baob8cb2e62018-07-06 12:14:36 -070070 }
71
Tao Baod34e6bc2018-07-13 13:11:09 -070072 std::string source;
73 std::string target;
74 std::string recovery;
75
76 private:
77 TemporaryFile cache_source_;
78 TemporaryFile patched_file_;
Tao Baob8cb2e62018-07-06 12:14:36 -070079};
80
Tao Baod34e6bc2018-07-13 13:11:09 -070081static int InvokeApplyPatchModes(const std::vector<std::string>& args) {
82 auto args_to_call = StringVectorToNullTerminatedArray(args);
83 return applypatch_modes(args_to_call.size() - 1, args_to_call.data());
84}
85
86static void VerifyPatchedTarget(const std::string& target) {
87 std::vector<std::string> pieces = android::base::Split(target, ":");
88 ASSERT_EQ(4, pieces.size());
89 ASSERT_EQ("EMMC", pieces[0]);
90
91 std::string patched_emmc = GetEmmcTargetString(pieces[1]);
92 ASSERT_FALSE(patched_emmc.empty());
93 ASSERT_EQ(target, patched_emmc);
94}
95
Tao Baob8cb2e62018-07-06 12:14:36 -070096TEST_F(ApplyPatchModesTest, InvalidArgs) {
97 // At least two args (including the filename).
Tao Baod34e6bc2018-07-13 13:11:09 -070098 ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch" }));
Tao Baob8cb2e62018-07-06 12:14:36 -070099
100 // Unrecognized args.
Tao Baod34e6bc2018-07-13 13:11:09 -0700101 ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch", "-x" }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700102}
103
104TEST_F(ApplyPatchModesTest, PatchModeEmmcTarget) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700105 std::vector<std::string> args{
106 "applypatch",
107 "--bonus",
108 from_testdata_base("bonus.file"),
109 "--patch",
110 from_testdata_base("recovery-from-boot.p"),
111 "--target",
112 target,
113 "--source",
114 source,
115 };
116 ASSERT_EQ(0, InvokeApplyPatchModes(args));
117 VerifyPatchedTarget(target);
Tao Baob8cb2e62018-07-06 12:14:36 -0700118}
119
Tao Baod34e6bc2018-07-13 13:11:09 -0700120// Tests patching an eMMC target without a separate bonus file (i.e. recovery-from-boot patch has
Tao Baob8cb2e62018-07-06 12:14:36 -0700121// everything).
122TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithoutBonusFile) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700123 std::vector<std::string> args{
124 "applypatch", "--patch", from_testdata_base("recovery-from-boot-with-bonus.p"),
125 "--target", target, "--source",
126 source,
127 };
Tao Baob8cb2e62018-07-06 12:14:36 -0700128
Tao Baod34e6bc2018-07-13 13:11:09 -0700129 ASSERT_EQ(0, InvokeApplyPatchModes(args));
130 VerifyPatchedTarget(target);
Tao Baob8cb2e62018-07-06 12:14:36 -0700131}
132
133// Ensures that applypatch works with a bsdiff based recovery-from-boot.p.
134TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithBsdiffPatch) {
Tao Baob8cb2e62018-07-06 12:14:36 -0700135 // Generate the bsdiff patch of recovery-from-boot.p.
136 std::string src_content;
Tao Baod34e6bc2018-07-13 13:11:09 -0700137 ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("boot.img"), &src_content));
Tao Baob8cb2e62018-07-06 12:14:36 -0700138
139 std::string tgt_content;
Tao Baod34e6bc2018-07-13 13:11:09 -0700140 ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("recovery.img"), &tgt_content));
Tao Baob8cb2e62018-07-06 12:14:36 -0700141
142 TemporaryFile patch_file;
143 ASSERT_EQ(0,
144 bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), src_content.size(),
145 reinterpret_cast<const uint8_t*>(tgt_content.data()), tgt_content.size(),
146 patch_file.path, nullptr));
147
Tao Baod34e6bc2018-07-13 13:11:09 -0700148 std::vector<std::string> args{
149 "applypatch", "--patch", patch_file.path, "--target", target, "--source", source,
150 };
151 ASSERT_EQ(0, InvokeApplyPatchModes(args));
152 VerifyPatchedTarget(target);
Tao Baob8cb2e62018-07-06 12:14:36 -0700153}
154
155TEST_F(ApplyPatchModesTest, PatchModeInvalidArgs) {
156 // Invalid bonus file.
Tao Baod34e6bc2018-07-13 13:11:09 -0700157 std::vector<std::string> args{
158 "applypatch", "--bonus", "/doesntexist", "--patch", from_testdata_base("recovery-from-boot.p"),
159 "--target", target, "--source", source,
160 };
161 ASSERT_NE(0, InvokeApplyPatchModes(args));
Tao Baob8cb2e62018-07-06 12:14:36 -0700162
Tao Baob8cb2e62018-07-06 12:14:36 -0700163 // With bonus file, but missing args.
Tao Baod34e6bc2018-07-13 13:11:09 -0700164 ASSERT_NE(0,
165 InvokeApplyPatchModes({ "applypatch", "--bonus", from_testdata_base("bonus.file") }));
166}
Tao Baob8cb2e62018-07-06 12:14:36 -0700167
Tao Baod34e6bc2018-07-13 13:11:09 -0700168TEST_F(ApplyPatchModesTest, FlashMode) {
169 std::vector<std::string> args{
170 "applypatch", "--flash", from_testdata_base("recovery.img"), "--target", target,
Tao Baob8cb2e62018-07-06 12:14:36 -0700171 };
Tao Baod34e6bc2018-07-13 13:11:09 -0700172 ASSERT_EQ(0, InvokeApplyPatchModes(args));
173 VerifyPatchedTarget(target);
174}
Tao Baob8cb2e62018-07-06 12:14:36 -0700175
Tao Baod34e6bc2018-07-13 13:11:09 -0700176TEST_F(ApplyPatchModesTest, FlashModeInvalidArgs) {
177 std::vector<std::string> args{
178 "applypatch", "--bonus", from_testdata_base("bonus.file"), "--flash", source,
179 "--target", target,
Tao Baob8cb2e62018-07-06 12:14:36 -0700180 };
Tao Baod34e6bc2018-07-13 13:11:09 -0700181 ASSERT_NE(0, InvokeApplyPatchModes(args));
182}
Tao Baob8cb2e62018-07-06 12:14:36 -0700183
Tao Baod34e6bc2018-07-13 13:11:09 -0700184TEST_F(ApplyPatchModesTest, CheckMode) {
185 ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--check", recovery }));
186 ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--check", source }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700187}
188
189TEST_F(ApplyPatchModesTest, CheckModeInvalidArgs) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700190 ASSERT_EQ(2, InvokeApplyPatchModes({ "applypatch", "--check" }));
191}
192
193TEST_F(ApplyPatchModesTest, CheckModeNonEmmcTarget) {
194 ASSERT_NE(0, InvokeApplyPatchModes({ "applypatch", "--check", from_testdata_base("boot.img") }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700195}
196
197TEST_F(ApplyPatchModesTest, ShowLicenses) {
Tao Baod34e6bc2018-07-13 13:11:09 -0700198 ASSERT_EQ(0, InvokeApplyPatchModes({ "applypatch", "--license" }));
Tao Baob8cb2e62018-07-06 12:14:36 -0700199}