aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTianjie Xu2018-02-08 13:53:37 -0600
committerGerrit Code Review2018-02-08 13:53:37 -0600
commit6a3646fc0306b8f8781e3f080dc2f957ae811f75 (patch)
tree708dde0ab1709b15d48084ed11024055009628da /updater/blockimg.cpp
parent7ee7e27400012c31a78563a8f78a44bdf83d5629 (diff)
parent284752e2bc2daf93778d317c47bc202c668e3d89 (diff)
downloadplatform-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.cpp181
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";
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)) {