aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorTianjie Xu2017-10-18 15:15:21 -0500
committerTianjie Xu2017-10-20 13:14:56 -0500
commit5450c84ba4cc62b887e69ec11a922194b36756a9 (patch)
tree920a40bc079d95c8714a47f11c24f6017d7e4ea7 /tests
parent30ec0051042344465a67637eb4cd86250164f1fe (diff)
downloadplatform-bootable-recovery-5450c84ba4cc62b887e69ec11a922194b36756a9.tar.gz
platform-bootable-recovery-5450c84ba4cc62b887e69ec11a922194b36756a9.tar.xz
platform-bootable-recovery-5450c84ba4cc62b887e69ec11a922194b36756a9.zip
Finish the new data receiver when update fails
The thread to receive new data may still be alive after we exit PerformBlockImageUpdate() upon failures. This caused memory corruption when we run the unittest repeatedly. Set the receiver_available flag to false and make sure the receiver exits when the update fails. Bug: 65430057 Test: unittests passed with tsan Change-Id: Icb232d13fb96c78262249ffbd29cdbe5b77f1fce
Diffstat (limited to 'tests')
-rw-r--r--tests/component/updater_test.cpp220
1 files changed, 133 insertions, 87 deletions
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index e6aec4ad..266657d3 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -23,6 +23,7 @@
23#include <algorithm> 23#include <algorithm>
24#include <memory> 24#include <memory>
25#include <string> 25#include <string>
26#include <unordered_map>
26#include <vector> 27#include <vector>
27 28
28#include <android-base/file.h> 29#include <android-base/file.h>
@@ -74,6 +75,23 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c
74 ASSERT_EQ(cause_code, state.cause_code); 75 ASSERT_EQ(cause_code, state.cause_code);
75} 76}
76 77
78static 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
77static std::string get_sha1(const std::string& content) { 95static std::string get_sha1(const std::string& content) {
78 uint8_t digest[SHA_DIGEST_LENGTH]; 96 uint8_t digest[SHA_DIGEST_LENGTH];
79 SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest); 97 SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest);
@@ -420,30 +438,19 @@ TEST_F(UpdaterTest, show_progress) {
420 ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); 438 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
421} 439}
422 440
423TEST_F(UpdaterTest, block_image_update) { 441TEST_F(UpdaterTest, block_image_update_patch_data) {
424 // Create a zip file with new_data and patch_data.
425 TemporaryFile zip_file;
426 FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
427 ZipWriter zip_writer(zip_file_ptr);
428
429 // Add a dummy new data.
430 ASSERT_EQ(0, zip_writer.StartEntry("new_data", 0));
431 ASSERT_EQ(0, zip_writer.FinishEntry());
432
433 // Generate and add the patch data.
434 std::string src_content = std::string(4096, 'a') + std::string(4096, 'c'); 442 std::string src_content = std::string(4096, 'a') + std::string(4096, 'c');
435 std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd'); 443 std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd');
444
445 // Generate the patch data.
436 TemporaryFile patch_file; 446 TemporaryFile patch_file;
437 ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()), 447 ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()),
438 src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()), 448 src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()),
439 tgt_content.size(), patch_file.path, nullptr)); 449 tgt_content.size(), patch_file.path, nullptr));
440 std::string patch_content; 450 std::string patch_content;
441 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content)); 451 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content));
442 ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
443 ASSERT_EQ(0, zip_writer.WriteBytes(patch_content.data(), patch_content.size()));
444 ASSERT_EQ(0, zip_writer.FinishEntry());
445 452
446 // Add two transfer lists. The first one contains a bsdiff; and we expect the update to succeed. 453 // Create the transfer list that contains a bsdiff.
447 std::string src_hash = get_sha1(src_content); 454 std::string src_hash = get_sha1(src_content);
448 std::string tgt_hash = get_sha1(tgt_content); 455 std::string tgt_hash = get_sha1(tgt_content);
449 std::vector<std::string> transfer_list = { 456 std::vector<std::string> transfer_list = {
@@ -456,27 +463,16 @@ TEST_F(UpdaterTest, block_image_update) {
456 src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()), 463 src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()),
457 "free " + src_hash, 464 "free " + src_hash,
458 }; 465 };
459 ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0));
460 std::string commands = android::base::Join(transfer_list, '\n');
461 ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size()));
462 ASSERT_EQ(0, zip_writer.FinishEntry());
463 466
464 // Stash and free some blocks, then fail the 2nd update intentionally. 467 std::unordered_map<std::string, std::string> entries = {
465 std::vector<std::string> fail_transfer_list = { 468 { "new_data", "" },
466 "4", 469 { "patch_data", patch_content },
467 "2", 470 { "transfer_list", android::base::Join(transfer_list, '\n') },
468 "0",
469 "2",
470 "stash " + tgt_hash + " 2,0,2",
471 "free " + tgt_hash,
472 "fail",
473 }; 471 };
474 ASSERT_EQ(0, zip_writer.StartEntry("fail_transfer_list", 0)); 472
475 std::string fail_commands = android::base::Join(fail_transfer_list, '\n'); 473 // Build the update package.
476 ASSERT_EQ(0, zip_writer.WriteBytes(fail_commands.data(), fail_commands.size())); 474 TemporaryFile zip_file;
477 ASSERT_EQ(0, zip_writer.FinishEntry()); 475 BuildUpdatePackage(entries, zip_file.release());
478 ASSERT_EQ(0, zip_writer.Finish());
479 ASSERT_EQ(0, fclose(zip_file_ptr));
480 476
481 MemMapping map; 477 MemMapping map;
482 ASSERT_TRUE(map.MapFile(zip_file.path)); 478 ASSERT_TRUE(map.MapFile(zip_file.path));
@@ -491,7 +487,7 @@ TEST_F(UpdaterTest, block_image_update) {
491 updater_info.package_zip_addr = map.addr; 487 updater_info.package_zip_addr = map.addr;
492 updater_info.package_zip_len = map.length; 488 updater_info.package_zip_len = map.length;
493 489
494 // Execute the commands in the 1st transfer list. 490 // Execute the commands in the transfer list.
495 TemporaryFile update_file; 491 TemporaryFile update_file;
496 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path)); 492 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
497 std::string script = "block_image_update(\"" + std::string(update_file.path) + 493 std::string script = "block_image_update(\"" + std::string(update_file.path) +
@@ -502,44 +498,98 @@ TEST_F(UpdaterTest, block_image_update) {
502 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content)); 498 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
503 ASSERT_EQ(tgt_hash, get_sha1(updated_content)); 499 ASSERT_EQ(tgt_hash, get_sha1(updated_content));
504 500
505 // Expect the 2nd update to fail, but expect the stashed blocks to be freed. 501 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
506 script = "block_image_update(\"" + std::string(update_file.path) + 502 CloseArchive(handle);
507 R"(", package_extract_file("fail_transfer_list"), "new_data", "patch_data"))"; 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"))";
508 expect("", script.c_str(), kNoCause, &updater_info); 542 expect("", script.c_str(), kNoCause, &updater_info);
509 // Updater generates the stash name based on the input file name. 543 // Updater generates the stash name based on the input file name.
510 std::string name_digest = get_sha1(update_file.path); 544 std::string name_digest = get_sha1(update_file.path);
511 std::string stash_base = "/cache/recovery/" + name_digest; 545 std::string stash_base = "/cache/recovery/" + name_digest;
512 ASSERT_EQ(0, access(stash_base.c_str(), F_OK)); 546 ASSERT_EQ(0, access(stash_base.c_str(), F_OK));
513 ASSERT_EQ(-1, access((stash_base + tgt_hash).c_str(), F_OK)); 547 ASSERT_EQ(-1, access((stash_base + src_hash).c_str(), F_OK));
514 ASSERT_EQ(0, rmdir(stash_base.c_str())); 548 ASSERT_EQ(0, rmdir(stash_base.c_str()));
515 549
516 ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); 550 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
517 CloseArchive(handle); 551 CloseArchive(handle);
518} 552}
519 553
520TEST_F(UpdaterTest, new_data_short_write) { 554TEST_F(UpdaterTest, new_data_over_write) {
521 // Create a zip file with new_data. 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.
522 TemporaryFile zip_file; 567 TemporaryFile zip_file;
523 FILE* zip_file_ptr = fdopen(zip_file.release(), "wb"); 568 BuildUpdatePackage(entries, zip_file.release());
524 ZipWriter zip_writer(zip_file_ptr); 569
570 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));
525 574
526 // Add the empty new data. 575 // Set up the handler, command_pipe, patch offset & length.
527 ASSERT_EQ(0, zip_writer.StartEntry("empty_new_data", 0)); 576 UpdaterInfo updater_info;
528 ASSERT_EQ(0, zip_writer.FinishEntry()); 577 updater_info.package_zip = handle;
529 // Add the short written new data. 578 TemporaryFile temp_pipe;
530 ASSERT_EQ(0, zip_writer.StartEntry("short_new_data", 0)); 579 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
531 std::string new_data_short = std::string(10, 'a'); 580 updater_info.package_zip_addr = map.addr;
532 ASSERT_EQ(0, zip_writer.WriteBytes(new_data_short.data(), new_data_short.size())); 581 updater_info.package_zip_len = map.length;
533 ASSERT_EQ(0, zip_writer.FinishEntry());
534 // Add the data of exactly one block.
535 ASSERT_EQ(0, zip_writer.StartEntry("exact_new_data", 0));
536 std::string new_data_exact = std::string(4096, 'a');
537 ASSERT_EQ(0, zip_writer.WriteBytes(new_data_exact.data(), new_data_exact.size()));
538 ASSERT_EQ(0, zip_writer.FinishEntry());
539 // Add a dummy patch data.
540 ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
541 ASSERT_EQ(0, zip_writer.FinishEntry());
542 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) {
543 std::vector<std::string> transfer_list = { 593 std::vector<std::string> transfer_list = {
544 "4", 594 "4",
545 "1", 595 "1",
@@ -547,12 +597,17 @@ TEST_F(UpdaterTest, new_data_short_write) {
547 "0", 597 "0",
548 "new 2,0,1", 598 "new 2,0,1",
549 }; 599 };
550 ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); 600
551 std::string commands = android::base::Join(transfer_list, '\n'); 601 std::unordered_map<std::string, std::string> entries = {
552 ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); 602 { "empty_new_data", "" },
553 ASSERT_EQ(0, zip_writer.FinishEntry()); 603 { "short_new_data", std::string(10, 'a') },
554 ASSERT_EQ(0, zip_writer.Finish()); 604 { "exact_new_data", std::string(4096, 'a') },
555 ASSERT_EQ(0, fclose(zip_file_ptr)); 605 { "patch_data", "" },
606 { "transfer_list", android::base::Join(transfer_list, '\n') },
607 };
608
609 TemporaryFile zip_file;
610 BuildUpdatePackage(entries, zip_file.release());
556 611
557 MemMapping map; 612 MemMapping map;
558 ASSERT_TRUE(map.MapFile(zip_file.path)); 613 ASSERT_TRUE(map.MapFile(zip_file.path));
@@ -587,14 +642,6 @@ TEST_F(UpdaterTest, new_data_short_write) {
587} 642}
588 643
589TEST_F(UpdaterTest, brotli_new_data) { 644TEST_F(UpdaterTest, brotli_new_data) {
590 // Create a zip file with new_data.
591 TemporaryFile zip_file;
592 FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
593 ZipWriter zip_writer(zip_file_ptr);
594
595 // Add a brotli compressed new data entry.
596 ASSERT_EQ(0, zip_writer.StartEntry("new.dat.br", 0));
597
598 auto generator = []() { return rand() % 128; }; 645 auto generator = []() { return rand() % 128; };
599 // Generate 100 blocks of random data. 646 // Generate 100 blocks of random data.
600 std::string brotli_new_data; 647 std::string brotli_new_data;
@@ -602,16 +649,12 @@ TEST_F(UpdaterTest, brotli_new_data) {
602 generate_n(back_inserter(brotli_new_data), 4096 * 100, generator); 649 generate_n(back_inserter(brotli_new_data), 4096 * 100, generator);
603 650
604 size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size()); 651 size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size());
605 std::vector<uint8_t> encoded_data(encoded_size); 652 std::string encoded_data(encoded_size, 0);
606 ASSERT_TRUE(BrotliEncoderCompress( 653 ASSERT_TRUE(BrotliEncoderCompress(
607 BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(), 654 BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(),
608 reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size, encoded_data.data())); 655 reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size,
609 656 reinterpret_cast<uint8_t*>(const_cast<char*>(encoded_data.data()))));
610 ASSERT_EQ(0, zip_writer.WriteBytes(encoded_data.data(), encoded_size)); 657 encoded_data.resize(encoded_size);
611 ASSERT_EQ(0, zip_writer.FinishEntry());
612 // Add a dummy patch data.
613 ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
614 ASSERT_EQ(0, zip_writer.FinishEntry());
615 658
616 // Write a few small chunks of new data, then a large chunk, and finally a few small chunks. 659 // Write a few small chunks of new data, then a large chunk, and finally a few small chunks.
617 // This helps us to catch potential short writes. 660 // This helps us to catch potential short writes.
@@ -627,12 +670,15 @@ TEST_F(UpdaterTest, brotli_new_data) {
627 "new 2,98,99", 670 "new 2,98,99",
628 "new 2,99,100", 671 "new 2,99,100",
629 }; 672 };
630 ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0)); 673
631 std::string commands = android::base::Join(transfer_list, '\n'); 674 std::unordered_map<std::string, std::string> entries = {
632 ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size())); 675 { "new.dat.br", std::move(encoded_data) },
633 ASSERT_EQ(0, zip_writer.FinishEntry()); 676 { "patch_data", "" },
634 ASSERT_EQ(0, zip_writer.Finish()); 677 { "transfer_list", android::base::Join(transfer_list, '\n') },
635 ASSERT_EQ(0, fclose(zip_file_ptr)); 678 };
679
680 TemporaryFile zip_file;
681 BuildUpdatePackage(entries, zip_file.release());
636 682
637 MemMapping map; 683 MemMapping map;
638 ASSERT_TRUE(map.MapFile(zip_file.path)); 684 ASSERT_TRUE(map.MapFile(zip_file.path));