diff options
author | Tianjie Xu | 2018-02-08 13:53:37 -0600 |
---|---|---|
committer | Gerrit Code Review | 2018-02-08 13:53:37 -0600 |
commit | 6a3646fc0306b8f8781e3f080dc2f957ae811f75 (patch) | |
tree | 708dde0ab1709b15d48084ed11024055009628da /updater/blockimg.cpp | |
parent | 7ee7e27400012c31a78563a8f78a44bdf83d5629 (diff) | |
parent | 284752e2bc2daf93778d317c47bc202c668e3d89 (diff) | |
download | platform-bootable-recovery-6a3646fc0306b8f8781e3f080dc2f957ae811f75.tar.gz platform-bootable-recovery-6a3646fc0306b8f8781e3f080dc2f957ae811f75.tar.xz platform-bootable-recovery-6a3646fc0306b8f8781e3f080dc2f957ae811f75.zip |
Merge "Log the last command to cache"
Diffstat (limited to 'updater/blockimg.cpp')
-rw-r--r-- | updater/blockimg.cpp | 181 |
1 files changed, 172 insertions, 9 deletions
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"; | |||
67 | static constexpr mode_t STASH_DIRECTORY_MODE = 0700; | 69 | static constexpr mode_t STASH_DIRECTORY_MODE = 0700; |
68 | static constexpr mode_t STASH_FILE_MODE = 0600; | 70 | static constexpr mode_t STASH_FILE_MODE = 0600; |
69 | 71 | ||
72 | std::string last_command_file = "/cache/recovery/last_command"; | ||
73 | |||
70 | static CauseCode failure_type = kNoCause; | 74 | static CauseCode failure_type = kNoCause; |
71 | static bool is_retry = false; | 75 | static bool is_retry = false; |
72 | static std::unordered_map<std::string, RangeSet> stash_map; | 76 | static std::unordered_map<std::string, RangeSet> stash_map; |
73 | 77 | ||
78 | static 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. | ||
86 | static 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. | ||
121 | static 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 | |||
74 | static int read_all(int fd, uint8_t* data, size_t size) { | 162 | static 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, | |||
439 | struct CommandParameters { | 527 | struct 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 | ||
1184 | static int PerformCommandFree(CommandParameters& params) { | 1288 | static 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(¶ms.nti.mu); | 1806 | pthread_mutex_destroy(¶ms.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)) { |