aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTianjie Xu2017-12-05 13:04:17 -0600
committerTianjie Xu2018-02-06 18:16:49 -0600
commit284752e2bc2daf93778d317c47bc202c668e3d89 (patch)
tree8342606c8d5f7c74e53828936444e609434fba6a
parentbded087f7de69fc352c5860659e2db4478b30bdd (diff)
downloadplatform-bootable-recovery-284752e2bc2daf93778d317c47bc202c668e3d89.tar.gz
platform-bootable-recovery-284752e2bc2daf93778d317c47bc202c668e3d89.tar.xz
platform-bootable-recovery-284752e2bc2daf93778d317c47bc202c668e3d89.zip
Log the last command to cache
When performing an update, save the index and cmdline of the current command into the last command file if this command writes to the stash either explicitly of implicitly. This mitigates the overhead to update the last command file for every command. I ran a simple test on angler and the time to update 1000 times is ~2.3 seconds. Upon resuming an update, read the saved index first; then 1. In verification mode, check if all commands before the saved index have already produced the expected target blocks. If not, delete the last command file so that we will later resume the update from the start of the transfer list. 2. In update mode, skip all commands before the saved index. Therefore, we can avoid deleting stashes with duplicate id unintentionally; and also speed up the update. If an update succeeds or is unresumable, delete the last command file. Bug: 69858743 Test: Unittest passed, apply a failed update with invalid cmd on angler and check the last_command content, apply a failed update with invalid source hash and last_command is deleted. Change-Id: Ib60ba1e3c6d111d9f33097759b17dbcef97a37bf
-rw-r--r--tests/component/updater_test.cpp217
-rw-r--r--updater/blockimg.cpp181
-rw-r--r--updater/include/updater/blockimg.h3
3 files changed, 392 insertions, 9 deletions
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index d9d01d42..448fe493 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -707,3 +707,220 @@ TEST_F(UpdaterTest, brotli_new_data) {
707 ASSERT_EQ(0, fclose(updater_info.cmd_pipe)); 707 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
708 CloseArchive(handle); 708 CloseArchive(handle);
709} 709}
710
711TEST_F(UpdaterTest, last_command_update) {
712 TemporaryFile temp_file;
713 last_command_file = temp_file.path;
714
715 std::string block1 = std::string(4096, '1');
716 std::string block2 = std::string(4096, '2');
717 std::string block3 = std::string(4096, '3');
718 std::string block1_hash = get_sha1(block1);
719 std::string block2_hash = get_sha1(block2);
720 std::string block3_hash = get_sha1(block3);
721
722 // Compose the transfer list to fail the first update.
723 std::vector<std::string> transfer_list_fail = {
724 "4",
725 "2",
726 "0",
727 "2",
728 "stash " + block1_hash + " 2,0,1",
729 "move " + block1_hash + " 2,1,2 1 2,0,1",
730 "stash " + block3_hash + " 2,2,3",
731 "fail",
732 };
733
734 // Mimic a resumed update with the same transfer commands.
735 std::vector<std::string> transfer_list_continue = {
736 "4",
737 "2",
738 "0",
739 "2",
740 "stash " + block1_hash + " 2,0,1",
741 "move " + block1_hash + " 2,1,2 1 2,0,1",
742 "stash " + block3_hash + " 2,2,3",
743 "move " + block1_hash + " 2,2,3 1 2,0,1",
744 };
745
746 std::unordered_map<std::string, std::string> entries = {
747 { "new_data", "" },
748 { "patch_data", "" },
749 { "transfer_list_fail", android::base::Join(transfer_list_fail, '\n') },
750 { "transfer_list_continue", android::base::Join(transfer_list_continue, '\n') },
751 };
752
753 // Build the update package.
754 TemporaryFile zip_file;
755 BuildUpdatePackage(entries, zip_file.release());
756
757 MemMapping map;
758 ASSERT_TRUE(map.MapFile(zip_file.path));
759 ZipArchiveHandle handle;
760 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
761
762 // Set up the handler, command_pipe, patch offset & length.
763 UpdaterInfo updater_info;
764 updater_info.package_zip = handle;
765 TemporaryFile temp_pipe;
766 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
767 updater_info.package_zip_addr = map.addr;
768 updater_info.package_zip_len = map.length;
769
770 std::string src_content = block1 + block2 + block3;
771 TemporaryFile update_file;
772 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
773 std::string script =
774 "block_image_update(\"" + std::string(update_file.path) +
775 R"(", package_extract_file("transfer_list_fail"), "new_data", "patch_data"))";
776 expect("", script.c_str(), kNoCause, &updater_info);
777
778 // Expect last_command to contain the last stash command.
779 std::string last_command_content;
780 ASSERT_TRUE(android::base::ReadFileToString(last_command_file.c_str(), &last_command_content));
781 EXPECT_EQ("2\nstash " + block3_hash + " 2,2,3", last_command_content);
782 std::string updated_contents;
783 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_contents));
784 ASSERT_EQ(block1 + block1 + block3, updated_contents);
785
786 // Resume the update, expect the first 'move' to be skipped but the second 'move' to be executed.
787 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
788 std::string script_second_update =
789 "block_image_update(\"" + std::string(update_file.path) +
790 R"(", package_extract_file("transfer_list_continue"), "new_data", "patch_data"))";
791 expect("t", script_second_update.c_str(), kNoCause, &updater_info);
792 ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_contents));
793 ASSERT_EQ(block1 + block2 + block1, updated_contents);
794
795 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
796 CloseArchive(handle);
797}
798
799TEST_F(UpdaterTest, last_command_update_unresumable) {
800 TemporaryFile temp_file;
801 last_command_file = temp_file.path;
802
803 std::string block1 = std::string(4096, '1');
804 std::string block2 = std::string(4096, '2');
805 std::string block1_hash = get_sha1(block1);
806 std::string block2_hash = get_sha1(block2);
807
808 // Construct an unresumable update with source blocks mismatch.
809 std::vector<std::string> transfer_list_unresumable = {
810 "4", "2", "0", "2", "stash " + block1_hash + " 2,0,1", "move " + block2_hash + " 2,1,2 1 2,0,1",
811 };
812
813 std::unordered_map<std::string, std::string> entries = {
814 { "new_data", "" },
815 { "patch_data", "" },
816 { "transfer_list_unresumable", android::base::Join(transfer_list_unresumable, '\n') },
817 };
818
819 // Build the update package.
820 TemporaryFile zip_file;
821 BuildUpdatePackage(entries, zip_file.release());
822
823 MemMapping map;
824 ASSERT_TRUE(map.MapFile(zip_file.path));
825 ZipArchiveHandle handle;
826 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
827
828 // Set up the handler, command_pipe, patch offset & length.
829 UpdaterInfo updater_info;
830 updater_info.package_zip = handle;
831 TemporaryFile temp_pipe;
832 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
833 updater_info.package_zip_addr = map.addr;
834 updater_info.package_zip_len = map.length;
835
836 // Set up the last_command_file
837 ASSERT_TRUE(
838 android::base::WriteStringToFile("0\nstash " + block1_hash + " 2,0,1", last_command_file));
839
840 // The last_command_file will be deleted if the update encounters an unresumable failure
841 // later.
842 std::string src_content = block1 + block1;
843 TemporaryFile update_file;
844 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
845 std::string script =
846 "block_image_update(\"" + std::string(update_file.path) +
847 R"(", package_extract_file("transfer_list_unresumable"), "new_data", "patch_data"))";
848 expect("", script.c_str(), kNoCause, &updater_info);
849 ASSERT_EQ(-1, access(last_command_file.c_str(), R_OK));
850
851 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
852 CloseArchive(handle);
853}
854
855TEST_F(UpdaterTest, last_command_verify) {
856 TemporaryFile temp_file;
857 last_command_file = temp_file.path;
858
859 std::string block1 = std::string(4096, '1');
860 std::string block2 = std::string(4096, '2');
861 std::string block3 = std::string(4096, '3');
862 std::string block1_hash = get_sha1(block1);
863 std::string block2_hash = get_sha1(block2);
864 std::string block3_hash = get_sha1(block3);
865
866 std::vector<std::string> transfer_list_verify = {
867 "4",
868 "2",
869 "0",
870 "2",
871 "stash " + block1_hash + " 2,0,1",
872 "move " + block1_hash + " 2,0,1 1 2,0,1",
873 "move " + block1_hash + " 2,1,2 1 2,0,1",
874 "stash " + block3_hash + " 2,2,3",
875 };
876
877 std::unordered_map<std::string, std::string> entries = {
878 { "new_data", "" },
879 { "patch_data", "" },
880 { "transfer_list_verify", android::base::Join(transfer_list_verify, '\n') },
881 };
882
883 // Build the update package.
884 TemporaryFile zip_file;
885 BuildUpdatePackage(entries, zip_file.release());
886
887 MemMapping map;
888 ASSERT_TRUE(map.MapFile(zip_file.path));
889 ZipArchiveHandle handle;
890 ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
891
892 // Set up the handler, command_pipe, patch offset & length.
893 UpdaterInfo updater_info;
894 updater_info.package_zip = handle;
895 TemporaryFile temp_pipe;
896 updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
897 updater_info.package_zip_addr = map.addr;
898 updater_info.package_zip_len = map.length;
899
900 std::string src_content = block1 + block1 + block3;
901 TemporaryFile update_file;
902 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
903
904 ASSERT_TRUE(
905 android::base::WriteStringToFile("2\nstash " + block3_hash + " 2,2,3", last_command_file));
906
907 // Expect the verification to succeed and the last_command_file is intact.
908 std::string script_verify =
909 "block_image_verify(\"" + std::string(update_file.path) +
910 R"(", package_extract_file("transfer_list_verify"), "new_data","patch_data"))";
911 expect("t", script_verify.c_str(), kNoCause, &updater_info);
912
913 std::string last_command_content;
914 ASSERT_TRUE(android::base::ReadFileToString(last_command_file.c_str(), &last_command_content));
915 EXPECT_EQ("2\nstash " + block3_hash + " 2,2,3", last_command_content);
916
917 // Expect the verification to succeed but last_command_file to be deleted; because the target
918 // blocks don't have the expected contents for the second move command.
919 src_content = block1 + block2 + block3;
920 ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
921 expect("t", script_verify.c_str(), kNoCause, &updater_info);
922 ASSERT_EQ(-1, access(last_command_file.c_str(), R_OK));
923
924 ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
925 CloseArchive(handle);
926}
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 0e90e94a..feb2aeb2 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -34,11 +34,13 @@
34#include <fec/io.h> 34#include <fec/io.h>
35 35
36#include <functional> 36#include <functional>
37#include <limits>
37#include <memory> 38#include <memory>
38#include <string> 39#include <string>
39#include <unordered_map> 40#include <unordered_map>
40#include <vector> 41#include <vector>
41 42
43#include <android-base/file.h>
42#include <android-base/logging.h> 44#include <android-base/logging.h>
43#include <android-base/parseint.h> 45#include <android-base/parseint.h>
44#include <android-base/strings.h> 46#include <android-base/strings.h>
@@ -67,10 +69,96 @@ static constexpr const char* STASH_DIRECTORY_BASE = "/cache/recovery";
67static constexpr mode_t STASH_DIRECTORY_MODE = 0700; 69static constexpr mode_t STASH_DIRECTORY_MODE = 0700;
68static constexpr mode_t STASH_FILE_MODE = 0600; 70static constexpr mode_t STASH_FILE_MODE = 0600;
69 71
72std::string last_command_file = "/cache/recovery/last_command";
73
70static CauseCode failure_type = kNoCause; 74static CauseCode failure_type = kNoCause;
71static bool is_retry = false; 75static bool is_retry = false;
72static std::unordered_map<std::string, RangeSet> stash_map; 76static std::unordered_map<std::string, RangeSet> stash_map;
73 77
78static void DeleteLastCommandFile() {
79 if (unlink(last_command_file.c_str()) == -1 && errno != ENOENT) {
80 PLOG(ERROR) << "Failed to unlink: " << last_command_file;
81 }
82}
83
84// Parse the last command index of the last update and save the result to |last_command_index|.
85// Return true if we successfully read the index.
86static bool ParseLastCommandFile(int* last_command_index) {
87 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(last_command_file.c_str(), O_RDONLY)));
88 if (fd == -1) {
89 if (errno != ENOENT) {
90 PLOG(ERROR) << "Failed to open " << last_command_file;
91 return false;
92 }
93
94 LOG(INFO) << last_command_file << " doesn't exist.";
95 return false;
96 }
97
98 // Now that the last_command file exists, parse the last command index of previous update.
99 std::string content;
100 if (!android::base::ReadFdToString(fd.get(), &content)) {
101 LOG(ERROR) << "Failed to read: " << last_command_file;
102 return false;
103 }
104
105 std::vector<std::string> lines = android::base::Split(android::base::Trim(content), "\n");
106 if (lines.size() != 2) {
107 LOG(ERROR) << "Unexpected line counts in last command file: " << content;
108 return false;
109 }
110
111 if (!android::base::ParseInt(lines[0], last_command_index)) {
112 LOG(ERROR) << "Failed to parse integer in: " << lines[0];
113 return false;
114 }
115
116 return true;
117}
118
119// Update the last command index in the last_command_file if the current command writes to the
120// stash either explicitly or implicitly.
121static bool UpdateLastCommandIndex(int command_index, const std::string& command_string) {
122 std::string last_command_tmp = last_command_file + ".tmp";
123 std::string content = std::to_string(command_index) + "\n" + command_string;
124 android::base::unique_fd wfd(
125 TEMP_FAILURE_RETRY(open(last_command_tmp.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0660)));
126 if (wfd == -1 || !android::base::WriteStringToFd(content, wfd)) {
127 PLOG(ERROR) << "Failed to update last command";
128 return false;
129 }
130
131 if (fsync(wfd) == -1) {
132 PLOG(ERROR) << "Failed to fsync " << last_command_tmp;
133 return false;
134 }
135
136 if (chown(last_command_tmp.c_str(), AID_SYSTEM, AID_SYSTEM) == -1) {
137 PLOG(ERROR) << "Failed to change owner for " << last_command_tmp;
138 return false;
139 }
140
141 if (rename(last_command_tmp.c_str(), last_command_file.c_str()) == -1) {
142 PLOG(ERROR) << "Failed to rename" << last_command_tmp;
143 return false;
144 }
145
146 std::string last_command_dir = android::base::Dirname(last_command_file);
147 android::base::unique_fd dfd(
148 TEMP_FAILURE_RETRY(ota_open(last_command_dir.c_str(), O_RDONLY | O_DIRECTORY)));
149 if (dfd == -1) {
150 PLOG(ERROR) << "Failed to open " << last_command_dir;
151 return false;
152 }
153
154 if (fsync(dfd) == -1) {
155 PLOG(ERROR) << "Failed to fsync " << last_command_dir;
156 return false;
157 }
158
159 return true;
160}
161
74static int read_all(int fd, uint8_t* data, size_t size) { 162static int read_all(int fd, uint8_t* data, size_t size) {
75 size_t so_far = 0; 163 size_t so_far = 0;
76 while (so_far < size) { 164 while (so_far < size) {
@@ -439,6 +527,7 @@ static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer,
439struct CommandParameters { 527struct CommandParameters {
440 std::vector<std::string> tokens; 528 std::vector<std::string> tokens;
441 size_t cpos; 529 size_t cpos;
530 int cmdindex;
442 const char* cmdname; 531 const char* cmdname;
443 const char* cmdline; 532 const char* cmdline;
444 std::string freestash; 533 std::string freestash;
@@ -455,6 +544,7 @@ struct CommandParameters {
455 pthread_t thread; 544 pthread_t thread;
456 std::vector<uint8_t> buffer; 545 std::vector<uint8_t> buffer;
457 uint8_t* patch_start; 546 uint8_t* patch_start;
547 bool target_verified; // The target blocks have expected contents already.
458}; 548};
459 549
460// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is 550// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is
@@ -1072,6 +1162,10 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t*
1072 return -1; 1162 return -1;
1073 } 1163 }
1074 1164
1165 if (!UpdateLastCommandIndex(params.cmdindex, params.cmdline)) {
1166 LOG(WARNING) << "Failed to update the last command file.";
1167 }
1168
1075 params.stashed += *src_blocks; 1169 params.stashed += *src_blocks;
1076 // Can be deleted when the write has completed. 1170 // Can be deleted when the write has completed.
1077 if (!stash_exists) { 1171 if (!stash_exists) {
@@ -1112,8 +1206,11 @@ static int PerformCommandMove(CommandParameters& params) {
1112 1206
1113 if (status == 0) { 1207 if (status == 0) {
1114 params.foundwrites = true; 1208 params.foundwrites = true;
1115 } else if (params.foundwrites) { 1209 } else {
1116 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; 1210 params.target_verified = true;
1211 if (params.foundwrites) {
1212 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
1213 }
1117 } 1214 }
1118 1215
1119 if (params.canwrite) { 1216 if (params.canwrite) {
@@ -1177,8 +1274,15 @@ static int PerformCommandStash(CommandParameters& params) {
1177 } 1274 }
1178 1275
1179 LOG(INFO) << "stashing " << blocks << " blocks to " << id; 1276 LOG(INFO) << "stashing " << blocks << " blocks to " << id;
1180 params.stashed += blocks; 1277 int result = WriteStash(params.stashbase, id, blocks, params.buffer, false, nullptr);
1181 return WriteStash(params.stashbase, id, blocks, params.buffer, false, nullptr); 1278 if (result == 0) {
1279 if (!UpdateLastCommandIndex(params.cmdindex, params.cmdline)) {
1280 LOG(WARNING) << "Failed to update the last command file.";
1281 }
1282
1283 params.stashed += blocks;
1284 }
1285 return result;
1182} 1286}
1183 1287
1184static int PerformCommandFree(CommandParameters& params) { 1288static int PerformCommandFree(CommandParameters& params) {
@@ -1306,8 +1410,11 @@ static int PerformCommandDiff(CommandParameters& params) {
1306 1410
1307 if (status == 0) { 1411 if (status == 0) {
1308 params.foundwrites = true; 1412 params.foundwrites = true;
1309 } else if (params.foundwrites) { 1413 } else {
1310 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; 1414 params.target_verified = true;
1415 if (params.foundwrites) {
1416 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
1417 }
1311 } 1418 }
1312 1419
1313 if (params.canwrite) { 1420 if (params.canwrite) {
@@ -1566,6 +1673,23 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
1566 1673
1567 params.createdstash = res; 1674 params.createdstash = res;
1568 1675
1676 // When performing an update, save the index and cmdline of the current command into
1677 // the last_command_file if this command writes to the stash either explicitly of implicitly.
1678 // Upon resuming an update, read the saved index first; then
1679 // 1. In verification mode, check if the 'move' or 'diff' commands before the saved index has
1680 // the expected target blocks already. If not, these commands cannot be skipped and we need
1681 // to attempt to execute them again. Therefore, we will delete the last_command_file so that
1682 // the update will resume from the start of the transfer list.
1683 // 2. In update mode, skip all commands before the saved index. Therefore, we can avoid deleting
1684 // stashes with duplicate id unintentionally (b/69858743); and also speed up the update.
1685 // If an update succeeds or is unresumable, delete the last_command_file.
1686 int saved_last_command_index;
1687 if (!ParseLastCommandFile(&saved_last_command_index)) {
1688 DeleteLastCommandFile();
1689 // We failed to parse the last command, set it explicitly to -1.
1690 saved_last_command_index = -1;
1691 }
1692
1569 start += 2; 1693 start += 2;
1570 1694
1571 // Build a map of the available commands 1695 // Build a map of the available commands
@@ -1581,14 +1705,20 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
1581 int rc = -1; 1705 int rc = -1;
1582 1706
1583 // Subsequent lines are all individual transfer commands 1707 // Subsequent lines are all individual transfer commands
1584 for (auto it = lines.cbegin() + start; it != lines.cend(); it++) { 1708 for (size_t i = start; i < lines.size(); i++) {
1585 const std::string& line(*it); 1709 const std::string& line = lines[i];
1586 if (line.empty()) continue; 1710 if (line.empty()) continue;
1587 1711
1588 params.tokens = android::base::Split(line, " "); 1712 params.tokens = android::base::Split(line, " ");
1589 params.cpos = 0; 1713 params.cpos = 0;
1714 if (i - start > std::numeric_limits<int>::max()) {
1715 params.cmdindex = -1;
1716 } else {
1717 params.cmdindex = i - start;
1718 }
1590 params.cmdname = params.tokens[params.cpos++].c_str(); 1719 params.cmdname = params.tokens[params.cpos++].c_str();
1591 params.cmdline = line.c_str(); 1720 params.cmdline = line.c_str();
1721 params.target_verified = false;
1592 1722
1593 if (cmd_map.find(params.cmdname) == cmd_map.end()) { 1723 if (cmd_map.find(params.cmdname) == cmd_map.end()) {
1594 LOG(ERROR) << "unexpected command [" << params.cmdname << "]"; 1724 LOG(ERROR) << "unexpected command [" << params.cmdname << "]";
@@ -1597,11 +1727,38 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
1597 1727
1598 const Command* cmd = cmd_map[params.cmdname]; 1728 const Command* cmd = cmd_map[params.cmdname];
1599 1729
1600 if (cmd->f != nullptr && cmd->f(params) == -1) { 1730 if (cmd->f == nullptr) {
1731 LOG(ERROR) << "failed to find the function for command [" << line << "]";
1732 goto pbiudone;
1733 }
1734
1735 // Skip all commands before the saved last command index when resuming an update.
1736 if (params.canwrite && params.cmdindex != -1 && params.cmdindex <= saved_last_command_index) {
1737 LOG(INFO) << "Skipping already executed command: " << params.cmdindex
1738 << ", last executed command for previous update: " << saved_last_command_index;
1739 continue;
1740 }
1741
1742 if (cmd->f(params) == -1) {
1601 LOG(ERROR) << "failed to execute command [" << line << "]"; 1743 LOG(ERROR) << "failed to execute command [" << line << "]";
1602 goto pbiudone; 1744 goto pbiudone;
1603 } 1745 }
1604 1746
1747 // In verify mode, check if the commands before the saved last_command_index have been
1748 // executed correctly. If some target blocks have unexpected contents, delete the last command
1749 // file so that we will resume the update from the first command in the transfer list.
1750 if (!params.canwrite && saved_last_command_index != -1 && params.cmdindex != -1 &&
1751 params.cmdindex <= saved_last_command_index) {
1752 // TODO(xunchang) check that the cmdline of the saved index is correct.
1753 std::string cmdname = std::string(params.cmdname);
1754 if ((cmdname == "move" || cmdname == "bsdiff" || cmdname == "imgdiff") &&
1755 !params.target_verified) {
1756 LOG(WARNING) << "Previously executed command " << saved_last_command_index << ": "
1757 << params.cmdline << " doesn't produce expected target blocks.";
1758 saved_last_command_index = -1;
1759 DeleteLastCommandFile();
1760 }
1761 }
1605 if (params.canwrite) { 1762 if (params.canwrite) {
1606 if (ota_fsync(params.fd) == -1) { 1763 if (ota_fsync(params.fd) == -1) {
1607 failure_type = kFsyncFailure; 1764 failure_type = kFsyncFailure;
@@ -1643,6 +1800,7 @@ pbiudone:
1643 // Delete stash only after successfully completing the update, as it may contain blocks needed 1800 // Delete stash only after successfully completing the update, as it may contain blocks needed
1644 // to complete the update later. 1801 // to complete the update later.
1645 DeleteStash(params.stashbase); 1802 DeleteStash(params.stashbase);
1803 DeleteLastCommandFile();
1646 } 1804 }
1647 1805
1648 pthread_mutex_destroy(&params.nti.mu); 1806 pthread_mutex_destroy(&params.nti.mu);
@@ -1661,6 +1819,11 @@ pbiudone:
1661 BrotliDecoderDestroyInstance(params.nti.brotli_decoder_state); 1819 BrotliDecoderDestroyInstance(params.nti.brotli_decoder_state);
1662 } 1820 }
1663 1821
1822 // Delete the last command file if the update cannot be resumed.
1823 if (params.isunresumable) {
1824 DeleteLastCommandFile();
1825 }
1826
1664 // Only delete the stash if the update cannot be resumed, or it's a verification run and we 1827 // Only delete the stash if the update cannot be resumed, or it's a verification run and we
1665 // created the stash. 1828 // created the stash.
1666 if (params.isunresumable || (!params.canwrite && params.createdstash)) { 1829 if (params.isunresumable || (!params.canwrite && params.createdstash)) {
diff --git a/updater/include/updater/blockimg.h b/updater/include/updater/blockimg.h
index 2f4ad3c0..2cc68ce9 100644
--- a/updater/include/updater/blockimg.h
+++ b/updater/include/updater/blockimg.h
@@ -17,6 +17,9 @@
17#ifndef _UPDATER_BLOCKIMG_H_ 17#ifndef _UPDATER_BLOCKIMG_H_
18#define _UPDATER_BLOCKIMG_H_ 18#define _UPDATER_BLOCKIMG_H_
19 19
20#include <string>
21
22extern std::string last_command_file;
20void RegisterBlockImageFunctions(); 23void RegisterBlockImageFunctions();
21 24
22#endif 25#endif