blob: d9d01d427250b9bf2490b6662809ef2b7e638c19 [file] [log] [blame]
Tao Bao0c7839a2016-10-10 15:48:37 -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 agreed 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
Tao Bao9aa7ab52017-01-05 17:27:19 -080017#include <stdio.h>
Tianjie Xu107a34f2017-06-29 17:04:21 -070018#include <stdlib.h>
Tao Bao89929022016-11-08 20:51:31 -080019#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
22
Tianjie Xu107a34f2017-06-29 17:04:21 -070023#include <algorithm>
Tianjie Xuc4447322017-03-06 14:44:59 -080024#include <memory>
Tao Bao0c7839a2016-10-10 15:48:37 -070025#include <string>
Tianjie Xu5450c842017-10-18 13:15:21 -070026#include <unordered_map>
Tianjie Xu56ebe622017-03-16 00:48:21 -070027#include <vector>
Tao Bao0c7839a2016-10-10 15:48:37 -070028
Tao Bao51d516e2016-11-03 14:49:01 -070029#include <android-base/file.h>
Tao Bao0c7839a2016-10-10 15:48:37 -070030#include <android-base/properties.h>
Tao Bao9aa7ab52017-01-05 17:27:19 -080031#include <android-base/stringprintf.h>
32#include <android-base/strings.h>
Tao Bao51d516e2016-11-03 14:49:01 -070033#include <android-base/test_utils.h>
Tao Baobedf5fc2016-11-18 12:01:26 -080034#include <bootloader_message/bootloader_message.h>
Tianjie Xu107a34f2017-06-29 17:04:21 -070035#include <brotli/encode.h>
Alex Deymofa188262017-10-10 17:56:17 +020036#include <bsdiff/bsdiff.h>
Tao Bao0c7839a2016-10-10 15:48:37 -070037#include <gtest/gtest.h>
Tao Baoef0eb3b2016-11-14 21:29:52 -080038#include <ziparchive/zip_archive.h>
Tianjie Xu56ebe622017-03-16 00:48:21 -070039#include <ziparchive/zip_writer.h>
Tao Bao0c7839a2016-10-10 15:48:37 -070040
Tao Baoef0eb3b2016-11-14 21:29:52 -080041#include "common/test_constants.h"
Tao Bao0c7839a2016-10-10 15:48:37 -070042#include "edify/expr.h"
Tianjie Xu56ebe622017-03-16 00:48:21 -070043#include "otautil/SysUtil.h"
Tao Bao1fc5bf32017-10-06 07:43:41 -070044#include "otautil/error_code.h"
Tao Bao09e468f2017-09-29 14:39:33 -070045#include "otautil/print_sha1.h"
Tianjie Xu56ebe622017-03-16 00:48:21 -070046#include "updater/blockimg.h"
Tao Bao0c7839a2016-10-10 15:48:37 -070047#include "updater/install.h"
Tao Baoef0eb3b2016-11-14 21:29:52 -080048#include "updater/updater.h"
Tao Bao0c7839a2016-10-10 15:48:37 -070049
50struct selabel_handle *sehandle = nullptr;
51
Tao Baoef0eb3b2016-11-14 21:29:52 -080052static void expect(const char* expected, const char* expr_str, CauseCode cause_code,
53 UpdaterInfo* info = nullptr) {
Tianjie Xuc4447322017-03-06 14:44:59 -080054 std::unique_ptr<Expr> e;
Tao Baoef0eb3b2016-11-14 21:29:52 -080055 int error_count = 0;
56 ASSERT_EQ(0, parse_string(expr_str, &e, &error_count));
57 ASSERT_EQ(0, error_count);
Tao Bao0c7839a2016-10-10 15:48:37 -070058
Tao Baoef0eb3b2016-11-14 21:29:52 -080059 State state(expr_str, info);
Tao Bao0c7839a2016-10-10 15:48:37 -070060
Tao Baoef0eb3b2016-11-14 21:29:52 -080061 std::string result;
62 bool status = Evaluate(&state, e, &result);
Tao Bao0c7839a2016-10-10 15:48:37 -070063
Tao Baoef0eb3b2016-11-14 21:29:52 -080064 if (expected == nullptr) {
65 ASSERT_FALSE(status);
66 } else {
67 ASSERT_TRUE(status);
68 ASSERT_STREQ(expected, result.c_str());
69 }
Tao Bao0c7839a2016-10-10 15:48:37 -070070
Tao Baoef0eb3b2016-11-14 21:29:52 -080071 // Error code is set in updater/updater.cpp only, by parsing State.errmsg.
72 ASSERT_EQ(kNoError, state.error_code);
Tao Bao361342c2016-02-08 11:15:50 -080073
Tao Baoef0eb3b2016-11-14 21:29:52 -080074 // Cause code should always be available.
75 ASSERT_EQ(cause_code, state.cause_code);
Tao Bao0c7839a2016-10-10 15:48:37 -070076}
77
Tianjie Xu5450c842017-10-18 13:15:21 -070078static void BuildUpdatePackage(const std::unordered_map<std::string, std::string>& entries,
79 int fd) {
80 FILE* zip_file_ptr = fdopen(fd, "wb");
81 ZipWriter zip_writer(zip_file_ptr);
82
83 for (const auto& entry : entries) {
84 ASSERT_EQ(0, zip_writer.StartEntry(entry.first.c_str(), 0));
85 if (!entry.second.empty()) {
86 ASSERT_EQ(0, zip_writer.WriteBytes(entry.second.data(), entry.second.size()));
87 }
88 ASSERT_EQ(0, zip_writer.FinishEntry());
89 }
90
91 ASSERT_EQ(0, zip_writer.Finish());
92 ASSERT_EQ(0, fclose(zip_file_ptr));
93}
94
Tianjie Xu56ebe622017-03-16 00:48:21 -070095static std::string get_sha1(const std::string& content) {
96 uint8_t digest[SHA_DIGEST_LENGTH];
97 SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest);
98 return print_sha1(digest);
99}
100
Tao Bao0c7839a2016-10-10 15:48:37 -0700101class UpdaterTest : public ::testing::Test {
Tianjie Xu56ebe622017-03-16 00:48:21 -0700102 protected:
103 virtual void SetUp() override {
104 RegisterBuiltins();
105 RegisterInstallFunctions();
106 RegisterBlockImageFunctions();
107 }
Tao Bao0c7839a2016-10-10 15:48:37 -0700108};
109
110TEST_F(UpdaterTest, getprop) {
111 expect(android::base::GetProperty("ro.product.device", "").c_str(),
112 "getprop(\"ro.product.device\")",
Tao Bao361342c2016-02-08 11:15:50 -0800113 kNoCause);
Tao Bao0c7839a2016-10-10 15:48:37 -0700114
115 expect(android::base::GetProperty("ro.build.fingerprint", "").c_str(),
116 "getprop(\"ro.build.fingerprint\")",
Tao Bao361342c2016-02-08 11:15:50 -0800117 kNoCause);
Tao Bao0c7839a2016-10-10 15:48:37 -0700118
119 // getprop() accepts only one parameter.
Tao Bao361342c2016-02-08 11:15:50 -0800120 expect(nullptr, "getprop()", kArgsParsingFailure);
121 expect(nullptr, "getprop(\"arg1\", \"arg2\")", kArgsParsingFailure);
122}
123
124TEST_F(UpdaterTest, sha1_check) {
125 // sha1_check(data) returns the SHA-1 of the data.
126 expect("81fe8bfe87576c3ecb22426f8e57847382917acf", "sha1_check(\"abcd\")", kNoCause);
127 expect("da39a3ee5e6b4b0d3255bfef95601890afd80709", "sha1_check(\"\")", kNoCause);
128
129 // sha1_check(data, sha1_hex, [sha1_hex, ...]) returns the matched SHA-1.
130 expect("81fe8bfe87576c3ecb22426f8e57847382917acf",
131 "sha1_check(\"abcd\", \"81fe8bfe87576c3ecb22426f8e57847382917acf\")",
132 kNoCause);
133
134 expect("81fe8bfe87576c3ecb22426f8e57847382917acf",
135 "sha1_check(\"abcd\", \"wrong_sha1\", \"81fe8bfe87576c3ecb22426f8e57847382917acf\")",
136 kNoCause);
137
138 // Or "" if there's no match.
139 expect("",
140 "sha1_check(\"abcd\", \"wrong_sha1\")",
141 kNoCause);
142
143 expect("",
144 "sha1_check(\"abcd\", \"wrong_sha1\", \"wrong_sha2\")",
145 kNoCause);
146
147 // sha1_check() expects at least one argument.
148 expect(nullptr, "sha1_check()", kArgsParsingFailure);
Tao Bao0c7839a2016-10-10 15:48:37 -0700149}
Tao Bao51d516e2016-11-03 14:49:01 -0700150
Tao Baodb56eb02017-03-23 06:34:20 -0700151TEST_F(UpdaterTest, apply_patch_check) {
152 // Zero-argument is not valid.
153 expect(nullptr, "apply_patch_check()", kArgsParsingFailure);
154
155 // File not found.
156 expect("", "apply_patch_check(\"/doesntexist\")", kNoCause);
157
158 std::string src_file = from_testdata_base("old.file");
159 std::string src_content;
160 ASSERT_TRUE(android::base::ReadFileToString(src_file, &src_content));
161 size_t src_size = src_content.size();
162 std::string src_hash = get_sha1(src_content);
163
164 // One-argument with EMMC:file:size:sha1 should pass the check.
165 std::string filename = android::base::Join(
166 std::vector<std::string>{ "EMMC", src_file, std::to_string(src_size), src_hash }, ":");
167 std::string cmd = "apply_patch_check(\"" + filename + "\")";
168 expect("t", cmd.c_str(), kNoCause);
169
170 // EMMC:file:(size-1):sha1:(size+1):sha1 should fail the check.
171 std::string filename_bad = android::base::Join(
172 std::vector<std::string>{ "EMMC", src_file, std::to_string(src_size - 1), src_hash,
173 std::to_string(src_size + 1), src_hash },
174 ":");
175 cmd = "apply_patch_check(\"" + filename_bad + "\")";
176 expect("", cmd.c_str(), kNoCause);
177
178 // EMMC:file:(size-1):sha1:size:sha1:(size+1):sha1 should pass the check.
179 filename_bad =
180 android::base::Join(std::vector<std::string>{ "EMMC", src_file, std::to_string(src_size - 1),
181 src_hash, std::to_string(src_size), src_hash,
182 std::to_string(src_size + 1), src_hash },
183 ":");
184 cmd = "apply_patch_check(\"" + filename_bad + "\")";
185 expect("t", cmd.c_str(), kNoCause);
186
187 // Multiple arguments.
188 cmd = "apply_patch_check(\"" + filename + "\", \"wrong_sha1\", \"wrong_sha2\")";
189 expect("", cmd.c_str(), kNoCause);
190
191 cmd = "apply_patch_check(\"" + filename + "\", \"wrong_sha1\", \"" + src_hash +
192 "\", \"wrong_sha2\")";
193 expect("t", cmd.c_str(), kNoCause);
194
195 cmd = "apply_patch_check(\"" + filename_bad + "\", \"wrong_sha1\", \"" + src_hash +
196 "\", \"wrong_sha2\")";
197 expect("t", cmd.c_str(), kNoCause);
198}
199
Tao Bao51d516e2016-11-03 14:49:01 -0700200TEST_F(UpdaterTest, file_getprop) {
201 // file_getprop() expects two arguments.
202 expect(nullptr, "file_getprop()", kArgsParsingFailure);
203 expect(nullptr, "file_getprop(\"arg1\")", kArgsParsingFailure);
204 expect(nullptr, "file_getprop(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
205
206 // File doesn't exist.
207 expect(nullptr, "file_getprop(\"/doesntexist\", \"key1\")", kFileGetPropFailure);
208
209 // Reject too large files (current limit = 65536).
210 TemporaryFile temp_file1;
211 std::string buffer(65540, '\0');
212 ASSERT_TRUE(android::base::WriteStringToFile(buffer, temp_file1.path));
213
214 // Read some keys.
215 TemporaryFile temp_file2;
216 std::string content("ro.product.name=tardis\n"
217 "# comment\n\n\n"
218 "ro.product.model\n"
219 "ro.product.board = magic \n");
220 ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file2.path));
221
222 std::string script1("file_getprop(\"" + std::string(temp_file2.path) +
223 "\", \"ro.product.name\")");
224 expect("tardis", script1.c_str(), kNoCause);
225
226 std::string script2("file_getprop(\"" + std::string(temp_file2.path) +
227 "\", \"ro.product.board\")");
228 expect("magic", script2.c_str(), kNoCause);
229
230 // No match.
231 std::string script3("file_getprop(\"" + std::string(temp_file2.path) +
232 "\", \"ro.product.wrong\")");
233 expect("", script3.c_str(), kNoCause);
234
235 std::string script4("file_getprop(\"" + std::string(temp_file2.path) +
236 "\", \"ro.product.name=\")");
237 expect("", script4.c_str(), kNoCause);
238
239 std::string script5("file_getprop(\"" + std::string(temp_file2.path) +
240 "\", \"ro.product.nam\")");
241 expect("", script5.c_str(), kNoCause);
242
243 std::string script6("file_getprop(\"" + std::string(temp_file2.path) +
244 "\", \"ro.product.model\")");
245 expect("", script6.c_str(), kNoCause);
246}
Tao Bao0831d0b2016-11-03 23:25:04 -0700247
Tao Baoef0eb3b2016-11-14 21:29:52 -0800248// TODO: Test extracting to block device.
249TEST_F(UpdaterTest, package_extract_file) {
250 // package_extract_file expects 1 or 2 arguments.
251 expect(nullptr, "package_extract_file()", kArgsParsingFailure);
252 expect(nullptr, "package_extract_file(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
253
254 std::string zip_path = from_testdata_base("ziptest_valid.zip");
255 ZipArchiveHandle handle;
256 ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
257
258 // Need to set up the ziphandle.
259 UpdaterInfo updater_info;
260 updater_info.package_zip = handle;
261
262 // Two-argument version.
263 TemporaryFile temp_file1;
264 std::string script("package_extract_file(\"a.txt\", \"" + std::string(temp_file1.path) + "\")");
265 expect("t", script.c_str(), kNoCause, &updater_info);
266
267 // Verify the extracted entry.
268 std::string data;
269 ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data));
270 ASSERT_EQ(kATxtContents, data);
271
272 // Now extract another entry to the same location, which should overwrite.
273 script = "package_extract_file(\"b.txt\", \"" + std::string(temp_file1.path) + "\")";
274 expect("t", script.c_str(), kNoCause, &updater_info);
275
276 ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data));
277 ASSERT_EQ(kBTxtContents, data);
278
279 // Missing zip entry. The two-argument version doesn't abort.
280 script = "package_extract_file(\"doesntexist\", \"" + std::string(temp_file1.path) + "\")";
281 expect("", script.c_str(), kNoCause, &updater_info);
282
283 // Extract to /dev/full should fail.
284 script = "package_extract_file(\"a.txt\", \"/dev/full\")";
285 expect("", script.c_str(), kNoCause, &updater_info);
286
287 // One-argument version.
288 script = "sha1_check(package_extract_file(\"a.txt\"))";
289 expect(kATxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info);
290
291 script = "sha1_check(package_extract_file(\"b.txt\"))";
292 expect(kBTxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info);
293
294 // Missing entry. The one-argument version aborts the evaluation.
295 script = "package_extract_file(\"doesntexist\")";
296 expect(nullptr, script.c_str(), kPackageExtractFileFailure, &updater_info);
297
298 CloseArchive(handle);
299}
Tao Baod0f30882016-11-03 23:52:01 -0700300
301TEST_F(UpdaterTest, write_value) {
302 // write_value() expects two arguments.
303 expect(nullptr, "write_value()", kArgsParsingFailure);
304 expect(nullptr, "write_value(\"arg1\")", kArgsParsingFailure);
305 expect(nullptr, "write_value(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
306
307 // filename cannot be empty.
308 expect(nullptr, "write_value(\"value\", \"\")", kArgsParsingFailure);
309
310 // Write some value to file.
311 TemporaryFile temp_file;
312 std::string value = "magicvalue";
313 std::string script("write_value(\"" + value + "\", \"" + std::string(temp_file.path) + "\")");
314 expect("t", script.c_str(), kNoCause);
315
316 // Verify the content.
317 std::string content;
318 ASSERT_TRUE(android::base::ReadFileToString(temp_file.path, &content));
319 ASSERT_EQ(value, content);
320
321 // Allow writing empty string.
322 script = "write_value(\"\", \"" + std::string(temp_file.path) + "\")";
323 expect("t", script.c_str(), kNoCause);
324
325 // Verify the content.
326 ASSERT_TRUE(android::base::ReadFileToString(temp_file.path, &content));
327 ASSERT_EQ("", content);
328
329 // It should fail gracefully when write fails.
330 script = "write_value(\"value\", \"/proc/0/file1\")";
331 expect("", script.c_str(), kNoCause);
332}
Tao Baobedf5fc2016-11-18 12:01:26 -0800333
334TEST_F(UpdaterTest, get_stage) {
335 // get_stage() expects one argument.
336 expect(nullptr, "get_stage()", kArgsParsingFailure);
337 expect(nullptr, "get_stage(\"arg1\", \"arg2\")", kArgsParsingFailure);
338 expect(nullptr, "get_stage(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
339
340 // Set up a local file as BCB.
341 TemporaryFile tf;
342 std::string temp_file(tf.path);
343 bootloader_message boot;
344 strlcpy(boot.stage, "2/3", sizeof(boot.stage));
345 std::string err;
346 ASSERT_TRUE(write_bootloader_message_to(boot, temp_file, &err));
347
348 // Can read the stage value.
349 std::string script("get_stage(\"" + temp_file + "\")");
350 expect("2/3", script.c_str(), kNoCause);
351
352 // Bad BCB path.
353 script = "get_stage(\"doesntexist\")";
354 expect("", script.c_str(), kNoCause);
355}
356
357TEST_F(UpdaterTest, set_stage) {
358 // set_stage() expects two arguments.
359 expect(nullptr, "set_stage()", kArgsParsingFailure);
360 expect(nullptr, "set_stage(\"arg1\")", kArgsParsingFailure);
361 expect(nullptr, "set_stage(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
362
363 // Set up a local file as BCB.
364 TemporaryFile tf;
365 std::string temp_file(tf.path);
366 bootloader_message boot;
367 strlcpy(boot.command, "command", sizeof(boot.command));
368 strlcpy(boot.stage, "2/3", sizeof(boot.stage));
369 std::string err;
370 ASSERT_TRUE(write_bootloader_message_to(boot, temp_file, &err));
371
372 // Write with set_stage().
373 std::string script("set_stage(\"" + temp_file + "\", \"1/3\")");
374 expect(tf.path, script.c_str(), kNoCause);
375
376 // Verify.
377 bootloader_message boot_verify;
378 ASSERT_TRUE(read_bootloader_message_from(&boot_verify, temp_file, &err));
379
380 // Stage should be updated, with command part untouched.
381 ASSERT_STREQ("1/3", boot_verify.stage);
382 ASSERT_STREQ(boot.command, boot_verify.command);
383
384 // Bad BCB path.
385 script = "set_stage(\"doesntexist\", \"1/3\")";
386 expect("", script.c_str(), kNoCause);
387
388 script = "set_stage(\"/dev/full\", \"1/3\")";
389 expect("", script.c_str(), kNoCause);
390}
Tao Bao9aa7ab52017-01-05 17:27:19 -0800391
392TEST_F(UpdaterTest, set_progress) {
393 // set_progress() expects one argument.
394 expect(nullptr, "set_progress()", kArgsParsingFailure);
395 expect(nullptr, "set_progress(\"arg1\", \"arg2\")", kArgsParsingFailure);
396
397 // Invalid progress argument.
398 expect(nullptr, "set_progress(\"arg1\")", kArgsParsingFailure);
399 expect(nullptr, "set_progress(\"3x+5\")", kArgsParsingFailure);
400 expect(nullptr, "set_progress(\".3.5\")", kArgsParsingFailure);
401
402 TemporaryFile tf;
403 UpdaterInfo updater_info;
Tianjie Xu79327ac2017-09-08 17:09:10 -0700404 updater_info.cmd_pipe = fdopen(tf.release(), "w");
Tao Bao9aa7ab52017-01-05 17:27:19 -0800405 expect(".52", "set_progress(\".52\")", kNoCause, &updater_info);
406 fflush(updater_info.cmd_pipe);
407
408 std::string cmd;
409 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &cmd));
410 ASSERT_EQ(android::base::StringPrintf("set_progress %f\n", .52), cmd);
411 // recovery-updater protocol expects 2 tokens ("set_progress <frac>").
412 ASSERT_EQ(2U, android::base::Split(cmd, " ").size());
Tianjie Xu79327ac2017-09-08 17:09:10 -0700413 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
Tao Bao9aa7ab52017-01-05 17:27:19 -0800414}
415
416TEST_F(UpdaterTest, show_progress) {
417 // show_progress() expects two arguments.
418 expect(nullptr, "show_progress()", kArgsParsingFailure);
419 expect(nullptr, "show_progress(\"arg1\")", kArgsParsingFailure);
420 expect(nullptr, "show_progress(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
421
422 // Invalid progress arguments.
423 expect(nullptr, "show_progress(\"arg1\", \"arg2\")", kArgsParsingFailure);
424 expect(nullptr, "show_progress(\"3x+5\", \"10\")", kArgsParsingFailure);
425 expect(nullptr, "show_progress(\".3\", \"5a\")", kArgsParsingFailure);
426
427 TemporaryFile tf;
428 UpdaterInfo updater_info;
Tianjie Xu79327ac2017-09-08 17:09:10 -0700429 updater_info.cmd_pipe = fdopen(tf.release(), "w");
Tao Bao9aa7ab52017-01-05 17:27:19 -0800430 expect(".52", "show_progress(\".52\", \"10\")", kNoCause, &updater_info);
431 fflush(updater_info.cmd_pipe);
432
433 std::string cmd;
434 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &cmd));
435 ASSERT_EQ(android::base::StringPrintf("progress %f %d\n", .52, 10), cmd);
436 // recovery-updater protocol expects 3 tokens ("progress <frac> <secs>").
437 ASSERT_EQ(3U, android::base::Split(cmd, " ").size());
Tianjie Xu79327ac2017-09-08 17:09:10 -0700438 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
Tao Bao9aa7ab52017-01-05 17:27:19 -0800439}
Tianjie Xu56ebe622017-03-16 00:48:21 -0700440
Tianjie Xu5450c842017-10-18 13:15:21 -0700441TEST_F(UpdaterTest, block_image_update_patch_data) {
Tianjie Xu56ebe622017-03-16 00:48:21 -0700442 std::string src_content = std::string(4096, 'a') + std::string(4096, 'c');
443 std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd');
Tianjie Xu5450c842017-10-18 13:15:21 -0700444
445 // Generate the patch data.
Tianjie Xu56ebe622017-03-16 00:48:21 -0700446 TemporaryFile patch_file;
447 ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()),
448 src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()),
449 tgt_content.size(), patch_file.path, nullptr));
450 std::string patch_content;
451 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content));
Tianjie Xu56ebe622017-03-16 00:48:21 -0700452
Tianjie Xu5450c842017-10-18 13:15:21 -0700453 // Create the transfer list that contains a bsdiff.
Tianjie Xu56ebe622017-03-16 00:48:21 -0700454 std::string src_hash = get_sha1(src_content);
455 std::string tgt_hash = get_sha1(tgt_content);
456 std::vector<std::string> transfer_list = {
457 "4",
458 "2",
459 "0",
460 "2",
461 "stash " + src_hash + " 2,0,2",
462 android::base::StringPrintf("bsdiff 0 %zu %s %s 2,0,2 2 - %s:2,0,2", patch_content.size(),
463 src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()),
464 "free " + src_hash,
465 };
Tianjie Xu56ebe622017-03-16 00:48:21 -0700466
Tianjie Xu5450c842017-10-18 13:15:21 -0700467 std::unordered_map<std::string, std::string> entries = {
468 { "new_data", "" },
469 { "patch_data", patch_content },
470 { "transfer_list", android::base::Join(transfer_list, '\n') },
Tianjie Xu56ebe622017-03-16 00:48:21 -0700471 };
Tianjie Xu5450c842017-10-18 13:15:21 -0700472
473 // Build the update package.
474 TemporaryFile zip_file;
475 BuildUpdatePackage(entries, zip_file.release());
Tianjie Xu56ebe622017-03-16 00:48:21 -0700476
477 MemMapping map;
Tao Baob656a152017-04-18 23:54:29 -0700478 ASSERT_TRUE(map.MapFile(zip_file.path));
Tianjie Xu56ebe622017-03-16 00:48:21 -0700479 ZipArchiveHandle handle;
480 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
481
482 // Set up the handler, command_pipe, patch offset & length.
483 UpdaterInfo updater_info;
484 updater_info.package_zip = handle;
485 TemporaryFile temp_pipe;
Tianjie Xu79327ac2017-09-08 17:09:10 -0700486 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
Tianjie Xu56ebe622017-03-16 00:48:21 -0700487 updater_info.package_zip_addr = map.addr;
488 updater_info.package_zip_len = map.length;
489
Tianjie Xu5450c842017-10-18 13:15:21 -0700490 // Execute the commands in the transfer list.
Tianjie Xu56ebe622017-03-16 00:48:21 -0700491 TemporaryFile update_file;
492 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
493 std::string script = "block_image_update(\"" + std::string(update_file.path) +
494 R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
495 expect("t", script.c_str(), kNoCause, &updater_info);
496 // The update_file should be patched correctly.
497 std::string updated_content;
498 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
499 ASSERT_EQ(tgt_hash, get_sha1(updated_content));
500
Tianjie Xu5450c842017-10-18 13:15:21 -0700501 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
502 CloseArchive(handle);
503}
504
505TEST_F(UpdaterTest, block_image_update_fail) {
506 std::string src_content(4096 * 2, 'e');
507 std::string src_hash = get_sha1(src_content);
508 // Stash and free some blocks, then fail the update intentionally.
509 std::vector<std::string> transfer_list = {
510 "4", "2", "0", "2", "stash " + src_hash + " 2,0,2", "free " + src_hash, "fail",
511 };
512
513 // Add a new data of 10 bytes to test the deadlock.
514 std::unordered_map<std::string, std::string> entries = {
515 { "new_data", std::string(10, 0) },
516 { "patch_data", "" },
517 { "transfer_list", android::base::Join(transfer_list, '\n') },
518 };
519
520 // Build the update package.
521 TemporaryFile zip_file;
522 BuildUpdatePackage(entries, zip_file.release());
523
524 MemMapping map;
525 ASSERT_TRUE(map.MapFile(zip_file.path));
526 ZipArchiveHandle handle;
527 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
528
529 // Set up the handler, command_pipe, patch offset & length.
530 UpdaterInfo updater_info;
531 updater_info.package_zip = handle;
532 TemporaryFile temp_pipe;
533 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
534 updater_info.package_zip_addr = map.addr;
535 updater_info.package_zip_len = map.length;
536
537 TemporaryFile update_file;
538 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
539 // Expect the stashed blocks to be freed.
540 std::string script = "block_image_update(\"" + std::string(update_file.path) +
541 R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
Tianjie Xu56ebe622017-03-16 00:48:21 -0700542 expect("", script.c_str(), kNoCause, &updater_info);
543 // Updater generates the stash name based on the input file name.
544 std::string name_digest = get_sha1(update_file.path);
545 std::string stash_base = "/cache/recovery/" + name_digest;
546 ASSERT_EQ(0, access(stash_base.c_str(), F_OK));
Tianjie Xu5450c842017-10-18 13:15:21 -0700547 ASSERT_EQ(-1, access((stash_base + src_hash).c_str(), F_OK));
Tianjie Xu56ebe622017-03-16 00:48:21 -0700548 ASSERT_EQ(0, rmdir(stash_base.c_str()));
549
550 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
551 CloseArchive(handle);
552}
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700553
Tianjie Xu5450c842017-10-18 13:15:21 -0700554TEST_F(UpdaterTest, new_data_over_write) {
555 std::vector<std::string> transfer_list = {
556 "4", "1", "0", "0", "new 2,0,1",
557 };
558
559 // Write 4096 + 100 bytes of new data.
560 std::unordered_map<std::string, std::string> entries = {
561 { "new_data", std::string(4196, 0) },
562 { "patch_data", "" },
563 { "transfer_list", android::base::Join(transfer_list, '\n') },
564 };
565
566 // Build the update package.
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700567 TemporaryFile zip_file;
Tianjie Xu5450c842017-10-18 13:15:21 -0700568 BuildUpdatePackage(entries, zip_file.release());
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700569
Tianjie Xu5450c842017-10-18 13:15:21 -0700570 MemMapping map;
571 ASSERT_TRUE(map.MapFile(zip_file.path));
572 ZipArchiveHandle handle;
573 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700574
Tianjie Xu5450c842017-10-18 13:15:21 -0700575 // Set up the handler, command_pipe, patch offset & length.
576 UpdaterInfo updater_info;
577 updater_info.package_zip = handle;
578 TemporaryFile temp_pipe;
579 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
580 updater_info.package_zip_addr = map.addr;
581 updater_info.package_zip_len = map.length;
582
583 TemporaryFile update_file;
584 std::string script = "block_image_update(\"" + std::string(update_file.path) +
585 R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
586 expect("t", script.c_str(), kNoCause, &updater_info);
587
588 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
589 CloseArchive(handle);
590}
591
592TEST_F(UpdaterTest, new_data_short_write) {
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700593 std::vector<std::string> transfer_list = {
594 "4",
595 "1",
596 "0",
597 "0",
598 "new 2,0,1",
599 };
Tianjie Xu5450c842017-10-18 13:15:21 -0700600
601 std::unordered_map<std::string, std::string> entries = {
602 { "empty_new_data", "" },
603 { "short_new_data", std::string(10, 'a') },
604 { "exact_new_data", std::string(4096, 'a') },
605 { "patch_data", "" },
606 { "transfer_list", android::base::Join(transfer_list, '\n') },
607 };
608
609 TemporaryFile zip_file;
610 BuildUpdatePackage(entries, zip_file.release());
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700611
612 MemMapping map;
Tao Baob656a152017-04-18 23:54:29 -0700613 ASSERT_TRUE(map.MapFile(zip_file.path));
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700614 ZipArchiveHandle handle;
615 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
616
617 // Set up the handler, command_pipe, patch offset & length.
618 UpdaterInfo updater_info;
619 updater_info.package_zip = handle;
620 TemporaryFile temp_pipe;
Tianjie Xu79327ac2017-09-08 17:09:10 -0700621 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700622 updater_info.package_zip_addr = map.addr;
623 updater_info.package_zip_len = map.length;
624
625 // Updater should report the failure gracefully rather than stuck in deadlock.
626 TemporaryFile update_file;
627 std::string script_empty_data = "block_image_update(\"" + std::string(update_file.path) +
628 R"(", package_extract_file("transfer_list"), "empty_new_data", "patch_data"))";
629 expect("", script_empty_data.c_str(), kNoCause, &updater_info);
630
631 std::string script_short_data = "block_image_update(\"" + std::string(update_file.path) +
632 R"(", package_extract_file("transfer_list"), "short_new_data", "patch_data"))";
633 expect("", script_short_data.c_str(), kNoCause, &updater_info);
634
635 // Expect to write 1 block of new data successfully.
636 std::string script_exact_data = "block_image_update(\"" + std::string(update_file.path) +
637 R"(", package_extract_file("transfer_list"), "exact_new_data", "patch_data"))";
638 expect("t", script_exact_data.c_str(), kNoCause, &updater_info);
Tianjie Xu79327ac2017-09-08 17:09:10 -0700639
640 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
Tianjie Xu107a34f2017-06-29 17:04:21 -0700641 CloseArchive(handle);
642}
643
644TEST_F(UpdaterTest, brotli_new_data) {
Tianjie Xu107a34f2017-06-29 17:04:21 -0700645 auto generator = []() { return rand() % 128; };
Tianjie Xu6ed175d2017-07-18 11:29:40 -0700646 // Generate 100 blocks of random data.
Tianjie Xu107a34f2017-06-29 17:04:21 -0700647 std::string brotli_new_data;
Tianjie Xu6ed175d2017-07-18 11:29:40 -0700648 brotli_new_data.reserve(4096 * 100);
649 generate_n(back_inserter(brotli_new_data), 4096 * 100, generator);
Tianjie Xu107a34f2017-06-29 17:04:21 -0700650
651 size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size());
Tianjie Xu5450c842017-10-18 13:15:21 -0700652 std::string encoded_data(encoded_size, 0);
Tianjie Xu107a34f2017-06-29 17:04:21 -0700653 ASSERT_TRUE(BrotliEncoderCompress(
654 BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(),
Tianjie Xu5450c842017-10-18 13:15:21 -0700655 reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size,
656 reinterpret_cast<uint8_t*>(const_cast<char*>(encoded_data.data()))));
657 encoded_data.resize(encoded_size);
Tianjie Xu107a34f2017-06-29 17:04:21 -0700658
Tianjie Xu6ed175d2017-07-18 11:29:40 -0700659 // Write a few small chunks of new data, then a large chunk, and finally a few small chunks.
660 // This helps us to catch potential short writes.
Tianjie Xu107a34f2017-06-29 17:04:21 -0700661 std::vector<std::string> transfer_list = {
Tianjie Xu6ed175d2017-07-18 11:29:40 -0700662 "4",
663 "100",
664 "0",
665 "0",
666 "new 2,0,1",
667 "new 2,1,2",
668 "new 4,2,50,50,97",
669 "new 2,97,98",
670 "new 2,98,99",
671 "new 2,99,100",
Tianjie Xu107a34f2017-06-29 17:04:21 -0700672 };
Tianjie Xu5450c842017-10-18 13:15:21 -0700673
674 std::unordered_map<std::string, std::string> entries = {
675 { "new.dat.br", std::move(encoded_data) },
676 { "patch_data", "" },
677 { "transfer_list", android::base::Join(transfer_list, '\n') },
678 };
679
680 TemporaryFile zip_file;
681 BuildUpdatePackage(entries, zip_file.release());
Tianjie Xu107a34f2017-06-29 17:04:21 -0700682
683 MemMapping map;
684 ASSERT_TRUE(map.MapFile(zip_file.path));
685 ZipArchiveHandle handle;
686 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
687
688 // Set up the handler, command_pipe, patch offset & length.
689 UpdaterInfo updater_info;
690 updater_info.package_zip = handle;
691 TemporaryFile temp_pipe;
Tianjie Xu79327ac2017-09-08 17:09:10 -0700692 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wb");
Tianjie Xu107a34f2017-06-29 17:04:21 -0700693 updater_info.package_zip_addr = map.addr;
694 updater_info.package_zip_len = map.length;
695
696 // Check if we can decompress the new data correctly.
697 TemporaryFile update_file;
698 std::string script_new_data =
699 "block_image_update(\"" + std::string(update_file.path) +
700 R"(", package_extract_file("transfer_list"), "new.dat.br", "patch_data"))";
701 expect("t", script_new_data.c_str(), kNoCause, &updater_info);
702
703 std::string updated_content;
704 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
705 ASSERT_EQ(brotli_new_data, updated_content);
Tianjie Xu79327ac2017-09-08 17:09:10 -0700706
707 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
Tianjie Xu107a34f2017-06-29 17:04:21 -0700708 CloseArchive(handle);
Tianjie Xu3a8d98d2017-04-03 20:01:17 -0700709}