summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--applypatch/applypatch.cpp1044
-rw-r--r--applypatch/imgdiff.cpp32
-rw-r--r--bootloader_message/bootloader_message.cpp68
-rw-r--r--bootloader_message/include/bootloader_message/bootloader_message.h18
-rw-r--r--device.cpp32
-rw-r--r--error_code.h83
-rw-r--r--install.cpp201
-rw-r--r--minadbd/minadbd_services.cpp2
-rw-r--r--minui/font_10x18.h8
-rw-r--r--minui/graphics.cpp114
-rw-r--r--minui/graphics_adf.cpp8
-rw-r--r--minui/graphics_fbdev.cpp2
-rw-r--r--minui/minui.h16
-rw-r--r--minui/resources.cpp12
-rw-r--r--otafault/ota_io.cpp28
-rw-r--r--otafault/ota_io.h24
-rw-r--r--screen_ui.cpp10
-rw-r--r--tests/Android.mk4
-rw-r--r--tests/common/test_constants.h11
-rw-r--r--tests/component/applypatch_test.cpp175
-rw-r--r--tests/component/updater_test.cpp280
-rw-r--r--tests/unit/zip_test.cpp3
-rw-r--r--update_verifier/Android.mk5
-rw-r--r--update_verifier/update_verifier.cpp31
-rw-r--r--updater/Android.mk2
-rw-r--r--updater/install.cpp508
-rw-r--r--wear_ui.cpp12
27 files changed, 1675 insertions, 1058 deletions
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 9d505f9f6..95389da6e 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "applypatch/applypatch.h"
+
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
@@ -27,16 +29,18 @@
#include <memory>
#include <string>
+#include <utility>
+#include <vector>
+#include <android-base/parseint.h>
#include <android-base/strings.h>
+#include <openssl/sha.h>
-#include "openssl/sha.h"
-#include "applypatch/applypatch.h"
#include "edify/expr.h"
#include "ota_io.h"
#include "print_sha1.h"
-static int LoadPartitionContents(const char* filename, FileContents* file);
+static int LoadPartitionContents(const std::string& filename, FileContents* file);
static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token);
static int GenerateTarget(FileContents* source_file,
const Value* source_patch_value,
@@ -48,39 +52,34 @@ static int GenerateTarget(FileContents* source_file,
size_t target_size,
const Value* bonus_data);
-// Read a file into memory; store the file contents and associated
-// metadata in *file.
-//
+// Read a file into memory; store the file contents and associated metadata in *file.
// Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) {
- // A special 'filename' beginning with "EMMC:" means to
- // load the contents of a partition.
- if (strncmp(filename, "EMMC:", 5) == 0) {
- return LoadPartitionContents(filename, file);
- }
+ // A special 'filename' beginning with "EMMC:" means to load the contents of a partition.
+ if (strncmp(filename, "EMMC:", 5) == 0) {
+ return LoadPartitionContents(filename, file);
+ }
- if (stat(filename, &file->st) != 0) {
- printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
- return -1;
- }
+ if (stat(filename, &file->st) == -1) {
+ printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
+ return -1;
+ }
- std::vector<unsigned char> data(file->st.st_size);
- FILE* f = ota_fopen(filename, "rb");
- if (f == NULL) {
- printf("failed to open \"%s\": %s\n", filename, strerror(errno));
- return -1;
- }
+ std::vector<unsigned char> data(file->st.st_size);
+ unique_file f(ota_fopen(filename, "rb"));
+ if (!f) {
+ printf("failed to open \"%s\": %s\n", filename, strerror(errno));
+ return -1;
+ }
- size_t bytes_read = ota_fread(data.data(), 1, data.size(), f);
- if (bytes_read != data.size()) {
- printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size());
- ota_fclose(f);
- return -1;
- }
- ota_fclose(f);
- file->data = std::move(data);
- SHA1(file->data.data(), file->data.size(), file->sha1);
- return 0;
+ size_t bytes_read = ota_fread(data.data(), 1, data.size(), f.get());
+ if (bytes_read != data.size()) {
+ printf("short read of \"%s\" (%zu bytes of %zu)\n", filename, bytes_read, data.size());
+ return -1;
+ }
+ file->data = std::move(data);
+ SHA1(file->data.data(), file->data.size(), file->sha1);
+ return 0;
}
// Load the contents of an EMMC partition into the provided
@@ -97,284 +96,257 @@ int LoadFileContents(const char* filename, FileContents* file) {
// "end-of-file" marker), so the caller must specify the possible
// lengths and the hash of the data, and we'll do the load expecting
// to find one of those hashes.
-static int LoadPartitionContents(const char* filename, FileContents* file) {
- std::string copy(filename);
- std::vector<std::string> pieces = android::base::Split(copy, ":");
- if (pieces.size() < 4 || pieces.size() % 2 != 0) {
- printf("LoadPartitionContents called with bad filename (%s)\n", filename);
- return -1;
- }
-
- if (pieces[0] != "EMMC") {
- printf("LoadPartitionContents called with bad filename (%s)\n", filename);
+static int LoadPartitionContents(const std::string& filename, FileContents* file) {
+ std::vector<std::string> pieces = android::base::Split(filename, ":");
+ if (pieces.size() < 4 || pieces.size() % 2 != 0 || pieces[0] != "EMMC") {
+ printf("LoadPartitionContents called with bad filename \"%s\"\n", filename.c_str());
+ return -1;
+ }
+
+ size_t pair_count = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename
+ std::vector<std::pair<size_t, std::string>> pairs;
+ for (size_t i = 0; i < pair_count; ++i) {
+ size_t size;
+ if (!android::base::ParseUint(pieces[i * 2 + 2], &size) || size == 0) {
+ printf("LoadPartitionContents called with bad size \"%s\"\n", pieces[i * 2 + 2].c_str());
+ return -1;
+ }
+ pairs.push_back({ size, pieces[i * 2 + 3] });
+ }
+
+ // Sort the pairs array so that they are in order of increasing size.
+ std::sort(pairs.begin(), pairs.end());
+
+ const char* partition = pieces[1].c_str();
+ unique_file dev(ota_fopen(partition, "rb"));
+ if (!dev) {
+ printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno));
+ return -1;
+ }
+
+ SHA_CTX sha_ctx;
+ SHA1_Init(&sha_ctx);
+
+ // Allocate enough memory to hold the largest size.
+ std::vector<unsigned char> buffer(pairs[pair_count - 1].first);
+ unsigned char* buffer_ptr = buffer.data();
+ size_t buffer_size = 0; // # bytes read so far
+ bool found = false;
+
+ for (const auto& pair : pairs) {
+ size_t current_size = pair.first;
+ const std::string& current_sha1 = pair.second;
+
+ // Read enough additional bytes to get us up to the next size. (Again,
+ // we're trying the possibilities in order of increasing size).
+ size_t next = current_size - buffer_size;
+ if (next > 0) {
+ size_t read = ota_fread(buffer_ptr, 1, next, dev.get());
+ if (next != read) {
+ printf("short read (%zu bytes of %zu) for partition \"%s\"\n", read, next, partition);
return -1;
- }
- const char* partition = pieces[1].c_str();
-
- size_t pairs = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename
- std::vector<size_t> index(pairs);
- std::vector<size_t> size(pairs);
- std::vector<std::string> sha1sum(pairs);
-
- for (size_t i = 0; i < pairs; ++i) {
- size[i] = strtol(pieces[i*2+2].c_str(), NULL, 10);
- if (size[i] == 0) {
- printf("LoadPartitionContents called with bad size (%s)\n", filename);
- return -1;
- }
- sha1sum[i] = pieces[i*2+3].c_str();
- index[i] = i;
+ }
+ SHA1_Update(&sha_ctx, buffer_ptr, read);
+ buffer_size += read;
+ buffer_ptr += read;
}
- // Sort the index[] array so it indexes the pairs in order of increasing size.
- sort(index.begin(), index.end(),
- [&](const size_t& i, const size_t& j) {
- return (size[i] < size[j]);
- }
- );
+ // Duplicate the SHA context and finalize the duplicate so we can
+ // check it against this pair's expected hash.
+ SHA_CTX temp_ctx;
+ memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX));
+ uint8_t sha_so_far[SHA_DIGEST_LENGTH];
+ SHA1_Final(sha_so_far, &temp_ctx);
- FILE* dev = ota_fopen(partition, "rb");
- if (dev == NULL) {
- printf("failed to open emmc partition \"%s\": %s\n", partition, strerror(errno));
- return -1;
- }
-
- SHA_CTX sha_ctx;
- SHA1_Init(&sha_ctx);
uint8_t parsed_sha[SHA_DIGEST_LENGTH];
-
- // Allocate enough memory to hold the largest size.
- std::vector<unsigned char> data(size[index[pairs-1]]);
- char* p = reinterpret_cast<char*>(data.data());
- size_t data_size = 0; // # bytes read so far
- bool found = false;
-
- for (size_t i = 0; i < pairs; ++i) {
- // Read enough additional bytes to get us up to the next size. (Again,
- // we're trying the possibilities in order of increasing size).
- size_t next = size[index[i]] - data_size;
- if (next > 0) {
- size_t read = ota_fread(p, 1, next, dev);
- if (next != read) {
- printf("short read (%zu bytes of %zu) for partition \"%s\"\n",
- read, next, partition);
- return -1;
- }
- SHA1_Update(&sha_ctx, p, read);
- data_size += read;
- p += read;
- }
-
- // Duplicate the SHA context and finalize the duplicate so we can
- // check it against this pair's expected hash.
- SHA_CTX temp_ctx;
- memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX));
- uint8_t sha_so_far[SHA_DIGEST_LENGTH];
- SHA1_Final(sha_so_far, &temp_ctx);
-
- if (ParseSha1(sha1sum[index[i]].c_str(), parsed_sha) != 0) {
- printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]].c_str(), filename);
- return -1;
- }
-
- if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_LENGTH) == 0) {
- // we have a match. stop reading the partition; we'll return
- // the data we've read so far.
- printf("partition read matched size %zu sha %s\n",
- size[index[i]], sha1sum[index[i]].c_str());
- found = true;
- break;
- }
+ if (ParseSha1(current_sha1.c_str(), parsed_sha) != 0) {
+ printf("failed to parse SHA-1 %s in %s\n", current_sha1.c_str(), filename.c_str());
+ return -1;
}
- ota_fclose(dev);
-
- if (!found) {
- // Ran off the end of the list of (size,sha1) pairs without finding a match.
- printf("contents of partition \"%s\" didn't match %s\n", partition, filename);
- return -1;
+ if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_LENGTH) == 0) {
+ // We have a match. Stop reading the partition; we'll return the data we've read so far.
+ printf("partition read matched size %zu SHA-1 %s\n", current_size, current_sha1.c_str());
+ found = true;
+ break;
}
+ }
- SHA1_Final(file->sha1, &sha_ctx);
+ if (!found) {
+ // Ran off the end of the list of (size, sha1) pairs without finding a match.
+ printf("contents of partition \"%s\" didn't match %s\n", partition, filename.c_str());
+ return -1;
+ }
- data.resize(data_size);
- file->data = std::move(data);
- // Fake some stat() info.
- file->st.st_mode = 0644;
- file->st.st_uid = 0;
- file->st.st_gid = 0;
+ SHA1_Final(file->sha1, &sha_ctx);
- return 0;
+ buffer.resize(buffer_size);
+ file->data = std::move(buffer);
+ // Fake some stat() info.
+ file->st.st_mode = 0644;
+ file->st.st_uid = 0;
+ file->st.st_gid = 0;
+
+ return 0;
}
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
int SaveFileContents(const char* filename, const FileContents* file) {
- int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
- if (fd < 0) {
- printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno));
- return -1;
- }
+ unique_fd fd(ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR));
+ if (fd == -1) {
+ printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno));
+ return -1;
+ }
- ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd);
- if (bytes_written != static_cast<ssize_t>(file->data.size())) {
- printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n",
- filename, bytes_written, file->data.size(), strerror(errno));
- ota_close(fd);
- return -1;
- }
- if (ota_fsync(fd) != 0) {
- printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno));
- return -1;
- }
- if (ota_close(fd) != 0) {
- printf("close of \"%s\" failed: %s\n", filename, strerror(errno));
- return -1;
- }
+ ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd);
+ if (bytes_written != static_cast<ssize_t>(file->data.size())) {
+ printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written,
+ file->data.size(), strerror(errno));
+ return -1;
+ }
+ if (ota_fsync(fd) != 0) {
+ printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno));
+ return -1;
+ }
+ if (ota_close(fd) != 0) {
+ printf("close of \"%s\" failed: %s\n", filename, strerror(errno));
+ return -1;
+ }
- if (chmod(filename, file->st.st_mode) != 0) {
- printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
- return -1;
- }
- if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) {
- printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
- return -1;
- }
+ if (chmod(filename, file->st.st_mode) != 0) {
+ printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
+ return -1;
+ }
+ if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) {
+ printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
+ return -1;
+ }
- return 0;
+ return 0;
}
// Write a memory buffer to 'target' partition, a string of the form
// "EMMC:<partition_device>[:...]". The target name
// might contain multiple colons, but WriteToPartition() only uses the first
// two and ignores the rest. Return 0 on success.
-int WriteToPartition(const unsigned char* data, size_t len, const char* target) {
- std::string copy(target);
- std::vector<std::string> pieces = android::base::Split(copy, ":");
+int WriteToPartition(const unsigned char* data, size_t len, const std::string& target) {
+ std::vector<std::string> pieces = android::base::Split(target, ":");
+ if (pieces.size() < 2 || pieces[0] != "EMMC") {
+ printf("WriteToPartition called with bad target (%s)\n", target.c_str());
+ return -1;
+ }
- if (pieces.size() < 2) {
- printf("WriteToPartition called with bad target (%s)\n", target);
+ const char* partition = pieces[1].c_str();
+ unique_fd fd(ota_open(partition, O_RDWR));
+ if (fd == -1) {
+ printf("failed to open %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
+
+ size_t start = 0;
+ bool success = false;
+ for (size_t attempt = 0; attempt < 2; ++attempt) {
+ if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
+ printf("failed seek on %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
+ while (start < len) {
+ size_t to_write = len - start;
+ if (to_write > 1 << 20) to_write = 1 << 20;
+
+ ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data + start, to_write));
+ if (written == -1) {
+ printf("failed write writing to %s: %s\n", partition, strerror(errno));
return -1;
+ }
+ start += written;
}
- if (pieces[0] != "EMMC") {
- printf("WriteToPartition called with bad target (%s)\n", target);
- return -1;
+ if (ota_fsync(fd) != 0) {
+ printf("failed to sync to %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
+ if (ota_close(fd) != 0) {
+ printf("failed to close %s: %s\n", partition, strerror(errno));
+ return -1;
}
- const char* partition = pieces[1].c_str();
- size_t start = 0;
- bool success = false;
- int fd = ota_open(partition, O_RDWR | O_SYNC);
- if (fd < 0) {
- printf("failed to open %s: %s\n", partition, strerror(errno));
- return -1;
+ fd.reset(ota_open(partition, O_RDONLY));
+ if (fd == -1) {
+ printf("failed to reopen %s for verify: %s\n", partition, strerror(errno));
+ return -1;
}
- for (size_t attempt = 0; attempt < 2; ++attempt) {
- if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
- printf("failed seek on %s: %s\n", partition, strerror(errno));
- return -1;
- }
- while (start < len) {
- size_t to_write = len - start;
- if (to_write > 1<<20) to_write = 1<<20;
-
- ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write));
- if (written == -1) {
- printf("failed write writing to %s: %s\n", partition, strerror(errno));
- return -1;
- }
- start += written;
- }
- if (ota_fsync(fd) != 0) {
- printf("failed to sync to %s (%s)\n", partition, strerror(errno));
- return -1;
- }
- if (ota_close(fd) != 0) {
- printf("failed to close %s (%s)\n", partition, strerror(errno));
- return -1;
- }
- fd = ota_open(partition, O_RDONLY);
- if (fd < 0) {
- printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno));
- return -1;
- }
+ // Drop caches so our subsequent verification read won't just be reading the cache.
+ sync();
+ unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY));
+ if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
+ printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
+ } else {
+ printf(" caches dropped\n");
+ }
+ ota_close(dc);
+ sleep(1);
- // Drop caches so our subsequent verification read
- // won't just be reading the cache.
- sync();
- int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY);
- if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
- printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
- } else {
- printf(" caches dropped\n");
- }
- ota_close(dc);
- sleep(1);
+ // Verify.
+ if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
+ printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
- // verify
- if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
- printf("failed to seek back to beginning of %s: %s\n",
- partition, strerror(errno));
- return -1;
+ unsigned char buffer[4096];
+ start = len;
+ for (size_t p = 0; p < len; p += sizeof(buffer)) {
+ size_t to_read = len - p;
+ if (to_read > sizeof(buffer)) {
+ to_read = sizeof(buffer);
+ }
+
+ size_t so_far = 0;
+ while (so_far < to_read) {
+ ssize_t read_count = TEMP_FAILURE_RETRY(ota_read(fd, buffer + so_far, to_read - so_far));
+ if (read_count == -1) {
+ printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno));
+ return -1;
+ } else if (read_count == 0) {
+ printf("verify read reached unexpected EOF, %s at %zu\n", partition, p);
+ return -1;
}
- unsigned char buffer[4096];
- start = len;
- for (size_t p = 0; p < len; p += sizeof(buffer)) {
- size_t to_read = len - p;
- if (to_read > sizeof(buffer)) {
- to_read = sizeof(buffer);
- }
-
- size_t so_far = 0;
- while (so_far < to_read) {
- ssize_t read_count =
- TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far));
- if (read_count == -1) {
- printf("verify read error %s at %zu: %s\n",
- partition, p, strerror(errno));
- return -1;
- } else if (read_count == 0) {
- printf("verify read reached unexpected EOF, %s at %zu\n", partition, p);
- return -1;
- }
- if (static_cast<size_t>(read_count) < to_read) {
- printf("short verify read %s at %zu: %zd %zu %s\n",
- partition, p, read_count, to_read, strerror(errno));
- }
- so_far += read_count;
- }
-
- if (memcmp(buffer, data+p, to_read) != 0) {
- printf("verification failed starting at %zu\n", p);
- start = p;
- break;
- }
+ if (static_cast<size_t>(read_count) < to_read) {
+ printf("short verify read %s at %zu: %zd %zu\n", partition, p, read_count, to_read);
}
+ so_far += read_count;
+ }
- if (start == len) {
- printf("verification read succeeded (attempt %zu)\n", attempt+1);
- success = true;
- break;
- }
+ if (memcmp(buffer, data + p, to_read) != 0) {
+ printf("verification failed starting at %zu\n", p);
+ start = p;
+ break;
+ }
}
- if (!success) {
- printf("failed to verify after all attempts\n");
- return -1;
+ if (start == len) {
+ printf("verification read succeeded (attempt %zu)\n", attempt + 1);
+ success = true;
+ break;
}
+ }
- if (ota_close(fd) != 0) {
- printf("error closing %s (%s)\n", partition, strerror(errno));
- return -1;
- }
- sync();
+ if (!success) {
+ printf("failed to verify after all attempts\n");
+ return -1;
+ }
- return 0;
-}
+ if (ota_close(fd) == -1) {
+ printf("error closing %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
+ sync();
+ return 0;
+}
// Take a string 'str' of 40 hex digits and parse it into the 20
// byte array 'digest'. 'str' may contain only the digest or be of
@@ -409,48 +381,46 @@ int ParseSha1(const char* str, uint8_t* digest) {
// Return the index of the match on success, or -1 if no match is
// found.
int FindMatchingPatch(uint8_t* sha1, const std::vector<std::string>& patch_sha1_str) {
- for (size_t i = 0; i < patch_sha1_str.size(); ++i) {
- uint8_t patch_sha1[SHA_DIGEST_LENGTH];
- if (ParseSha1(patch_sha1_str[i].c_str(), patch_sha1) == 0 &&
- memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) {
- return i;
- }
- }
- return -1;
+ for (size_t i = 0; i < patch_sha1_str.size(); ++i) {
+ uint8_t patch_sha1[SHA_DIGEST_LENGTH];
+ if (ParseSha1(patch_sha1_str[i].c_str(), patch_sha1) == 0 &&
+ memcmp(patch_sha1, sha1, SHA_DIGEST_LENGTH) == 0) {
+ return i;
+ }
+ }
+ return -1;
}
// Returns 0 if the contents of the file (argv[2]) or the cached file
// match any of the sha1's on the command line (argv[3:]). Returns
// nonzero otherwise.
int applypatch_check(const char* filename, const std::vector<std::string>& patch_sha1_str) {
- FileContents file;
-
- // It's okay to specify no sha1s; the check will pass if the
- // LoadFileContents is successful. (Useful for reading
- // partitions, where the filename encodes the sha1s; no need to
- // check them twice.)
- if (LoadFileContents(filename, &file) != 0 ||
- (patch_sha1_str.size() > 0 && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) {
- printf("file \"%s\" doesn't have any of expected "
- "sha1 sums; checking cache\n", filename);
-
- // If the source file is missing or corrupted, it might be because
- // we were killed in the middle of patching it. A copy of it
- // should have been made in CACHE_TEMP_SOURCE. If that file
- // exists and matches the sha1 we're looking for, the check still
- // passes.
-
- if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
- printf("failed to load cache file\n");
- return 1;
- }
-
- if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) {
- printf("cache bits don't match any sha1 for \"%s\"\n", filename);
- return 1;
- }
- }
- return 0;
+ FileContents file;
+
+ // It's okay to specify no sha1s; the check will pass if the
+ // LoadFileContents is successful. (Useful for reading
+ // partitions, where the filename encodes the sha1s; no need to
+ // check them twice.)
+ if (LoadFileContents(filename, &file) != 0 ||
+ (!patch_sha1_str.empty() && FindMatchingPatch(file.sha1, patch_sha1_str) < 0)) {
+ printf("file \"%s\" doesn't have any of expected sha1 sums; checking cache\n", filename);
+
+ // If the source file is missing or corrupted, it might be because
+ // we were killed in the middle of patching it. A copy of it
+ // should have been made in CACHE_TEMP_SOURCE. If that file
+ // exists and matches the sha1 we're looking for, the check still
+ // passes.
+ if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
+ printf("failed to load cache file\n");
+ return 1;
+ }
+
+ if (FindMatchingPatch(file.sha1, patch_sha1_str) < 0) {
+ printf("cache bits don't match any sha1 for \"%s\"\n", filename);
+ return 1;
+ }
+ }
+ return 0;
}
int ShowLicenses() {
@@ -544,10 +514,8 @@ int applypatch(const char* source_filename,
return 1;
}
- FileContents copy_file;
FileContents source_file;
const Value* source_patch_value = nullptr;
- const Value* copy_patch_value = nullptr;
// We try to load the target file into the source_file object.
if (LoadFileContents(target_filename, &source_file) == 0) {
@@ -575,6 +543,8 @@ int applypatch(const char* source_filename,
}
}
+ FileContents copy_file;
+ const Value* copy_patch_value = nullptr;
if (source_patch_value == nullptr) {
source_file.data.clear();
printf("source file is bad; trying copy\n");
@@ -612,50 +582,49 @@ int applypatch(const char* source_filename,
*/
int applypatch_flash(const char* source_filename, const char* target_filename,
const char* target_sha1_str, size_t target_size) {
- printf("flash %s: ", target_filename);
-
- uint8_t target_sha1[SHA_DIGEST_LENGTH];
- if (ParseSha1(target_sha1_str, target_sha1) != 0) {
- printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
- return 1;
- }
-
- FileContents source_file;
- std::string target_str(target_filename);
-
- std::vector<std::string> pieces = android::base::Split(target_str, ":");
- if (pieces.size() != 2 || pieces[0] != "EMMC") {
- printf("invalid target name \"%s\"", target_filename);
- return 1;
- }
-
- // Load the target into the source_file object to see if already applied.
- pieces.push_back(std::to_string(target_size));
- pieces.push_back(target_sha1_str);
- std::string fullname = android::base::Join(pieces, ':');
- if (LoadPartitionContents(fullname.c_str(), &source_file) == 0 &&
- memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) {
- // The early-exit case: the image was already applied, this partition
- // has the desired hash, nothing for us to do.
- printf("already %s\n", short_sha1(target_sha1).c_str());
- return 0;
- }
-
- if (LoadFileContents(source_filename, &source_file) == 0) {
- if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) {
- // The source doesn't have desired checksum.
- printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename);
- printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(),
- short_sha1(source_file.sha1).c_str());
- return 1;
- }
- }
-
- if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) {
- printf("write of copied data to %s failed\n", target_filename);
- return 1;
- }
+ printf("flash %s: ", target_filename);
+
+ uint8_t target_sha1[SHA_DIGEST_LENGTH];
+ if (ParseSha1(target_sha1_str, target_sha1) != 0) {
+ printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
+ return 1;
+ }
+
+ std::string target_str(target_filename);
+ std::vector<std::string> pieces = android::base::Split(target_str, ":");
+ if (pieces.size() != 2 || pieces[0] != "EMMC") {
+ printf("invalid target name \"%s\"", target_filename);
+ return 1;
+ }
+
+ // Load the target into the source_file object to see if already applied.
+ pieces.push_back(std::to_string(target_size));
+ pieces.push_back(target_sha1_str);
+ std::string fullname = android::base::Join(pieces, ':');
+ FileContents source_file;
+ if (LoadPartitionContents(fullname, &source_file) == 0 &&
+ memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) == 0) {
+ // The early-exit case: the image was already applied, this partition
+ // has the desired hash, nothing for us to do.
+ printf("already %s\n", short_sha1(target_sha1).c_str());
return 0;
+ }
+
+ if (LoadFileContents(source_filename, &source_file) == 0) {
+ if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) {
+ // The source doesn't have desired checksum.
+ printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename);
+ printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(),
+ short_sha1(source_file.sha1).c_str());
+ return 1;
+ }
+ }
+
+ if (WriteToPartition(source_file.data.data(), target_size, target_filename) != 0) {
+ printf("write of copied data to %s failed\n", target_filename);
+ return 1;
+ }
+ return 0;
}
static int GenerateTarget(FileContents* source_file,
@@ -667,221 +636,214 @@ static int GenerateTarget(FileContents* source_file,
const uint8_t target_sha1[SHA_DIGEST_LENGTH],
size_t target_size,
const Value* bonus_data) {
- int retry = 1;
- SHA_CTX ctx;
- std::string memory_sink_str;
- FileContents* source_to_use;
- int made_copy = 0;
-
- bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
- const std::string tmp_target_filename = std::string(target_filename) + ".patch";
-
- // assume that target_filename (eg "/system/app/Foo.apk") is located
- // on the same filesystem as its top-level directory ("/system").
- // We need something that exists for calling statfs().
- std::string target_fs = target_filename;
- auto slash_pos = target_fs.find('/', 1);
- if (slash_pos != std::string::npos) {
- target_fs.resize(slash_pos);
- }
-
- const Value* patch;
- if (source_patch_value != NULL) {
- source_to_use = source_file;
- patch = source_patch_value;
- } else {
- source_to_use = copy_file;
- patch = copy_patch_value;
- }
- if (patch->type != VAL_BLOB) {
- printf("patch is not a blob\n");
+ // assume that target_filename (eg "/system/app/Foo.apk") is located
+ // on the same filesystem as its top-level directory ("/system").
+ // We need something that exists for calling statfs().
+ std::string target_fs = target_filename;
+ auto slash_pos = target_fs.find('/', 1);
+ if (slash_pos != std::string::npos) {
+ target_fs.resize(slash_pos);
+ }
+
+ FileContents* source_to_use;
+ const Value* patch;
+ if (source_patch_value != nullptr) {
+ source_to_use = source_file;
+ patch = source_patch_value;
+ } else {
+ source_to_use = copy_file;
+ patch = copy_patch_value;
+ }
+
+ if (patch->type != VAL_BLOB) {
+ printf("patch is not a blob\n");
+ return 1;
+ }
+
+ const char* header = &patch->data[0];
+ size_t header_bytes_read = patch->data.size();
+ bool use_bsdiff = false;
+ if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) {
+ use_bsdiff = true;
+ } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) {
+ use_bsdiff = false;
+ } else {
+ printf("Unknown patch file format\n");
+ return 1;
+ }
+
+ bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
+ const std::string tmp_target_filename = std::string(target_filename) + ".patch";
+
+ int retry = 1;
+ bool made_copy = false;
+ SHA_CTX ctx;
+ std::string memory_sink_str; // Don't need to reserve space.
+ do {
+ // Is there enough room in the target filesystem to hold the patched file?
+
+ if (target_is_partition) {
+ // If the target is a partition, we're actually going to
+ // write the output to /tmp and then copy it to the
+ // partition. statfs() always returns 0 blocks free for
+ // /tmp, so instead we'll just assume that /tmp has enough
+ // space to hold the file.
+
+ // We still write the original source to cache, in case
+ // the partition write is interrupted.
+ if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
+ printf("not enough free space on /cache\n");
return 1;
- }
- const char* header = &patch->data[0];
- size_t header_bytes_read = patch->data.size();
- bool use_bsdiff = false;
- if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) {
- use_bsdiff = true;
- } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) {
- use_bsdiff = false;
- } else {
- printf("Unknown patch file format\n");
+ }
+ if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
+ printf("failed to back up source file\n");
return 1;
- }
-
- do {
- // Is there enough room in the target filesystem to hold the patched
- // file?
-
- if (target_is_partition) {
- // If the target is a partition, we're actually going to
- // write the output to /tmp and then copy it to the
- // partition. statfs() always returns 0 blocks free for
- // /tmp, so instead we'll just assume that /tmp has enough
- // space to hold the file.
-
- // We still write the original source to cache, in case
- // the partition write is interrupted.
- if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
- printf("not enough free space on /cache\n");
- return 1;
- }
- if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
- printf("failed to back up source file\n");
- return 1;
- }
- made_copy = 1;
- retry = 0;
- } else {
- int enough_space = 0;
- if (retry > 0) {
- size_t free_space = FreeSpaceForFile(target_fs.c_str());
- enough_space =
- (free_space > (256 << 10)) && // 256k (two-block) minimum
- (free_space > (target_size * 3 / 2)); // 50% margin of error
- if (!enough_space) {
- printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n",
- target_size, free_space, retry, enough_space);
- }
- }
-
- if (!enough_space) {
- retry = 0;
- }
-
- if (!enough_space && source_patch_value != NULL) {
- // Using the original source, but not enough free space. First
- // copy the source file to cache, then delete it from the original
- // location.
-
- if (strncmp(source_filename, "EMMC:", 5) == 0) {
- // It's impossible to free space on the target filesystem by
- // deleting the source if the source is a partition. If
- // we're ever in a state where we need to do this, fail.
- printf("not enough free space for target but source is partition\n");
- return 1;
- }
-
- if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
- printf("not enough free space on /cache\n");
- return 1;
- }
-
- if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
- printf("failed to back up source file\n");
- return 1;
- }
- made_copy = 1;
- unlink(source_filename);
-
- size_t free_space = FreeSpaceForFile(target_fs.c_str());
- printf("(now %zu bytes free for target) ", free_space);
- }
- }
-
-
- SinkFn sink = NULL;
- void* token = NULL;
- int output_fd = -1;
- if (target_is_partition) {
- // We store the decoded output in memory.
- sink = MemorySink;
- token = &memory_sink_str;
- } else {
- // We write the decoded output to "<tgt-file>.patch".
- output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
- S_IRUSR | S_IWUSR);
- if (output_fd < 0) {
- printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(),
- strerror(errno));
- return 1;
- }
- sink = FileSink;
- token = &output_fd;
+ }
+ made_copy = true;
+ retry = 0;
+ } else {
+ bool enough_space = false;
+ if (retry > 0) {
+ size_t free_space = FreeSpaceForFile(target_fs.c_str());
+ enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum
+ (free_space > (target_size * 3 / 2)); // 50% margin of error
+ if (!enough_space) {
+ printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", target_size,
+ free_space, retry, enough_space);
}
+ }
+ if (!enough_space) {
+ retry = 0;
+ }
- SHA1_Init(&ctx);
+ if (!enough_space && source_patch_value != nullptr) {
+ // Using the original source, but not enough free space. First
+ // copy the source file to cache, then delete it from the original
+ // location.
- int result;
- if (use_bsdiff) {
- result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(),
- patch, 0, sink, token, &ctx);
- } else {
- result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(),
- patch, sink, token, &ctx, bonus_data);
+ if (strncmp(source_filename, "EMMC:", 5) == 0) {
+ // It's impossible to free space on the target filesystem by
+ // deleting the source if the source is a partition. If
+ // we're ever in a state where we need to do this, fail.
+ printf("not enough free space for target but source is partition\n");
+ return 1;
}
- if (!target_is_partition) {
- if (ota_fsync(output_fd) != 0) {
- printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(),
- strerror(errno));
- result = 1;
- }
- if (ota_close(output_fd) != 0) {
- printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(),
- strerror(errno));
- result = 1;
- }
+ if (MakeFreeSpaceOnCache(source_file->data.size()) < 0) {
+ printf("not enough free space on /cache\n");
+ return 1;
}
- if (result != 0) {
- if (retry == 0) {
- printf("applying patch failed\n");
- return result != 0;
- } else {
- printf("applying patch failed; retrying\n");
- }
- if (!target_is_partition) {
- unlink(tmp_target_filename.c_str());
- }
- } else {
- // succeeded; no need to retry
- break;
+ if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
+ printf("failed to back up source file\n");
+ return 1;
}
- } while (retry-- > 0);
+ made_copy = true;
+ unlink(source_filename);
- uint8_t current_target_sha1[SHA_DIGEST_LENGTH];
- SHA1_Final(current_target_sha1, &ctx);
- if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) {
- printf("patch did not produce expected sha1\n");
- return 1;
- } else {
- printf("now %s\n", short_sha1(target_sha1).c_str());
+ size_t free_space = FreeSpaceForFile(target_fs.c_str());
+ printf("(now %zu bytes free for target) ", free_space);
+ }
}
+ SinkFn sink = nullptr;
+ void* token = nullptr;
+ unique_fd output_fd;
if (target_is_partition) {
- // Copy the temp file to the partition.
- if (WriteToPartition(reinterpret_cast<const unsigned char*>(memory_sink_str.c_str()),
- memory_sink_str.size(), target_filename) != 0) {
- printf("write of patched data to %s failed\n", target_filename);
- return 1;
- }
+ // We store the decoded output in memory.
+ sink = MemorySink;
+ token = &memory_sink_str;
} else {
- // Give the .patch file the same owner, group, and mode of the
- // original source file.
- if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) {
- printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
- return 1;
- }
- if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
- printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
- return 1;
- }
+ // We write the decoded output to "<tgt-file>.patch".
+ output_fd.reset(ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
+ S_IRUSR | S_IWUSR));
+ if (output_fd == -1) {
+ printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno));
+ return 1;
+ }
+ sink = FileSink;
+ token = &output_fd;
+ }
- // Finally, rename the .patch file to replace the target file.
- if (rename(tmp_target_filename.c_str(), target_filename) != 0) {
- printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno));
- return 1;
- }
+ SHA1_Init(&ctx);
+
+ int result;
+ if (use_bsdiff) {
+ result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0,
+ sink, token, &ctx);
+ } else {
+ result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink,
+ token, &ctx, bonus_data);
}
- // If this run of applypatch created the copy, and we're here, we
- // can delete it.
- if (made_copy) {
- unlink(CACHE_TEMP_SOURCE);
+ if (!target_is_partition) {
+ if (ota_fsync(output_fd) != 0) {
+ printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno));
+ result = 1;
+ }
+ if (ota_close(output_fd) != 0) {
+ printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno));
+ result = 1;
+ }
}
- // Success!
- return 0;
+ if (result != 0) {
+ if (retry == 0) {
+ printf("applying patch failed\n");
+ return 1;
+ } else {
+ printf("applying patch failed; retrying\n");
+ }
+ if (!target_is_partition) {
+ unlink(tmp_target_filename.c_str());
+ }
+ } else {
+ // succeeded; no need to retry
+ break;
+ }
+ } while (retry-- > 0);
+
+ uint8_t current_target_sha1[SHA_DIGEST_LENGTH];
+ SHA1_Final(current_target_sha1, &ctx);
+ if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_LENGTH) != 0) {
+ printf("patch did not produce expected sha1\n");
+ return 1;
+ } else {
+ printf("now %s\n", short_sha1(target_sha1).c_str());
+ }
+
+ if (target_is_partition) {
+ // Copy the temp file to the partition.
+ if (WriteToPartition(reinterpret_cast<const unsigned char*>(memory_sink_str.c_str()),
+ memory_sink_str.size(), target_filename) != 0) {
+ printf("write of patched data to %s failed\n", target_filename);
+ return 1;
+ }
+ } else {
+ // Give the .patch file the same owner, group, and mode of the original source file.
+ if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) {
+ printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
+ return 1;
+ }
+ if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid,
+ source_to_use->st.st_gid) != 0) {
+ printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
+ return 1;
+ }
+
+ // Finally, rename the .patch file to replace the target file.
+ if (rename(tmp_target_filename.c_str(), target_filename) != 0) {
+ printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno));
+ return 1;
+ }
+ }
+
+ // If this run of applypatch created the copy, and we're here, we can delete it.
+ if (made_copy) {
+ unlink(CACHE_TEMP_SOURCE);
+ }
+
+ // Success!
+ return 0;
}
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index e78a60477..4dc481093 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -189,7 +189,7 @@ unsigned char* ReadZip(const char* filename,
}
size_t sz = static_cast<size_t>(st.st_size);
- unsigned char* img = reinterpret_cast<unsigned char*>(malloc(sz));
+ unsigned char* img = static_cast<unsigned char*>(malloc(sz));
FILE* f = fopen(filename, "rb");
if (fread(img, 1, sz, f) != sz) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
@@ -216,7 +216,7 @@ unsigned char* ReadZip(const char* filename,
int cdcount = Read2(img+i+8);
int cdoffset = Read4(img+i+16);
- ZipFileEntry* temp_entries = reinterpret_cast<ZipFileEntry*>(malloc(
+ ZipFileEntry* temp_entries = static_cast<ZipFileEntry*>(malloc(
cdcount * sizeof(ZipFileEntry)));
int entrycount = 0;
@@ -235,7 +235,7 @@ unsigned char* ReadZip(const char* filename,
int mlen = Read2(cd+32); // file comment len
int hoffset = Read4(cd+42); // local header offset
- char* filename = reinterpret_cast<char*>(malloc(nlen+1));
+ char* filename = static_cast<char*>(malloc(nlen+1));
memcpy(filename, cd+46, nlen);
filename[nlen] = '\0';
@@ -284,7 +284,7 @@ unsigned char* ReadZip(const char* filename,
#endif
*num_chunks = 0;
- *chunks = reinterpret_cast<ImageChunk*>(malloc((entrycount*2+2) * sizeof(ImageChunk)));
+ *chunks = static_cast<ImageChunk*>(malloc((entrycount*2+2) * sizeof(ImageChunk)));
ImageChunk* curr = *chunks;
if (include_pseudo_chunk) {
@@ -309,7 +309,7 @@ unsigned char* ReadZip(const char* filename,
curr->filename = temp_entries[nextentry].filename;
curr->len = temp_entries[nextentry].uncomp_len;
- curr->data = reinterpret_cast<unsigned char*>(malloc(curr->len));
+ curr->data = static_cast<unsigned char*>(malloc(curr->len));
z_stream strm;
strm.zalloc = Z_NULL;
@@ -379,7 +379,7 @@ unsigned char* ReadImage(const char* filename,
}
size_t sz = static_cast<size_t>(st.st_size);
- unsigned char* img = reinterpret_cast<unsigned char*>(malloc(sz + 4));
+ unsigned char* img = static_cast<unsigned char*>(malloc(sz + 4));
FILE* f = fopen(filename, "rb");
if (fread(img, 1, sz, f) != sz) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
@@ -409,7 +409,7 @@ unsigned char* ReadImage(const char* filename,
size_t chunk_offset = pos;
*num_chunks += 3;
- *chunks = reinterpret_cast<ImageChunk*>(realloc(*chunks,
+ *chunks = static_cast<ImageChunk*>(realloc(*chunks,
*num_chunks * sizeof(ImageChunk)));
ImageChunk* curr = *chunks + (*num_chunks-3);
@@ -432,7 +432,7 @@ unsigned char* ReadImage(const char* filename,
size_t allocated = 32768;
curr->len = 0;
- curr->data = reinterpret_cast<unsigned char*>(malloc(allocated));
+ curr->data = static_cast<unsigned char*>(malloc(allocated));
curr->start = pos;
curr->deflate_data = p;
@@ -460,7 +460,7 @@ unsigned char* ReadImage(const char* filename,
curr->len = allocated - strm.avail_out;
if (strm.avail_out == 0) {
allocated *= 2;
- curr->data = reinterpret_cast<unsigned char*>(realloc(curr->data, allocated));
+ curr->data = static_cast<unsigned char*>(realloc(curr->data, allocated));
}
} while (ret != Z_STREAM_END);
@@ -503,7 +503,7 @@ unsigned char* ReadImage(const char* filename,
// Reallocate the list for every chunk; we expect the number of
// chunks to be small (5 for typical boot and recovery images).
++*num_chunks;
- *chunks = reinterpret_cast<ImageChunk*>(realloc(*chunks, *num_chunks * sizeof(ImageChunk)));
+ *chunks = static_cast<ImageChunk*>(realloc(*chunks, *num_chunks * sizeof(ImageChunk)));
ImageChunk* curr = *chunks + (*num_chunks-1);
curr->start = pos;
@@ -586,7 +586,7 @@ int ReconstructDeflateChunk(ImageChunk* chunk) {
return -1;
}
- unsigned char* out = reinterpret_cast<unsigned char*>(malloc(BUFFER_SIZE));
+ unsigned char* out = static_cast<unsigned char*>(malloc(BUFFER_SIZE));
// We only check two combinations of encoder parameters: level 6
// (the default) and level 9 (the maximum).
@@ -647,7 +647,7 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) {
size_t sz = static_cast<size_t>(st.st_size);
// TODO: Memory leak on error return.
- unsigned char* data = reinterpret_cast<unsigned char*>(malloc(sz));
+ unsigned char* data = static_cast<unsigned char*>(malloc(sz));
if (tgt->type == CHUNK_NORMAL && tgt->len <= sz) {
unlink(ptemp);
@@ -814,7 +814,7 @@ int main(int argc, char** argv) {
return 1;
}
bonus_size = st.st_size;
- bonus_data = reinterpret_cast<unsigned char*>(malloc(bonus_size));
+ bonus_data = static_cast<unsigned char*>(malloc(bonus_size));
FILE* f = fopen(argv[2], "rb");
if (f == NULL) {
printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
@@ -960,9 +960,9 @@ int main(int argc, char** argv) {
DumpChunks(src_chunks, num_src_chunks);
printf("Construct patches for %d chunks...\n", num_tgt_chunks);
- unsigned char** patch_data = reinterpret_cast<unsigned char**>(malloc(
+ unsigned char** patch_data = static_cast<unsigned char**>(malloc(
num_tgt_chunks * sizeof(unsigned char*)));
- size_t* patch_size = reinterpret_cast<size_t*>(malloc(num_tgt_chunks * sizeof(size_t)));
+ size_t* patch_size = static_cast<size_t*>(malloc(num_tgt_chunks * sizeof(size_t)));
for (i = 0; i < num_tgt_chunks; ++i) {
if (zip_mode) {
ImageChunk* src;
@@ -976,7 +976,7 @@ int main(int argc, char** argv) {
} else {
if (i == 1 && bonus_data) {
printf(" using %zu bytes of bonus data for chunk %d\n", bonus_size, i);
- src_chunks[i].data = reinterpret_cast<unsigned char*>(realloc(src_chunks[i].data,
+ src_chunks[i].data = static_cast<unsigned char*>(realloc(src_chunks[i].data,
src_chunks[i].len + bonus_size));
memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data, bonus_size);
src_chunks[i].len += bonus_size;
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
index f6f8005f6..9a5671843 100644
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -80,26 +80,23 @@ static bool wait_for_device(const std::string& blk_device, std::string* err) {
return ret == 0;
}
-static bool read_misc_partition(void* p, size_t size, size_t offset, std::string* err) {
- std::string misc_blk_device = get_misc_blk_device(err);
- if (misc_blk_device.empty()) {
- return false;
- }
+static bool read_misc_partition(void* p, size_t size, const std::string& misc_blk_device,
+ size_t offset, std::string* err) {
if (!wait_for_device(misc_blk_device, err)) {
return false;
}
android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY));
- if (fd.get() == -1) {
+ if (fd == -1) {
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
strerror(errno));
return false;
}
- if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
+ if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
*err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
strerror(errno));
return false;
}
- if (!android::base::ReadFully(fd.get(), p, size)) {
+ if (!android::base::ReadFully(fd, p, size)) {
*err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(),
strerror(errno));
return false;
@@ -107,29 +104,25 @@ static bool read_misc_partition(void* p, size_t size, size_t offset, std::string
return true;
}
-static bool write_misc_partition(const void* p, size_t size, size_t offset, std::string* err) {
- std::string misc_blk_device = get_misc_blk_device(err);
- if (misc_blk_device.empty()) {
- return false;
- }
- android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY | O_SYNC));
- if (fd.get() == -1) {
+static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
+ size_t offset, std::string* err) {
+ android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
+ if (fd == -1) {
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
strerror(errno));
return false;
}
- if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
+ if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
*err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
strerror(errno));
return false;
}
- if (!android::base::WriteFully(fd.get(), p, size)) {
+ if (!android::base::WriteFully(fd, p, size)) {
*err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(),
strerror(errno));
return false;
}
- // TODO: O_SYNC and fsync duplicates each other?
- if (fsync(fd.get()) == -1) {
+ if (fsync(fd) == -1) {
*err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
strerror(errno));
return false;
@@ -137,12 +130,32 @@ static bool write_misc_partition(const void* p, size_t size, size_t offset, std:
return true;
}
+bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
+ std::string* err) {
+ return read_misc_partition(boot, sizeof(*boot), misc_blk_device,
+ BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
+}
+
bool read_bootloader_message(bootloader_message* boot, std::string* err) {
- return read_misc_partition(boot, sizeof(*boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
+ std::string misc_blk_device = get_misc_blk_device(err);
+ if (misc_blk_device.empty()) {
+ return false;
+ }
+ return read_bootloader_message_from(boot, misc_blk_device, err);
+}
+
+bool write_bootloader_message_to(const bootloader_message& boot, const std::string& misc_blk_device,
+ std::string* err) {
+ return write_misc_partition(&boot, sizeof(boot), misc_blk_device,
+ BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
}
bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
- return write_misc_partition(&boot, sizeof(boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
+ std::string misc_blk_device = get_misc_blk_device(err);
+ if (misc_blk_device.empty()) {
+ return false;
+ }
+ return write_bootloader_message_to(boot, misc_blk_device, err);
}
bool clear_bootloader_message(std::string* err) {
@@ -177,12 +190,21 @@ bool write_reboot_bootloader(std::string* err) {
}
bool read_wipe_package(std::string* package_data, size_t size, std::string* err) {
+ std::string misc_blk_device = get_misc_blk_device(err);
+ if (misc_blk_device.empty()) {
+ return false;
+ }
package_data->resize(size);
- return read_misc_partition(&(*package_data)[0], size, WIPE_PACKAGE_OFFSET_IN_MISC, err);
+ return read_misc_partition(&(*package_data)[0], size, misc_blk_device,
+ WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
bool write_wipe_package(const std::string& package_data, std::string* err) {
- return write_misc_partition(package_data.data(), package_data.size(),
+ std::string misc_blk_device = get_misc_blk_device(err);
+ if (misc_blk_device.empty()) {
+ return false;
+ }
+ return write_misc_partition(package_data.data(), package_data.size(), misc_blk_device,
WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index 5a5dd8793..e45f42487 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -178,15 +178,33 @@ static_assert(sizeof(struct bootloader_control) ==
#include <string>
#include <vector>
+// Read bootloader message into boot. Error message will be set in err.
bool read_bootloader_message(bootloader_message* boot, std::string* err);
+
+// Read bootloader message from the specified misc device into boot.
+bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
+ std::string* err);
+
+// Write bootloader message to BCB.
bool write_bootloader_message(const bootloader_message& boot, std::string* err);
+
+// Write bootloader message to the specified BCB device.
+bool write_bootloader_message_to(const bootloader_message& boot,
+ const std::string& misc_blk_device, std::string* err);
+
+// Write bootloader message (boots into recovery with the options) to BCB.
bool write_bootloader_message(const std::vector<std::string>& options, std::string* err);
+
+// Clear BCB.
bool clear_bootloader_message(std::string* err);
// Writes the reboot-bootloader reboot reason to the bootloader_message.
bool write_reboot_bootloader(std::string* err);
+// Read the wipe package from BCB (from offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool read_wipe_package(std::string* package_data, size_t size, std::string* err);
+
+// Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool write_wipe_package(const std::string& package_data, std::string* err);
#else
diff --git a/device.cpp b/device.cpp
index f8fbb8a49..e717dddf7 100644
--- a/device.cpp
+++ b/device.cpp
@@ -16,36 +16,15 @@
#include "device.h"
-#if defined(AB_OTA_UPDATER)
-
-static const char* MENU_ITEMS[] = {
- "Reboot system now",
- "Reboot to bootloader",
- "Wipe data/factory reset",
- "Mount /system",
- "Run graphics test",
- "Power off",
- NULL,
-};
-
-static const Device::BuiltinAction MENU_ACTIONS[] = {
- Device::REBOOT,
- Device::REBOOT_BOOTLOADER,
- Device::WIPE_DATA,
- Device::MOUNT_SYSTEM,
- Device::RUN_GRAPHICS_TEST,
- Device::SHUTDOWN,
-};
-
-#else
-
static const char* MENU_ITEMS[] = {
"Reboot system now",
"Reboot to bootloader",
"Apply update from ADB",
"Apply update from SD card",
"Wipe data/factory reset",
+#ifndef AB_OTA_UPDATER
"Wipe cache partition",
+#endif // !AB_OTA_UPDATER
"Mount /system",
"View recovery logs",
"Run graphics test",
@@ -59,14 +38,19 @@ static const Device::BuiltinAction MENU_ACTIONS[] = {
Device::APPLY_ADB_SIDELOAD,
Device::APPLY_SDCARD,
Device::WIPE_DATA,
+#ifndef AB_OTA_UPDATER
Device::WIPE_CACHE,
+#endif // !AB_OTA_UPDATER
Device::MOUNT_SYSTEM,
Device::VIEW_RECOVERY_LOGS,
Device::RUN_GRAPHICS_TEST,
Device::SHUTDOWN,
};
-#endif
+static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
+ sizeof(MENU_ACTIONS) / sizeof(MENU_ACTIONS[0]) + 1,
+ "MENU_ITEMS and MENU_ACTIONS should have the same length, "
+ "except for the extra NULL entry in MENU_ITEMS.");
const char* const* Device::GetMenuItems() {
return MENU_ITEMS;
diff --git a/error_code.h b/error_code.h
index 92e93bdea..92b1574d4 100644
--- a/error_code.h
+++ b/error_code.h
@@ -18,52 +18,53 @@
#define _ERROR_CODE_H_
enum ErrorCode {
- kNoError = -1,
- kLowBattery = 20,
- kZipVerificationFailure,
- kZipOpenFailure,
- kBootreasonInBlacklist
+ kNoError = -1,
+ kLowBattery = 20,
+ kZipVerificationFailure,
+ kZipOpenFailure,
+ kBootreasonInBlacklist
};
enum CauseCode {
- kNoCause = -1,
- kArgsParsingFailure = 100,
- kStashCreationFailure,
- kFileOpenFailure,
- kLseekFailure,
- kFreadFailure,
- kFwriteFailure,
- kFsyncFailure,
- kLibfecFailure,
- kFileGetPropFailure,
- kFileRenameFailure,
- kSymlinkFailure,
- kSetMetadataFailure,
- kTune2FsFailure,
- kRebootFailure,
- kVendorFailure = 200
+ kNoCause = -1,
+ kArgsParsingFailure = 100,
+ kStashCreationFailure,
+ kFileOpenFailure,
+ kLseekFailure,
+ kFreadFailure,
+ kFwriteFailure,
+ kFsyncFailure,
+ kLibfecFailure,
+ kFileGetPropFailure,
+ kFileRenameFailure,
+ kSymlinkFailure,
+ kSetMetadataFailure,
+ kTune2FsFailure,
+ kRebootFailure,
+ kPackageExtractFileFailure,
+ kVendorFailure = 200
};
enum UncryptErrorCode {
- kUncryptNoError = -1,
- kUncryptErrorHolder = 50,
- kUncryptTimeoutError = 100,
- kUncryptFileRemoveError,
- kUncryptFileOpenError,
- kUncryptSocketOpenError,
- kUncryptSocketWriteError,
- kUncryptSocketListenError,
- kUncryptSocketAcceptError,
- kUncryptFstabReadError,
- kUncryptFileStatError,
- kUncryptBlockOpenError,
- kUncryptIoctlError,
- kUncryptReadError,
- kUncryptWriteError,
- kUncryptFileSyncError,
- kUncryptFileCloseError,
- kUncryptFileRenameError,
- kUncryptPackageMissingError,
+ kUncryptNoError = -1,
+ kUncryptErrorHolder = 50,
+ kUncryptTimeoutError = 100,
+ kUncryptFileRemoveError,
+ kUncryptFileOpenError,
+ kUncryptSocketOpenError,
+ kUncryptSocketWriteError,
+ kUncryptSocketListenError,
+ kUncryptSocketAcceptError,
+ kUncryptFstabReadError,
+ kUncryptFileStatError,
+ kUncryptBlockOpenError,
+ kUncryptIoctlError,
+ kUncryptReadError,
+ kUncryptWriteError,
+ kUncryptFileSyncError,
+ kUncryptFileCloseError,
+ kUncryptFileRenameError,
+ kUncryptPackageMissingError,
};
-#endif
+#endif // _ERROR_CODE_H_
diff --git a/install.cpp b/install.cpp
index 3871271f7..f124a2688 100644
--- a/install.cpp
+++ b/install.cpp
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <limits.h>
#include <string.h>
#include <sys/stat.h>
@@ -24,6 +25,8 @@
#include <unistd.h>
#include <chrono>
+#include <limits>
+#include <map>
#include <string>
#include <vector>
@@ -32,6 +35,7 @@
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <cutils/properties.h>
#include <ziparchive/zip_archive.h>
#include "common.h"
@@ -44,6 +48,8 @@
#include "verifier.h"
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
+static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
+static constexpr const char* AB_OTA_PAYLOAD = "payload.bin";
#define PUBLIC_KEYS_FILE "/res/keys"
static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata";
static constexpr const char* UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";
@@ -118,13 +124,146 @@ static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::stri
}
}
-// If the package contains an update binary, extract it and run it.
+// Extract the update binary from the open zip archive |zip| located at |path|
+// and store into |cmd| the command line that should be called. The |status_fd|
+// is the file descriptor the child process should use to report back the
+// progress of the update.
static int
-try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
- std::vector<std::string>& log_buffer, int retry_count)
+update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
+ int status_fd, std::vector<std::string>* cmd);
+
+#ifdef AB_OTA_UPDATER
+
+// Parses the metadata of the OTA package in |zip| and checks whether we are
+// allowed to accept this A/B package. Downgrading is not allowed unless
+// explicitly enabled in the package and only for incremental packages.
+static int check_newer_ab_build(ZipArchiveHandle zip)
{
- read_source_target_build(zip, log_buffer);
+ std::string metadata_str;
+ if (!read_metadata_from_package(zip, &metadata_str)) {
+ return INSTALL_CORRUPT;
+ }
+ std::map<std::string, std::string> metadata;
+ for (const std::string& line : android::base::Split(metadata_str, "\n")) {
+ size_t eq = line.find('=');
+ if (eq != std::string::npos) {
+ metadata[line.substr(0, eq)] = line.substr(eq + 1);
+ }
+ }
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.product.device", value, "");
+ const std::string& pkg_device = metadata["pre-device"];
+ if (pkg_device != value || pkg_device.empty()) {
+ LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << value;
+ return INSTALL_ERROR;
+ }
+
+ // We allow the package to not have any serialno, but if it has a non-empty
+ // value it should match.
+ property_get("ro.serialno", value, "");
+ const std::string& pkg_serial_no = metadata["serialno"];
+ if (!pkg_serial_no.empty() && pkg_serial_no != value) {
+ LOG(ERROR) << "Package is for serial " << pkg_serial_no;
+ return INSTALL_ERROR;
+ }
+
+ if (metadata["ota-type"] != "AB") {
+ LOG(ERROR) << "Package is not A/B";
+ return INSTALL_ERROR;
+ }
+
+ // Incremental updates should match the current build.
+ property_get("ro.build.version.incremental", value, "");
+ const std::string& pkg_pre_build = metadata["pre-build-incremental"];
+ if (!pkg_pre_build.empty() && pkg_pre_build != value) {
+ LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected " << value;
+ return INSTALL_ERROR;
+ }
+ property_get("ro.build.fingerprint", value, "");
+ const std::string& pkg_pre_build_fingerprint = metadata["pre-build"];
+ if (!pkg_pre_build_fingerprint.empty() &&
+ pkg_pre_build_fingerprint != value) {
+ LOG(ERROR) << "Package is for source build " << pkg_pre_build_fingerprint
+ << " but expected " << value;
+ return INSTALL_ERROR;
+ }
+
+ // Check for downgrade version.
+ int64_t build_timestamp = property_get_int64(
+ "ro.build.date.utc", std::numeric_limits<int64_t>::max());
+ int64_t pkg_post_timestamp = 0;
+ // We allow to full update to the same version we are running, in case there
+ // is a problem with the current copy of that version.
+ if (metadata["post-timestamp"].empty() ||
+ !android::base::ParseInt(metadata["post-timestamp"].c_str(),
+ &pkg_post_timestamp) ||
+ pkg_post_timestamp < build_timestamp) {
+ if (metadata["ota-downgrade"] != "yes") {
+ LOG(ERROR) << "Update package is older than the current build, expected a build "
+ "newer than timestamp " << build_timestamp << " but package has "
+ "timestamp " << pkg_post_timestamp << " and downgrade not allowed.";
+ return INSTALL_ERROR;
+ }
+ if (pkg_pre_build_fingerprint.empty()) {
+ LOG(ERROR) << "Downgrade package must have a pre-build version set, not allowed.";
+ return INSTALL_ERROR;
+ }
+ }
+
+ return 0;
+}
+
+static int
+update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
+ int status_fd, std::vector<std::string>* cmd)
+{
+ int ret = check_newer_ab_build(zip);
+ if (ret) {
+ return ret;
+ }
+ // For A/B updates we extract the payload properties to a buffer and obtain
+ // the RAW payload offset in the zip file.
+ ZipString property_name(AB_OTA_PAYLOAD_PROPERTIES);
+ ZipEntry properties_entry;
+ if (FindEntry(zip, property_name, &properties_entry) != 0) {
+ LOG(ERROR) << "Can't find " << AB_OTA_PAYLOAD_PROPERTIES;
+ return INSTALL_CORRUPT;
+ }
+ std::vector<uint8_t> payload_properties(
+ properties_entry.uncompressed_length);
+ if (ExtractToMemory(zip, &properties_entry, payload_properties.data(),
+ properties_entry.uncompressed_length) != 0) {
+ LOG(ERROR) << "Can't extract " << AB_OTA_PAYLOAD_PROPERTIES;
+ return INSTALL_CORRUPT;
+ }
+
+ ZipString payload_name(AB_OTA_PAYLOAD);
+ ZipEntry payload_entry;
+ if (FindEntry(zip, payload_name, &payload_entry) != 0) {
+ LOG(ERROR) << "Can't find " << AB_OTA_PAYLOAD;
+ return INSTALL_CORRUPT;
+ }
+ long payload_offset = payload_entry.offset;
+ *cmd = {
+ "/sbin/update_engine_sideload",
+ android::base::StringPrintf("--payload=file://%s", path),
+ android::base::StringPrintf("--offset=%ld", payload_offset),
+ "--headers=" + std::string(payload_properties.begin(),
+ payload_properties.end()),
+ android::base::StringPrintf("--status_fd=%d", status_fd),
+ };
+ return 0;
+}
+
+#else // !AB_OTA_UPDATER
+
+static int
+update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
+ int status_fd, std::vector<std::string>* cmd)
+{
+ // On traditional updates we extract the update binary from the package.
ZipString binary_name(ASSUMED_UPDATE_BINARY_NAME);
ZipEntry binary_entry;
if (FindEntry(zip, binary_name, &binary_entry) != 0) {
@@ -147,9 +286,36 @@ try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
return INSTALL_ERROR;
}
+ *cmd = {
+ binary,
+ EXPAND(RECOVERY_API_VERSION), // defined in Android.mk
+ std::to_string(status_fd),
+ path,
+ };
+ if (retry_count > 0)
+ cmd->push_back("retry");
+ return 0;
+}
+#endif // !AB_OTA_UPDATER
+
+// If the package contains an update binary, extract it and run it.
+static int
+try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
+ std::vector<std::string>& log_buffer, int retry_count)
+{
+ read_source_target_build(zip, log_buffer);
+
int pipefd[2];
pipe(pipefd);
+ std::vector<std::string> args;
+ int ret = update_binary_command(path, zip, retry_count, pipefd[1], &args);
+ if (ret) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return ret;
+ }
+
// When executing the update binary contained in the package, the
// arguments passed are:
//
@@ -199,22 +365,27 @@ try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
// update attempt.
//
- const char* args[6];
- args[0] = binary;
- args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
- char temp[16];
- snprintf(temp, sizeof(temp), "%d", pipefd[1]);
- args[2] = temp;
- args[3] = path;
- args[4] = retry_count > 0 ? "retry" : NULL;
- args[5] = NULL;
+ // Convert the vector to a NULL-terminated char* array suitable for execv.
+ const char* chr_args[args.size() + 1];
+ chr_args[args.size()] = NULL;
+ for (size_t i = 0; i < args.size(); i++) {
+ chr_args[i] = args[i].c_str();
+ }
pid_t pid = fork();
+
+ if (pid == -1) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ PLOG(ERROR) << "Failed to fork update binary";
+ return INSTALL_ERROR;
+ }
+
if (pid == 0) {
umask(022);
close(pipefd[0]);
- execv(binary, const_cast<char**>(args));
- fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
+ execv(chr_args[0], const_cast<char**>(chr_args));
+ fprintf(stdout, "E:Can't run %s (%s)\n", chr_args[0], strerror(errno));
_exit(-1);
}
close(pipefd[1]);
diff --git a/minadbd/minadbd_services.cpp b/minadbd/minadbd_services.cpp
index 003b51913..426d982eb 100644
--- a/minadbd/minadbd_services.cpp
+++ b/minadbd/minadbd_services.cpp
@@ -66,7 +66,7 @@ static int create_service_thread(void (*func)(int, void *), void *cookie) {
return -1;
}
- stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
+ stinfo* sti = static_cast<stinfo*>(malloc(sizeof(stinfo)));
if(sti == 0) fatal("cannot allocate stinfo");
sti->func = func;
sti->cookie = cookie;
diff --git a/minui/font_10x18.h b/minui/font_10x18.h
index 29d705344..30dfb9c56 100644
--- a/minui/font_10x18.h
+++ b/minui/font_10x18.h
@@ -1,14 +1,14 @@
struct {
unsigned width;
unsigned height;
- unsigned cwidth;
- unsigned cheight;
+ unsigned char_width;
+ unsigned char_height;
unsigned char rundata[2973];
} font = {
.width = 960,
.height = 18,
- .cwidth = 10,
- .cheight = 18,
+ .char_width = 10,
+ .char_height = 18,
.rundata = {
0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x55,0x82,0x06,0x82,0x02,0x82,0x10,0x82,
0x11,0x83,0x08,0x82,0x0a,0x82,0x04,0x82,0x46,0x82,0x08,0x82,0x07,0x84,0x06,
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index c0eea9e38..dcca3ec41 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -35,12 +35,6 @@
#include "minui.h"
#include "graphics.h"
-struct GRFont {
- GRSurface* texture;
- int cwidth;
- int cheight;
-};
-
static GRFont* gr_font = NULL;
static minui_backend* gr_backend = NULL;
@@ -60,15 +54,20 @@ static bool outside(int x, int y)
return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
}
-int gr_measure(const char *s)
+const GRFont* gr_sys_font()
+{
+ return gr_font;
+}
+
+int gr_measure(const GRFont* font, const char *s)
{
- return gr_font->cwidth * strlen(s);
+ return font->char_width * strlen(s);
}
-void gr_font_size(int *x, int *y)
+void gr_font_size(const GRFont* font, int *x, int *y)
{
- *x = gr_font->cwidth;
- *y = gr_font->cheight;
+ *x = font->char_width;
+ *y = font->char_height;
}
static void text_blend(unsigned char* src_p, int src_row_bytes,
@@ -103,34 +102,32 @@ static void text_blend(unsigned char* src_p, int src_row_bytes,
}
}
-void gr_text(int x, int y, const char *s, bool bold)
+void gr_text(const GRFont* font, int x, int y, const char *s, bool bold)
{
- GRFont* font = gr_font;
-
if (!font->texture || gr_current_a == 0) return;
- bold = bold && (font->texture->height != font->cheight);
+ bold = bold && (font->texture->height != font->char_height);
x += overscan_offset_x;
y += overscan_offset_y;
unsigned char ch;
while ((ch = *s++)) {
- if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break;
+ if (outside(x, y) || outside(x+font->char_width-1, y+font->char_height-1)) break;
if (ch < ' ' || ch > '~') {
ch = '?';
}
- unsigned char* src_p = font->texture->data + ((ch - ' ') * font->cwidth) +
- (bold ? font->cheight * font->texture->row_bytes : 0);
+ unsigned char* src_p = font->texture->data + ((ch - ' ') * font->char_width) +
+ (bold ? font->char_height * font->texture->row_bytes : 0);
unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
text_blend(src_p, font->texture->row_bytes,
dst_p, gr_draw->row_bytes,
- font->cwidth, font->cheight);
+ font->char_width, font->char_height);
- x += font->cwidth;
+ x += font->char_width;
}
}
@@ -267,40 +264,59 @@ unsigned int gr_get_height(GRSurface* surface) {
return surface->height;
}
+int gr_init_font(const char* name, GRFont** dest) {
+ GRFont* font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
+ if (font == nullptr) {
+ return -1;
+ }
+
+ int res = res_create_alpha_surface(name, &(font->texture));
+ if (res < 0) {
+ free(font);
+ return res;
+ }
+
+ // The font image should be a 96x2 array of character images. The
+ // columns are the printable ASCII characters 0x20 - 0x7f. The
+ // top row is regular text; the bottom row is bold.
+ font->char_width = font->texture->width / 96;
+ font->char_height = font->texture->height / 2;
+
+ *dest = font;
+
+ return 0;
+}
+
static void gr_init_font(void)
{
- gr_font = reinterpret_cast<GRFont*>(calloc(sizeof(*gr_font), 1));
-
- int res = res_create_alpha_surface("font", &(gr_font->texture));
+ int res = gr_init_font("font", &gr_font);
if (res == 0) {
- // The font image should be a 96x2 array of character images. The
- // columns are the printable ASCII characters 0x20 - 0x7f. The
- // top row is regular text; the bottom row is bold.
- gr_font->cwidth = gr_font->texture->width / 96;
- gr_font->cheight = gr_font->texture->height / 2;
- } else {
- printf("failed to read font: res=%d\n", res);
-
- // fall back to the compiled-in font.
- gr_font->texture = reinterpret_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
- gr_font->texture->width = font.width;
- gr_font->texture->height = font.height;
- gr_font->texture->row_bytes = font.width;
- gr_font->texture->pixel_bytes = 1;
-
- unsigned char* bits = reinterpret_cast<unsigned char*>(malloc(font.width * font.height));
- gr_font->texture->data = reinterpret_cast<unsigned char*>(bits);
-
- unsigned char data;
- unsigned char* in = font.rundata;
- while((data = *in++)) {
- memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
- bits += (data & 0x7f);
- }
+ return;
+ }
+
+ printf("failed to read font: res=%d\n", res);
+
- gr_font->cwidth = font.cwidth;
- gr_font->cheight = font.cheight;
+ // fall back to the compiled-in font.
+ gr_font = static_cast<GRFont*>(calloc(sizeof(*gr_font), 1));
+ gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
+ gr_font->texture->width = font.width;
+ gr_font->texture->height = font.height;
+ gr_font->texture->row_bytes = font.width;
+ gr_font->texture->pixel_bytes = 1;
+
+ unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height));
+ gr_font->texture->data = bits;
+
+ unsigned char data;
+ unsigned char* in = font.rundata;
+ while((data = *in++)) {
+ memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
+ bits += (data & 0x7f);
}
+
+ gr_font->char_width = font.char_width;
+ gr_font->char_height = font.char_height;
}
#if 0
diff --git a/minui/graphics_adf.cpp b/minui/graphics_adf.cpp
index 3c3541094..9e262b044 100644
--- a/minui/graphics_adf.cpp
+++ b/minui/graphics_adf.cpp
@@ -68,9 +68,9 @@ static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surfa
surf->base.row_bytes = surf->pitch;
surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4;
- surf->base.data = reinterpret_cast<uint8_t*>(mmap(NULL,
- surf->pitch * surf->base.height, PROT_WRITE,
- MAP_SHARED, surf->fd, surf->offset));
+ surf->base.data = static_cast<uint8_t*>(mmap(NULL,
+ surf->pitch * surf->base.height, PROT_WRITE,
+ MAP_SHARED, surf->fd, surf->offset));
if (surf->base.data == MAP_FAILED) {
close(surf->fd);
return -errno;
@@ -259,7 +259,7 @@ static void adf_exit(minui_backend *backend)
minui_backend *open_adf()
{
- adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
+ adf_pdata* pdata = static_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
if (!pdata) {
perror("allocating adf backend failed");
return NULL;
diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp
index 0788f7552..631ef4e13 100644
--- a/minui/graphics_fbdev.cpp
+++ b/minui/graphics_fbdev.cpp
@@ -133,7 +133,7 @@ static GRSurface* fbdev_init(minui_backend* backend) {
gr_framebuffer[0].height = vi.yres;
gr_framebuffer[0].row_bytes = fi.line_length;
gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
- gr_framebuffer[0].data = reinterpret_cast<uint8_t*>(bits);
+ gr_framebuffer[0].data = static_cast<uint8_t*>(bits);
memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
/* check if we can use double buffering */
diff --git a/minui/minui.h b/minui/minui.h
index 5362d3fe3..78890b84b 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -33,6 +33,12 @@ struct GRSurface {
unsigned char* data;
};
+struct GRFont {
+ GRSurface* texture;
+ int char_width;
+ int char_height;
+};
+
int gr_init();
void gr_exit();
@@ -45,10 +51,14 @@ void gr_fb_blank(bool blank);
void gr_clear(); // clear entire surface to current color
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void gr_fill(int x1, int y1, int x2, int y2);
-void gr_text(int x, int y, const char *s, bool bold);
+
void gr_texticon(int x, int y, GRSurface* icon);
-int gr_measure(const char *s);
-void gr_font_size(int *x, int *y);
+
+const GRFont* gr_sys_font();
+int gr_init_font(const char* name, GRFont** dest);
+void gr_text(const GRFont* font, int x, int y, const char *s, bool bold);
+int gr_measure(const GRFont* font, const char *s);
+void gr_font_size(const GRFont* font, int *x, int *y);
void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
unsigned int gr_get_width(GRSurface* surface);
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 455ef2784..9ccbf4b1b 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -37,7 +37,7 @@
static GRSurface* malloc_surface(size_t data_size) {
size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT;
- unsigned char* temp = reinterpret_cast<unsigned char*>(malloc(size));
+ unsigned char* temp = static_cast<unsigned char*>(malloc(size));
if (temp == NULL) return NULL;
GRSurface* surface = reinterpret_cast<GRSurface*>(temp);
surface->data = temp + sizeof(GRSurface) +
@@ -221,7 +221,7 @@ int res_create_display_surface(const char* name, GRSurface** pSurface) {
png_set_bgr(png_ptr);
#endif
- p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
+ p_row = static_cast<unsigned char*>(malloc(width * 4));
for (y = 0; y < height; ++y) {
png_read_row(png_ptr, p_row, NULL);
transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
@@ -281,7 +281,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
goto exit;
}
- surface = reinterpret_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
+ surface = static_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*)));
if (surface == NULL) {
result = -8;
goto exit;
@@ -298,7 +298,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
png_set_bgr(png_ptr);
#endif
- p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
+ p_row = static_cast<unsigned char*>(malloc(width * 4));
for (y = 0; y < height; ++y) {
png_read_row(png_ptr, p_row, NULL);
int frame = y % *frames;
@@ -308,7 +308,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps,
}
free(p_row);
- *pSurface = reinterpret_cast<GRSurface**>(surface);
+ *pSurface = surface;
exit:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
@@ -436,7 +436,7 @@ int res_create_localized_alpha_surface(const char* name,
memcpy(surface->data + i*w, row.data(), w);
}
- *pSurface = reinterpret_cast<GRSurface*>(surface);
+ *pSurface = surface;
break;
} else {
int i;
diff --git a/otafault/ota_io.cpp b/otafault/ota_io.cpp
index 2efd3004a..f5b01136f 100644
--- a/otafault/ota_io.cpp
+++ b/otafault/ota_io.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <map>
+#include "ota_io.h"
#include <errno.h>
#include <fcntl.h>
@@ -22,8 +22,10 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <map>
+#include <memory>
+
#include "config.h"
-#include "ota_io.h"
static std::map<intptr_t, const char*> filename_cache;
static std::string read_fault_file_name = "";
@@ -68,17 +70,33 @@ FILE* ota_fopen(const char* path, const char* mode) {
return fh;
}
-int ota_close(int fd) {
+static int __ota_close(int fd) {
// descriptors can be reused, so make sure not to leave them in the cache
filename_cache.erase(fd);
return close(fd);
}
-int ota_fclose(FILE* fh) {
- filename_cache.erase((intptr_t)fh);
+void OtaCloser::Close(int fd) {
+ __ota_close(fd);
+}
+
+int ota_close(unique_fd& fd) {
+ return __ota_close(fd.release());
+}
+
+static int __ota_fclose(FILE* fh) {
+ filename_cache.erase(reinterpret_cast<intptr_t>(fh));
return fclose(fh);
}
+void OtaFcloser::operator()(FILE* f) {
+ __ota_fclose(f);
+};
+
+int ota_fclose(unique_file& fh) {
+ return __ota_fclose(fh.release());
+}
+
size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
if (should_fault_inject(OTAIO_READ)) {
auto cached = filename_cache.find((intptr_t)stream);
diff --git a/otafault/ota_io.h b/otafault/ota_io.h
index 84187a76e..395b4230e 100644
--- a/otafault/ota_io.h
+++ b/otafault/ota_io.h
@@ -26,6 +26,10 @@
#include <stdio.h>
#include <sys/stat.h>
+#include <memory>
+
+#include <android-base/unique_fd.h>
+
#define OTAIO_CACHE_FNAME "/cache/saved.file"
void ota_set_fault_files();
@@ -36,10 +40,6 @@ int ota_open(const char* path, int oflags, mode_t mode);
FILE* ota_fopen(const char* filename, const char* mode);
-int ota_close(int fd);
-
-int ota_fclose(FILE* fh);
-
size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream);
ssize_t ota_read(int fd, void* buf, size_t nbyte);
@@ -50,4 +50,20 @@ ssize_t ota_write(int fd, const void* buf, size_t nbyte);
int ota_fsync(int fd);
+struct OtaCloser {
+ static void Close(int);
+};
+
+using unique_fd = android::base::unique_fd_impl<OtaCloser>;
+
+int ota_close(unique_fd& fd);
+
+struct OtaFcloser {
+ void operator()(FILE*);
+};
+
+using unique_file = std::unique_ptr<FILE, OtaFcloser>;
+
+int ota_fclose(unique_file& fh);
+
#endif
diff --git a/screen_ui.cpp b/screen_ui.cpp
index c61727258..fab348964 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -248,7 +248,7 @@ void ScreenRecoveryUI::DrawHorizontalRule(int* y) {
}
void ScreenRecoveryUI::DrawTextLine(int x, int* y, const char* line, bool bold) {
- gr_text(x, *y, line, bold);
+ gr_text(gr_sys_font(), x, *y, line, bold);
*y += char_height_ + 4;
}
@@ -304,10 +304,10 @@ void ScreenRecoveryUI::draw_screen_locked() {
gr_fill(0, y - 2, gr_fb_width(), y + char_height_ + 2);
// Bold white text for the selected item.
SetColor(MENU_SEL_FG);
- gr_text(4, y, menu_[i], true);
+ gr_text(gr_sys_font(), 4, y, menu_[i], true);
SetColor(MENU);
} else {
- gr_text(4, y, menu_[i], false);
+ gr_text(gr_sys_font(), 4, y, menu_[i], false);
}
y += char_height_ + 4;
}
@@ -323,7 +323,7 @@ void ScreenRecoveryUI::draw_screen_locked() {
for (int ty = gr_fb_height() - char_height_;
ty >= y && count < text_rows_;
ty -= char_height_, ++count) {
- gr_text(0, ty, text_[row], false);
+ gr_text(gr_sys_font(), 0, ty, text_[row], false);
--row;
if (row < 0) row = text_rows_ - 1;
}
@@ -442,7 +442,7 @@ void ScreenRecoveryUI::Init() {
density_ = static_cast<float>(android::base::GetIntProperty("ro.sf.lcd_density", 160)) / 160.f;
is_large_ = gr_fb_height() > PixelsFromDp(800);
- gr_font_size(&char_width_, &char_height_);
+ gr_font_size(gr_sys_font(), &char_width_, &char_height_);
text_rows_ = gr_fb_height() / char_height_;
text_cols_ = gr_fb_width() / char_width_;
diff --git a/tests/Android.mk b/tests/Android.mk
index e87a22964..5f6a7ce0c 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -80,10 +80,12 @@ LOCAL_STATIC_LIBRARIES := \
libedify \
libotafault \
libupdater \
+ libbootloader_message \
libverifier \
libminui \
libotautil \
libmounts \
+ libfs_mgr \
liblog \
libselinux \
libext4_utils_static \
@@ -92,6 +94,8 @@ LOCAL_STATIC_LIBRARIES := \
libcrypto \
libcutils \
libbz \
+ libziparchive \
+ libutils \
libz \
libbase \
libtune2fs \
diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h
index 97e74a3c2..f6b6922a4 100644
--- a/tests/common/test_constants.h
+++ b/tests/common/test_constants.h
@@ -19,6 +19,17 @@
#include <stdlib.h>
+// Zip entries in ziptest_valid.zip.
+static const std::string kATxtContents("abcdefghabcdefgh\n");
+static const std::string kBTxtContents("abcdefgh\n");
+static const std::string kCTxtContents("abcdefghabcdefgh\n");
+static const std::string kDTxtContents("abcdefgh\n");
+
+// echo -n -e "abcdefghabcdefgh\n" | sha1sum
+static const std::string kATxtSha1Sum("32c96a03dc8cd20097940f351bca6261ee5a1643");
+// echo -n -e "abcdefgh\n" | sha1sum
+static const std::string kBTxtSha1Sum("e414af7161c9554089f4106d6f1797ef14a73666");
+
static const char* data_root = getenv("ANDROID_DATA");
static std::string from_testdata_base(const std::string& fname) {
diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp
index 1a0b19113..d178303aa 100644
--- a/tests/component/applypatch_test.cpp
+++ b/tests/component/applypatch_test.cpp
@@ -83,15 +83,11 @@ class ApplyPatchTest : public ::testing::Test {
ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file));
// set up SHA constants
- sha1sum(old_file, &old_sha1);
- sha1sum(new_file, &new_sha1);
+ sha1sum(old_file, &old_sha1, &old_size);
+ sha1sum(new_file, &new_sha1, &new_size);
srand(time(nullptr));
bad_sha1_a = android::base::StringPrintf("%040x", rand());
bad_sha1_b = android::base::StringPrintf("%040x", rand());
-
- struct stat st;
- stat(&new_file[0], &st);
- new_size = st.st_size;
}
static std::string old_file;
@@ -105,6 +101,7 @@ class ApplyPatchTest : public ::testing::Test {
static std::string bad_sha1_a;
static std::string bad_sha1_b;
+ static size_t old_size;
static size_t new_size;
};
@@ -184,7 +181,7 @@ std::string ApplyPatchTest::old_sha1;
std::string ApplyPatchTest::new_sha1;
std::string ApplyPatchTest::bad_sha1_a;
std::string ApplyPatchTest::bad_sha1_b;
-
+size_t ApplyPatchTest::old_size;
size_t ApplyPatchTest::new_size;
std::vector<std::unique_ptr<Value>> ApplyPatchFullTest::patches;
@@ -211,6 +208,42 @@ TEST_F(ApplyPatchTest, CheckModeFailure) {
ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
}
+TEST_F(ApplyPatchTest, CheckModeEmmcTarget) {
+ // EMMC:old_file:size:sha1 should pass the check.
+ std::string src_file =
+ "EMMC:" + old_file + ":" + std::to_string(old_size) + ":" + old_sha1;
+ std::vector<std::string> sha1s;
+ ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s));
+
+ // EMMC:old_file:(size-1):sha1:(size+1):sha1 should fail the check.
+ src_file = "EMMC:" + old_file + ":" + std::to_string(old_size - 1) + ":" + old_sha1 + ":" +
+ std::to_string(old_size + 1) + ":" + old_sha1;
+ ASSERT_EQ(1, applypatch_check(src_file.c_str(), sha1s));
+
+ // EMMC:old_file:(size-1):sha1:size:sha1:(size+1):sha1 should pass the check.
+ src_file = "EMMC:" + old_file + ":" +
+ std::to_string(old_size - 1) + ":" + old_sha1 + ":" +
+ std::to_string(old_size) + ":" + old_sha1 + ":" +
+ std::to_string(old_size + 1) + ":" + old_sha1;
+ ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s));
+
+ // EMMC:old_file:(size+1):sha1:(size-1):sha1:size:sha1 should pass the check.
+ src_file = "EMMC:" + old_file + ":" +
+ std::to_string(old_size + 1) + ":" + old_sha1 + ":" +
+ std::to_string(old_size - 1) + ":" + old_sha1 + ":" +
+ std::to_string(old_size) + ":" + old_sha1;
+ ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s));
+
+ // EMMC:new_file:(size+1):old_sha1:(size-1):old_sha1:size:old_sha1:size:new_sha1
+ // should pass the check.
+ src_file = "EMMC:" + new_file + ":" +
+ std::to_string(old_size + 1) + ":" + old_sha1 + ":" +
+ std::to_string(old_size - 1) + ":" + old_sha1 + ":" +
+ std::to_string(old_size) + ":" + old_sha1 + ":" +
+ std::to_string(new_size) + ":" + new_sha1;
+ ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s));
+}
+
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
mangle_file(old_file);
std::vector<std::string> sha1s = { old_sha1 };
@@ -307,7 +340,7 @@ TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
ASSERT_FALSE(file_cmp(output_loc, new_file));
}
-TEST(ApplyPatchModes, InvalidArgs) {
+TEST(ApplyPatchModesTest, InvalidArgs) {
// At least two args (including the filename).
ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" }));
@@ -315,21 +348,22 @@ TEST(ApplyPatchModes, InvalidArgs) {
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" }));
}
-TEST(ApplyPatchModes, PatchMode) {
+TEST(ApplyPatchModesTest, PatchMode) {
std::string boot_img = from_testdata_base("boot.img");
size_t boot_img_size;
std::string boot_img_sha1;
sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
std::string recovery_img = from_testdata_base("recovery.img");
- size_t recovery_img_size;
std::string recovery_img_sha1;
- sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
-
+ size_t size;
+ sha1sum(recovery_img, &recovery_img_sha1, &size);
+ std::string recovery_img_size = std::to_string(size);
std::string bonus_file = from_testdata_base("bonus.file");
// applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
TemporaryFile tmp1;
+ std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p");
std::vector<const char*> args = {
"applypatch",
"-b",
@@ -337,28 +371,32 @@ TEST(ApplyPatchModes, PatchMode) {
boot_img.c_str(),
tmp1.path,
recovery_img_sha1.c_str(),
- std::to_string(recovery_img_size).c_str(),
- (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str()
+ recovery_img_size.c_str(),
+ patch.c_str()
};
ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
// applypatch <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
TemporaryFile tmp2;
+ patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p");
std::vector<const char*> args2 = {
"applypatch",
boot_img.c_str(),
tmp2.path,
recovery_img_sha1.c_str(),
- std::to_string(recovery_img_size).c_str(),
- (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str()
+ recovery_img_size.c_str(),
+ patch.c_str()
};
ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data()));
// applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> \
- // <src-sha1-fake>:<patch1> <src-sha1>:<patch2>
+ // <src-sha1-fake>:<patch1> <src-sha1>:<patch2>
TemporaryFile tmp3;
std::string bad_sha1_a = android::base::StringPrintf("%040x", rand());
std::string bad_sha1_b = android::base::StringPrintf("%040x", rand());
+ std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p");
+ std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p");
+ std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p");
std::vector<const char*> args3 = {
"applypatch",
"-b",
@@ -366,15 +404,85 @@ TEST(ApplyPatchModes, PatchMode) {
boot_img.c_str(),
tmp3.path,
recovery_img_sha1.c_str(),
- std::to_string(recovery_img_size).c_str(),
- (bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
- (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
- (bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
+ recovery_img_size.c_str(),
+ patch1.c_str(),
+ patch2.c_str(),
+ patch3.c_str()
+ };
+ ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data()));
+}
+
+TEST(ApplyPatchModesTest, PatchModeEmmcTarget) {
+ std::string boot_img = from_testdata_base("boot.img");
+ size_t boot_img_size;
+ std::string boot_img_sha1;
+ sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
+
+ std::string recovery_img = from_testdata_base("recovery.img");
+ size_t size;
+ std::string recovery_img_sha1;
+ sha1sum(recovery_img, &recovery_img_sha1, &size);
+ std::string recovery_img_size = std::to_string(size);
+
+ std::string bonus_file = from_testdata_base("bonus.file");
+
+ // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
+ TemporaryFile tmp1;
+ std::string src_file =
+ "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1;
+ std::string tgt_file = "EMMC:" + std::string(tmp1.path);
+ std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p");
+ std::vector<const char*> args = {
+ "applypatch",
+ "-b",
+ bonus_file.c_str(),
+ src_file.c_str(),
+ tgt_file.c_str(),
+ recovery_img_sha1.c_str(),
+ recovery_img_size.c_str(),
+ patch.c_str()
+ };
+ ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
+
+ // applypatch <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
+ TemporaryFile tmp2;
+ patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p");
+ tgt_file = "EMMC:" + std::string(tmp2.path);
+ std::vector<const char*> args2 = {
+ "applypatch",
+ src_file.c_str(),
+ tgt_file.c_str(),
+ recovery_img_sha1.c_str(),
+ recovery_img_size.c_str(),
+ patch.c_str()
+ };
+ ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data()));
+
+ // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> \
+ // <src-sha1-fake>:<patch1> <src-sha1>:<patch2>
+ TemporaryFile tmp3;
+ tgt_file = "EMMC:" + std::string(tmp3.path);
+ std::string bad_sha1_a = android::base::StringPrintf("%040x", rand());
+ std::string bad_sha1_b = android::base::StringPrintf("%040x", rand());
+ std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p");
+ std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p");
+ std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p");
+ std::vector<const char*> args3 = {
+ "applypatch",
+ "-b",
+ bonus_file.c_str(),
+ src_file.c_str(),
+ tgt_file.c_str(),
+ recovery_img_sha1.c_str(),
+ recovery_img_size.c_str(),
+ patch1.c_str(),
+ patch2.c_str(),
+ patch3.c_str()
};
ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data()));
}
-TEST(ApplyPatchModes, PatchModeInvalidArgs) {
+TEST(ApplyPatchModesTest, PatchModeInvalidArgs) {
// Invalid bonus file.
ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" }));
@@ -388,9 +496,10 @@ TEST(ApplyPatchModes, PatchModeInvalidArgs) {
sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
std::string recovery_img = from_testdata_base("recovery.img");
- size_t recovery_img_size;
+ size_t size;
std::string recovery_img_sha1;
- sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
+ sha1sum(recovery_img, &recovery_img_sha1, &size);
+ std::string recovery_img_size = std::to_string(size);
// Bonus file is not supported in flash mode.
// applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size>
@@ -402,40 +511,44 @@ TEST(ApplyPatchModes, PatchModeInvalidArgs) {
boot_img.c_str(),
tmp4.path,
recovery_img_sha1.c_str(),
- std::to_string(recovery_img_size).c_str() };
+ recovery_img_size.c_str()
+ };
ASSERT_NE(0, applypatch_modes(args4.size(), args4.data()));
// Failed to parse patch args.
TemporaryFile tmp5;
+ std::string bad_arg1 =
+ "invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p");
std::vector<const char*> args5 = {
"applypatch",
boot_img.c_str(),
tmp5.path,
recovery_img_sha1.c_str(),
- std::to_string(recovery_img_size).c_str(),
- ("invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str(),
+ recovery_img_size.c_str(),
+ bad_arg1.c_str()
};
ASSERT_NE(0, applypatch_modes(args5.size(), args5.data()));
// Target size cannot be zero.
TemporaryFile tmp6;
+ std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p");
std::vector<const char*> args6 = {
"applypatch",
boot_img.c_str(),
tmp6.path,
recovery_img_sha1.c_str(),
"0", // target size
- (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str()
+ patch.c_str()
};
ASSERT_NE(0, applypatch_modes(args6.size(), args6.data()));
}
-TEST(ApplyPatchModes, CheckModeInvalidArgs) {
+TEST(ApplyPatchModesTest, CheckModeInvalidArgs) {
// Insufficient args.
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" }));
}
-TEST(ApplyPatchModes, SpaceModeInvalidArgs) {
+TEST(ApplyPatchModesTest, SpaceModeInvalidArgs) {
// Insufficient args.
ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-s" }));
@@ -449,6 +562,6 @@ TEST(ApplyPatchModes, SpaceModeInvalidArgs) {
ASSERT_EQ(0, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0x10" }));
}
-TEST(ApplyPatchModes, ShowLicenses) {
+TEST(ApplyPatchModesTest, ShowLicenses) {
ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" }));
}
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 973c19de3..f31f1f82a 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -23,36 +23,42 @@
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/test_utils.h>
+#include <bootloader_message/bootloader_message.h>
#include <gtest/gtest.h>
+#include <ziparchive/zip_archive.h>
+#include "common/test_constants.h"
#include "edify/expr.h"
#include "error_code.h"
#include "updater/install.h"
+#include "updater/updater.h"
struct selabel_handle *sehandle = nullptr;
-static void expect(const char* expected, const char* expr_str, CauseCode cause_code) {
- Expr* e;
- int error_count;
- EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0);
+static void expect(const char* expected, const char* expr_str, CauseCode cause_code,
+ UpdaterInfo* info = nullptr) {
+ Expr* e;
+ int error_count = 0;
+ ASSERT_EQ(0, parse_string(expr_str, &e, &error_count));
+ ASSERT_EQ(0, error_count);
- State state(expr_str, nullptr);
+ State state(expr_str, info);
- std::string result;
- bool status = Evaluate(&state, e, &result);
+ std::string result;
+ bool status = Evaluate(&state, e, &result);
- if (expected == nullptr) {
- EXPECT_FALSE(status);
- } else {
- EXPECT_STREQ(expected, result.c_str());
- }
-
- // Error code is set in updater/updater.cpp only, by parsing State.errmsg.
- EXPECT_EQ(kNoError, state.error_code);
+ if (expected == nullptr) {
+ ASSERT_FALSE(status);
+ } else {
+ ASSERT_TRUE(status);
+ ASSERT_STREQ(expected, result.c_str());
+ }
- // Cause code should always be available.
- EXPECT_EQ(cause_code, state.cause_code);
+ // Error code is set in updater/updater.cpp only, by parsing State.errmsg.
+ ASSERT_EQ(kNoError, state.error_code);
+ // Cause code should always be available.
+ ASSERT_EQ(cause_code, state.cause_code);
}
class UpdaterTest : public ::testing::Test {
@@ -264,3 +270,243 @@ TEST_F(UpdaterTest, symlink) {
ASSERT_EQ(0, unlink(src1.c_str()));
ASSERT_EQ(0, unlink(src2.c_str()));
}
+
+TEST_F(UpdaterTest, package_extract_dir) {
+ // package_extract_dir expects 2 arguments.
+ expect(nullptr, "package_extract_dir()", kArgsParsingFailure);
+ expect(nullptr, "package_extract_dir(\"arg1\")", kArgsParsingFailure);
+ expect(nullptr, "package_extract_dir(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
+
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Need to set up the ziphandle.
+ UpdaterInfo updater_info;
+ updater_info.package_zip = handle;
+
+ // Extract "b/c.txt" and "b/d.txt" with package_extract_dir("b", "<dir>").
+ TemporaryDir td;
+ std::string temp_dir(td.path);
+ std::string script("package_extract_dir(\"b\", \"" + temp_dir + "\")");
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ // Verify.
+ std::string data;
+ std::string file_c = temp_dir + "/c.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+
+ std::string file_d = temp_dir + "/d.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ // Modify the contents in order to retry. It's expected to be overwritten.
+ ASSERT_TRUE(android::base::WriteStringToFile("random", file_c));
+ ASSERT_TRUE(android::base::WriteStringToFile("random", file_d));
+
+ // Extract again and verify.
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+ ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ // Clean up the temp files under td.
+ ASSERT_EQ(0, unlink(file_c.c_str()));
+ ASSERT_EQ(0, unlink(file_d.c_str()));
+
+ // Extracting "b/" (with slash) should give the same result.
+ script = "package_extract_dir(\"b/\", \"" + temp_dir + "\")";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+ ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ ASSERT_EQ(0, unlink(file_c.c_str()));
+ ASSERT_EQ(0, unlink(file_d.c_str()));
+
+ // Extracting "" is allowed. The entries will carry the path name.
+ script = "package_extract_dir(\"\", \"" + temp_dir + "\")";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ std::string file_a = temp_dir + "/a.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_a, &data));
+ ASSERT_EQ(kATxtContents, data);
+ std::string file_b = temp_dir + "/b.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_b, &data));
+ ASSERT_EQ(kBTxtContents, data);
+ std::string file_b_c = temp_dir + "/b/c.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_b_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+ std::string file_b_d = temp_dir + "/b/d.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_b_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ ASSERT_EQ(0, unlink(file_a.c_str()));
+ ASSERT_EQ(0, unlink(file_b.c_str()));
+ ASSERT_EQ(0, unlink(file_b_c.c_str()));
+ ASSERT_EQ(0, unlink(file_b_d.c_str()));
+ ASSERT_EQ(0, rmdir((temp_dir + "/b").c_str()));
+
+ // Extracting non-existent entry should still give "t".
+ script = "package_extract_dir(\"doesntexist\", \"" + temp_dir + "\")";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ // Only relative zip_path is allowed.
+ script = "package_extract_dir(\"/b\", \"" + temp_dir + "\")";
+ expect("", script.c_str(), kNoCause, &updater_info);
+
+ // Only absolute dest_path is allowed.
+ script = "package_extract_dir(\"b\", \"path\")";
+ expect("", script.c_str(), kNoCause, &updater_info);
+
+ CloseArchive(handle);
+}
+
+// TODO: Test extracting to block device.
+TEST_F(UpdaterTest, package_extract_file) {
+ // package_extract_file expects 1 or 2 arguments.
+ expect(nullptr, "package_extract_file()", kArgsParsingFailure);
+ expect(nullptr, "package_extract_file(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
+
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Need to set up the ziphandle.
+ UpdaterInfo updater_info;
+ updater_info.package_zip = handle;
+
+ // Two-argument version.
+ TemporaryFile temp_file1;
+ std::string script("package_extract_file(\"a.txt\", \"" + std::string(temp_file1.path) + "\")");
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ // Verify the extracted entry.
+ std::string data;
+ ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data));
+ ASSERT_EQ(kATxtContents, data);
+
+ // Now extract another entry to the same location, which should overwrite.
+ script = "package_extract_file(\"b.txt\", \"" + std::string(temp_file1.path) + "\")";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ ASSERT_TRUE(android::base::ReadFileToString(temp_file1.path, &data));
+ ASSERT_EQ(kBTxtContents, data);
+
+ // Missing zip entry. The two-argument version doesn't abort.
+ script = "package_extract_file(\"doesntexist\", \"" + std::string(temp_file1.path) + "\")";
+ expect("", script.c_str(), kNoCause, &updater_info);
+
+ // Extract to /dev/full should fail.
+ script = "package_extract_file(\"a.txt\", \"/dev/full\")";
+ expect("", script.c_str(), kNoCause, &updater_info);
+
+ // One-argument version.
+ script = "sha1_check(package_extract_file(\"a.txt\"))";
+ expect(kATxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info);
+
+ script = "sha1_check(package_extract_file(\"b.txt\"))";
+ expect(kBTxtSha1Sum.c_str(), script.c_str(), kNoCause, &updater_info);
+
+ // Missing entry. The one-argument version aborts the evaluation.
+ script = "package_extract_file(\"doesntexist\")";
+ expect(nullptr, script.c_str(), kPackageExtractFileFailure, &updater_info);
+
+ CloseArchive(handle);
+}
+
+TEST_F(UpdaterTest, write_value) {
+ // write_value() expects two arguments.
+ expect(nullptr, "write_value()", kArgsParsingFailure);
+ expect(nullptr, "write_value(\"arg1\")", kArgsParsingFailure);
+ expect(nullptr, "write_value(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
+
+ // filename cannot be empty.
+ expect(nullptr, "write_value(\"value\", \"\")", kArgsParsingFailure);
+
+ // Write some value to file.
+ TemporaryFile temp_file;
+ std::string value = "magicvalue";
+ std::string script("write_value(\"" + value + "\", \"" + std::string(temp_file.path) + "\")");
+ expect("t", script.c_str(), kNoCause);
+
+ // Verify the content.
+ std::string content;
+ ASSERT_TRUE(android::base::ReadFileToString(temp_file.path, &content));
+ ASSERT_EQ(value, content);
+
+ // Allow writing empty string.
+ script = "write_value(\"\", \"" + std::string(temp_file.path) + "\")";
+ expect("t", script.c_str(), kNoCause);
+
+ // Verify the content.
+ ASSERT_TRUE(android::base::ReadFileToString(temp_file.path, &content));
+ ASSERT_EQ("", content);
+
+ // It should fail gracefully when write fails.
+ script = "write_value(\"value\", \"/proc/0/file1\")";
+ expect("", script.c_str(), kNoCause);
+}
+
+TEST_F(UpdaterTest, get_stage) {
+ // get_stage() expects one argument.
+ expect(nullptr, "get_stage()", kArgsParsingFailure);
+ expect(nullptr, "get_stage(\"arg1\", \"arg2\")", kArgsParsingFailure);
+ expect(nullptr, "get_stage(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
+
+ // Set up a local file as BCB.
+ TemporaryFile tf;
+ std::string temp_file(tf.path);
+ bootloader_message boot;
+ strlcpy(boot.stage, "2/3", sizeof(boot.stage));
+ std::string err;
+ ASSERT_TRUE(write_bootloader_message_to(boot, temp_file, &err));
+
+ // Can read the stage value.
+ std::string script("get_stage(\"" + temp_file + "\")");
+ expect("2/3", script.c_str(), kNoCause);
+
+ // Bad BCB path.
+ script = "get_stage(\"doesntexist\")";
+ expect("", script.c_str(), kNoCause);
+}
+
+TEST_F(UpdaterTest, set_stage) {
+ // set_stage() expects two arguments.
+ expect(nullptr, "set_stage()", kArgsParsingFailure);
+ expect(nullptr, "set_stage(\"arg1\")", kArgsParsingFailure);
+ expect(nullptr, "set_stage(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
+
+ // Set up a local file as BCB.
+ TemporaryFile tf;
+ std::string temp_file(tf.path);
+ bootloader_message boot;
+ strlcpy(boot.command, "command", sizeof(boot.command));
+ strlcpy(boot.stage, "2/3", sizeof(boot.stage));
+ std::string err;
+ ASSERT_TRUE(write_bootloader_message_to(boot, temp_file, &err));
+
+ // Write with set_stage().
+ std::string script("set_stage(\"" + temp_file + "\", \"1/3\")");
+ expect(tf.path, script.c_str(), kNoCause);
+
+ // Verify.
+ bootloader_message boot_verify;
+ ASSERT_TRUE(read_bootloader_message_from(&boot_verify, temp_file, &err));
+
+ // Stage should be updated, with command part untouched.
+ ASSERT_STREQ("1/3", boot_verify.stage);
+ ASSERT_STREQ(boot.command, boot_verify.command);
+
+ // Bad BCB path.
+ script = "set_stage(\"doesntexist\", \"1/3\")";
+ expect("", script.c_str(), kNoCause);
+
+ script = "set_stage(\"/dev/full\", \"1/3\")";
+ expect("", script.c_str(), kNoCause);
+}
diff --git a/tests/unit/zip_test.cpp b/tests/unit/zip_test.cpp
index 49729467d..ef0ee4c1d 100644
--- a/tests/unit/zip_test.cpp
+++ b/tests/unit/zip_test.cpp
@@ -30,9 +30,6 @@
#include "common/test_constants.h"
-static const std::string kATxtContents("abcdefghabcdefgh\n");
-static const std::string kBTxtContents("abcdefgh\n");
-
TEST(ZipTest, ExtractPackageRecursive) {
std::string zip_path = from_testdata_base("ziptest_valid.zip");
ZipArchiveHandle handle;
diff --git a/update_verifier/Android.mk b/update_verifier/Android.mk
index 8449c758d..49d19b0e1 100644
--- a/update_verifier/Android.mk
+++ b/update_verifier/Android.mk
@@ -24,7 +24,10 @@ LOCAL_SHARED_LIBRARIES := \
libbase \
libcutils \
libhardware \
- liblog
+ liblog \
+ libutils \
+ libhidlbase \
+ android.hardware.boot@1.0
LOCAL_CFLAGS := -Werror
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp
index 93ac605b1..e97a3adba 100644
--- a/update_verifier/update_verifier.cpp
+++ b/update_verifier/update_verifier.cpp
@@ -45,7 +45,12 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
-#include <hardware/boot_control.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+using android::sp;
+using android::hardware::boot::V1_0::IBootControl;
+using android::hardware::boot::V1_0::BoolResult;
+using android::hardware::boot::V1_0::CommandResult;
constexpr auto CARE_MAP_FILE = "/data/ota_package/care_map.txt";
constexpr int BLOCKSIZE = 4096;
@@ -142,21 +147,18 @@ int main(int argc, char** argv) {
LOG(INFO) << "Started with arg " << i << ": " << argv[i];
}
- const hw_module_t* hw_module;
- if (hw_get_module("bootctrl", &hw_module) != 0) {
+ sp<IBootControl> module = IBootControl::getService("bootctrl");
+ if (module == nullptr) {
LOG(ERROR) << "Error getting bootctrl module.";
return -1;
}
- boot_control_module_t* module = reinterpret_cast<boot_control_module_t*>(
- const_cast<hw_module_t*>(hw_module));
- module->init(module);
-
- unsigned current_slot = module->getCurrentSlot(module);
- int is_successful= module->isSlotMarkedSuccessful(module, current_slot);
- LOG(INFO) << "Booting slot " << current_slot << ": isSlotMarkedSuccessful=" << is_successful;
+ uint32_t current_slot = module->getCurrentSlot();
+ BoolResult is_successful = module->isSlotMarkedSuccessful(current_slot);
+ LOG(INFO) << "Booting slot " << current_slot << ": isSlotMarkedSuccessful="
+ << static_cast<int32_t>(is_successful);
- if (is_successful == 0) {
+ if (is_successful == BoolResult::FALSE) {
// The current slot has not booted successfully.
char verity_mode[PROPERTY_VALUE_MAX];
if (property_get("ro.boot.veritymode", verity_mode, "") == -1) {
@@ -175,9 +177,10 @@ int main(int argc, char** argv) {
return -1;
}
- int ret = module->markBootSuccessful(module);
- if (ret != 0) {
- LOG(ERROR) << "Error marking booted successfully: " << strerror(-ret);
+ CommandResult cr;
+ module->markBootSuccessful([&cr](CommandResult result) { cr = result; });
+ if (!cr.success) {
+ LOG(ERROR) << "Error marking booted successfully: " << cr.errMsg;
return -1;
}
LOG(INFO) << "Marked slot " << current_slot << " as booted successfully.";
diff --git a/updater/Android.mk b/updater/Android.mk
index 3c1d0d41f..5d328a3fa 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -27,12 +27,14 @@ updater_common_static_libraries := \
libedify \
libziparchive \
libotautil \
+ libbootloader_message \
libutils \
libmounts \
libotafault \
libext4_utils_static \
libfec \
libfec_rs \
+ libfs_mgr \
liblog \
libselinux \
libsparse_static \
diff --git a/updater/install.cpp b/updater/install.cpp
index 59c54dd4c..8db5c1fe0 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -39,11 +39,12 @@
#include <string>
#include <vector>
-#include <android-base/parseint.h>
+#include <android-base/file.h>
#include <android-base/parsedouble.h>
+#include <android-base/parseint.h>
#include <android-base/properties.h>
-#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/make_ext4fs.h>
#include <ext4_utils/wipe.h>
@@ -453,117 +454,114 @@ Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(frac_str);
}
-// package_extract_dir(package_path, destination_path)
-Value* PackageExtractDirFn(const char* name, State* state,
- int argc, Expr* argv[]) {
- if (argc != 2) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
- }
+// package_extract_dir(package_dir, dest_dir)
+// Extracts all files from the package underneath package_dir and writes them to the
+// corresponding tree beneath dest_dir. Any existing files are overwritten.
+// Example: package_extract_dir("system", "/system")
+//
+// Note: package_dir needs to be a relative path; dest_dir needs to be an absolute path.
+Value* PackageExtractDirFn(const char* name, State* state, int argc, Expr* argv[]) {
+ if (argc != 2) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
+ }
- std::vector<std::string> args;
- if (!ReadArgs(state, 2, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
- }
- const std::string& zip_path = args[0];
- const std::string& dest_path = args[1];
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 2, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
+ }
+ const std::string& zip_path = args[0];
+ const std::string& dest_path = args[1];
- ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
+ ZipArchiveHandle za = static_cast<UpdaterInfo*>(state->cookie)->package_zip;
- // To create a consistent system image, never use the clock for timestamps.
- struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
+ // To create a consistent system image, never use the clock for timestamps.
+ constexpr struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
- bool success = ExtractPackageRecursive(za, zip_path, dest_path, &timestamp, sehandle);
+ bool success = ExtractPackageRecursive(za, zip_path, dest_path, &timestamp, sehandle);
- return StringValue(success ? "t" : "");
+ return StringValue(success ? "t" : "");
}
+// package_extract_file(package_file[, dest_file])
+// Extracts a single package_file from the update package and writes it to dest_file,
+// overwriting existing files if necessary. Without the dest_file argument, returns the
+// contents of the package file as a binary blob.
+Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv[]) {
+ if (argc < 1 || argc > 2) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d", name, argc);
+ }
-// package_extract_file(package_path, destination_path)
-// or
-// package_extract_file(package_path)
-// to return the entire contents of the file as the result of this
-// function (the char* returned is actually a FileContents*).
-Value* PackageExtractFileFn(const char* name, State* state,
- int argc, Expr* argv[]) {
- if (argc < 1 || argc > 2) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d",
- name, argc);
- }
- bool success = false;
+ if (argc == 2) {
+ // The two-argument version extracts to a file.
- if (argc == 2) {
- // The two-argument version extracts to a file.
-
- ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
-
- std::vector<std::string> args;
- if (!ReadArgs(state, 2, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name,
- argc);
- }
- const std::string& zip_path = args[0];
- const std::string& dest_path = args[1];
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 2, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc);
+ }
+ const std::string& zip_path = args[0];
+ const std::string& dest_path = args[1];
- ZipString zip_string_path(zip_path.c_str());
- ZipEntry entry;
- if (FindEntry(za, zip_string_path, &entry) != 0) {
- printf("%s: no %s in package\n", name, zip_path.c_str());
- return StringValue("");
- }
+ ZipArchiveHandle za = static_cast<UpdaterInfo*>(state->cookie)->package_zip;
+ ZipString zip_string_path(zip_path.c_str());
+ ZipEntry entry;
+ if (FindEntry(za, zip_string_path, &entry) != 0) {
+ printf("%s: no %s in package\n", name, zip_path.c_str());
+ return StringValue("");
+ }
- int fd = TEMP_FAILURE_RETRY(ota_open(dest_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR));
- if (fd == -1) {
- printf("%s: can't open %s for write: %s\n", name, dest_path.c_str(), strerror(errno));
- return StringValue("");
- }
- success = ExtractEntryToFile(za, &entry, fd);
- if (ota_fsync(fd) == -1) {
- printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
- success = false;
- }
- if (ota_close(fd) == -1) {
- printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
- success = false;
- }
+ unique_fd fd(TEMP_FAILURE_RETRY(
+ ota_open(dest_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)));
+ if (fd == -1) {
+ printf("%s: can't open %s for write: %s\n", name, dest_path.c_str(), strerror(errno));
+ return StringValue("");
+ }
- return StringValue(success ? "t" : "");
- } else {
- // The one-argument version returns the contents of the file
- // as the result.
+ bool success = true;
+ int32_t ret = ExtractEntryToFile(za, &entry, fd);
+ if (ret != 0) {
+ printf("%s: Failed to extract entry \"%s\" (%u bytes) to \"%s\": %s\n", name,
+ zip_path.c_str(), entry.uncompressed_length, dest_path.c_str(), ErrorCodeString(ret));
+ success = false;
+ }
+ if (ota_fsync(fd) == -1) {
+ printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
+ success = false;
+ }
+ if (ota_close(fd) == -1) {
+ printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno));
+ success = false;
+ }
- std::vector<std::string> args;
- if (!ReadArgs(state, 1, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name,
- argc);
- }
- const std::string& zip_path = args[0];
+ return StringValue(success ? "t" : "");
+ } else {
+ // The one-argument version returns the contents of the file as the result.
- Value* v = new Value(VAL_INVALID, "");
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 1, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc);
+ }
+ const std::string& zip_path = args[0];
- ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip;
- ZipString zip_string_path(zip_path.c_str());
- ZipEntry entry;
- if (FindEntry(za, zip_string_path, &entry) != 0) {
- printf("%s: no %s in package\n", name, zip_path.c_str());
- return v;
- }
+ ZipArchiveHandle za = static_cast<UpdaterInfo*>(state->cookie)->package_zip;
+ ZipString zip_string_path(zip_path.c_str());
+ ZipEntry entry;
+ if (FindEntry(za, zip_string_path, &entry) != 0) {
+ return ErrorAbort(state, kPackageExtractFileFailure, "%s(): no %s in package", name,
+ zip_path.c_str());
+ }
- v->data.resize(entry.uncompressed_length);
- if (ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&v->data[0]),
- v->data.size()) != 0) {
- printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size());
- } else {
- success = true;
- }
+ std::string buffer;
+ buffer.resize(entry.uncompressed_length);
- if (!success) {
- v->data.clear();
- } else {
- v->type = VAL_BLOB;
- }
- return v;
+ int32_t ret = ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&buffer[0]), buffer.size());
+ if (ret != 0) {
+ return ErrorAbort(state, kPackageExtractFileFailure,
+ "%s: Failed to extract entry \"%s\" (%zu bytes) to memory: %s", name,
+ zip_path.c_str(), buffer.size(), ErrorCodeString(ret));
}
+
+ return new Value(VAL_BLOB, buffer);
+ }
}
// symlink(target, [src1, src2, ...])
@@ -868,75 +866,73 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(value);
}
-
// file_getprop(file, key)
//
// interprets 'file' as a getprop-style file (key=value pairs, one
// per line. # comment lines, blank lines, lines without '=' ignored),
// and returns the value for 'key' (or "" if it isn't defined).
Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
- if (argc != 2) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
- }
+ if (argc != 2) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
+ }
- std::vector<std::string> args;
- if (!ReadArgs(state, 2, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
- }
- const std::string& filename = args[0];
- const std::string& key = args[1];
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 2, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
+ }
+ const std::string& filename = args[0];
+ const std::string& key = args[1];
- struct stat st;
- if (stat(filename.c_str(), &st) < 0) {
- return ErrorAbort(state, kFileGetPropFailure, "%s: failed to stat \"%s\": %s", name,
- filename.c_str(), strerror(errno));
- }
+ struct stat st;
+ if (stat(filename.c_str(), &st) < 0) {
+ return ErrorAbort(state, kFileGetPropFailure, "%s: failed to stat \"%s\": %s", name,
+ filename.c_str(), strerror(errno));
+ }
+
+ constexpr off_t MAX_FILE_GETPROP_SIZE = 65536;
+ if (st.st_size > MAX_FILE_GETPROP_SIZE) {
+ return ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %lld)",
+ filename.c_str(), name, static_cast<long long>(MAX_FILE_GETPROP_SIZE));
+ }
+
+ std::string buffer(st.st_size, '\0');
+ unique_file f(ota_fopen(filename.c_str(), "rb"));
+ if (f == nullptr) {
+ return ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, filename.c_str(),
+ strerror(errno));
+ }
+
+ if (ota_fread(&buffer[0], 1, st.st_size, f.get()) != static_cast<size_t>(st.st_size)) {
+ ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s", name,
+ static_cast<size_t>(st.st_size), filename.c_str());
+ return nullptr;
+ }
- constexpr off_t MAX_FILE_GETPROP_SIZE = 65536;
- if (st.st_size > MAX_FILE_GETPROP_SIZE) {
- return ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %lld)",
- filename.c_str(), name, static_cast<long long>(MAX_FILE_GETPROP_SIZE));
- }
+ ota_fclose(f);
- std::string buffer(st.st_size, '\0');
- FILE* f = ota_fopen(filename.c_str(), "rb");
- if (f == nullptr) {
- return ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name,
- filename.c_str(), strerror(errno));
- }
+ std::vector<std::string> lines = android::base::Split(buffer, "\n");
+ for (size_t i = 0; i < lines.size(); i++) {
+ std::string line = android::base::Trim(lines[i]);
- if (ota_fread(&buffer[0], 1, st.st_size, f) != static_cast<size_t>(st.st_size)) {
- ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s",
- name, static_cast<size_t>(st.st_size), filename.c_str());
- ota_fclose(f);
- return nullptr;
+ // comment or blank line: skip to next line
+ if (line.empty() || line[0] == '#') {
+ continue;
+ }
+ size_t equal_pos = line.find('=');
+ if (equal_pos == std::string::npos) {
+ continue;
}
- ota_fclose(f);
-
- std::vector<std::string> lines = android::base::Split(buffer, "\n");
- for (size_t i = 0; i < lines.size(); i++) {
- std::string line = android::base::Trim(lines[i]);
-
- // comment or blank line: skip to next line
- if (line.empty() || line[0] == '#') {
- continue;
- }
- size_t equal_pos = line.find('=');
- if (equal_pos == std::string::npos) {
- continue;
- }
-
- // trim whitespace between key and '='
- std::string str = android::base::Trim(line.substr(0, equal_pos));
+ // trim whitespace between key and '='
+ std::string str = android::base::Trim(line.substr(0, equal_pos));
- // not the key we're looking for
- if (key != str) continue;
+ // not the key we're looking for
+ if (key != str) continue;
- return StringValue(android::base::Trim(line.substr(equal_pos + 1)));
- }
+ return StringValue(android::base::Trim(line.substr(equal_pos + 1)));
+ }
- return StringValue("");
+ return StringValue("");
}
// apply_patch_space(bytes)
@@ -1162,6 +1158,33 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
return v;
}
+// write_value(value, filename)
+// Writes 'value' to 'filename'.
+// Example: write_value("960000", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq")
+Value* WriteValueFn(const char* name, State* state, int argc, Expr* argv[]) {
+ if (argc != 2) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
+ }
+
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 2, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name);
+ }
+
+ const std::string& filename = args[1];
+ if (filename.empty()) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s(): Filename cannot be empty", name);
+ }
+
+ const std::string& value = args[0];
+ if (!android::base::WriteStringToFile(value, filename)) {
+ printf("%s: Failed to write to \"%s\": %s\n", name, filename.c_str(), strerror(errno));
+ return StringValue("");
+ } else {
+ return StringValue("t");
+ }
+}
+
// Immediately reboot the device. Recovery is not finished normally,
// so if you reboot into recovery it will re-start applying the
// current package (because nothing has cleared the copy of the
@@ -1172,31 +1195,35 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
// partition, or "" (empty string) to boot from the regular boot
// partition.
Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
- if (argc != 2) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
- }
+ if (argc != 2) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
+ }
+
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 2, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name);
+ }
+ const std::string& filename = args[0];
+ const std::string& property = args[1];
+
+ // Zero out the 'command' field of the bootloader message. Leave the rest intact.
+ bootloader_message boot;
+ std::string err;
+ if (!read_bootloader_message_from(&boot, filename, &err)) {
+ printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str());
+ return StringValue("");
+ }
+ memset(boot.command, 0, sizeof(boot.command));
+ if (!write_bootloader_message_to(boot, filename, &err)) {
+ printf("%s(): Failed to write to \"%s\": %s", name, filename.c_str(), err.c_str());
+ return StringValue("");
+ }
- std::vector<std::string> args;
- if (!ReadArgs(state, 2, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
- }
- const std::string& filename = args[0];
- const std::string& property = args[1];
-
- // zero out the 'command' field of the bootloader message.
- char buffer[80];
- memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command));
- FILE* f = ota_fopen(filename.c_str(), "r+b");
- fseek(f, offsetof(struct bootloader_message, command), SEEK_SET);
- ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f);
- ota_fclose(f);
-
- std::string reboot_cmd = "reboot,";
- reboot_cmd += property;
- android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd);
-
- sleep(5);
- return ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name);
+ const std::string reboot_cmd = "reboot," + property;
+ android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd);
+
+ sleep(5);
+ return ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name);
}
// Store a string value somewhere that future invocations of recovery
@@ -1210,88 +1237,80 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
// second argument is the string to store; it should not exceed 31
// bytes.
Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
- if (argc != 2) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
- }
+ if (argc != 2) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
+ }
+
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 2, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
+ }
+ const std::string& filename = args[0];
+ const std::string& stagestr = args[1];
+
+ // Store this value in the misc partition, immediately after the
+ // bootloader message that the main recovery uses to save its
+ // arguments in case of the device restarting midway through
+ // package installation.
+ bootloader_message boot;
+ std::string err;
+ if (!read_bootloader_message_from(&boot, filename, &err)) {
+ printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str());
+ return StringValue("");
+ }
+ strlcpy(boot.stage, stagestr.c_str(), sizeof(boot.stage));
+ if (!write_bootloader_message_to(boot, filename, &err)) {
+ printf("%s(): Failed to write to \"%s\": %s", name, filename.c_str(), err.c_str());
+ return StringValue("");
+ }
- std::vector<std::string> args;
- if (!ReadArgs(state, 2, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
- }
- const std::string& filename = args[0];
- std::string& stagestr = args[1];
-
- // Store this value in the misc partition, immediately after the
- // bootloader message that the main recovery uses to save its
- // arguments in case of the device restarting midway through
- // package installation.
- FILE* f = ota_fopen(filename.c_str(), "r+b");
- fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
- size_t to_write = stagestr.size();
- size_t max_size = sizeof(((struct bootloader_message*)0)->stage);
- if (to_write > max_size) {
- to_write = max_size;
- stagestr = stagestr.substr(0, max_size-1);
- }
- size_t status = ota_fwrite(stagestr.c_str(), to_write, 1, f);
- ota_fclose(f);
-
- if (status != to_write) {
- return StringValue("");
- }
- return StringValue(filename);
+ return StringValue(filename);
}
// Return the value most recently saved with SetStageFn. The argument
// is the block device for the misc partition.
Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
- if (argc != 1) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
- }
-
- std::vector<std::string> args;
- if (!ReadArgs(state, 1, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
- }
- const std::string& filename = args[0];
-
- char buffer[sizeof(((struct bootloader_message*)0)->stage)];
- FILE* f = ota_fopen(filename.c_str(), "rb");
- fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET);
- size_t status = ota_fread(buffer, sizeof(buffer), 1, f);
- ota_fclose(f);
- if (status != sizeof(buffer)) {
- return StringValue("");
- }
+ if (argc != 1) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
+ }
+
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 1, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
+ }
+ const std::string& filename = args[0];
+
+ bootloader_message boot;
+ std::string err;
+ if (!read_bootloader_message_from(&boot, filename, &err)) {
+ printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str());
+ return StringValue("");
+ }
- buffer[sizeof(buffer)-1] = '\0';
- return StringValue(buffer);
+ return StringValue(boot.stage);
}
Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) {
- if (argc != 2) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
- }
-
- std::vector<std::string> args;
- if (!ReadArgs(state, 2, argv, &args)) {
- return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
- }
- const std::string& filename = args[0];
- const std::string& len_str = args[1];
-
- size_t len;
- if (!android::base::ParseUint(len_str.c_str(), &len)) {
- return nullptr;
- }
- int fd = ota_open(filename.c_str(), O_WRONLY, 0644);
- // The wipe_block_device function in ext4_utils returns 0 on success and 1
- // for failure.
- int status = wipe_block_device(fd, len);
-
- ota_close(fd);
-
- return StringValue((status == 0) ? "t" : "");
+ if (argc != 2) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
+ }
+
+ std::vector<std::string> args;
+ if (!ReadArgs(state, 2, argv, &args)) {
+ return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name);
+ }
+ const std::string& filename = args[0];
+ const std::string& len_str = args[1];
+
+ size_t len;
+ if (!android::base::ParseUint(len_str.c_str(), &len)) {
+ return nullptr;
+ }
+ unique_fd fd(ota_open(filename.c_str(), O_WRONLY, 0644));
+ // The wipe_block_device function in ext4_utils returns 0 on success and 1
+ // for failure.
+ int status = wipe_block_device(fd, len);
+ return StringValue((status == 0) ? "t" : "");
}
Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) {
@@ -1370,6 +1389,7 @@ void RegisterInstallFunctions() {
RegisterFunction("read_file", ReadFileFn);
RegisterFunction("sha1_check", Sha1CheckFn);
RegisterFunction("rename", RenameFn);
+ RegisterFunction("write_value", WriteValueFn);
RegisterFunction("wipe_cache", WipeCacheFn);
diff --git a/wear_ui.cpp b/wear_ui.cpp
index 17889076a..5433d110b 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -177,7 +177,7 @@ void WearRecoveryUI::draw_screen_locked()
// items don't fit on the screen.
if (menu_items > menu_end - menu_start) {
sprintf(cur_selection_str, "Current item: %d/%d", menu_sel + 1, menu_items);
- gr_text(x+4, y, cur_selection_str, 1);
+ gr_text(gr_sys_font(), x+4, y, cur_selection_str, 1);
y += char_height_+4;
}
@@ -192,10 +192,10 @@ void WearRecoveryUI::draw_screen_locked()
gr_fill(x, y-2, gr_fb_width()-x, y+char_height_+2);
// white text of selected item
SetColor(MENU_SEL_FG);
- if (menu[i][0]) gr_text(x+4, y, menu[i], 1);
+ if (menu[i][0]) gr_text(gr_sys_font(), x+4, y, menu[i], 1);
SetColor(MENU);
- } else {
- if (menu[i][0]) gr_text(x+4, y, menu[i], 0);
+ } else if (menu[i][0]) {
+ gr_text(gr_sys_font(), x+4, y, menu[i], 0);
}
y += char_height_+4;
}
@@ -216,7 +216,7 @@ void WearRecoveryUI::draw_screen_locked()
for (int ty = gr_fb_height() - char_height_ - outer_height;
ty > y+2 && count < text_rows;
ty -= char_height_, ++count) {
- gr_text(x+4, ty, text[row], 0);
+ gr_text(gr_sys_font(), x+4, ty, text[row], 0);
--row;
if (row < 0) row = text_rows-1;
}
@@ -285,7 +285,7 @@ void WearRecoveryUI::Init()
{
gr_init();
- gr_font_size(&char_width_, &char_height_);
+ gr_font_size(gr_sys_font(), &char_width_, &char_height_);
text_col = text_row = 0;
text_rows = (gr_fb_height()) / char_height_;