Merge changes Ie68aed2f,Ic40696b3
* changes: fastboot: Handle libsparse failures better. libsparse: Fix allocation failures on 32-bit systems.
This commit is contained in:
commit
ecdbbbda82
6 changed files with 140 additions and 20 deletions
|
@ -988,7 +988,7 @@ std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size) {
|
|||
}
|
||||
|
||||
const int files = sparse_file_resparse(s, max_size, nullptr, 0);
|
||||
if (files < 0) die("Failed to resparse");
|
||||
if (files < 0) die("Failed to compute resparse boundaries");
|
||||
|
||||
auto temp = std::make_unique<sparse_file*[]>(files);
|
||||
const int rv = sparse_file_resparse(s, max_size, temp.get(), files);
|
||||
|
@ -1057,6 +1057,10 @@ static bool load_buf_fd(unique_fd fd, struct fastboot_buffer* buf) {
|
|||
|
||||
if (sparse_file* s = sparse_file_import(fd.get(), false, false)) {
|
||||
buf->image_size = sparse_file_len(s, false, false);
|
||||
if (buf->image_size < 0) {
|
||||
LOG(ERROR) << "Could not compute length of sparse file";
|
||||
return false;
|
||||
}
|
||||
sparse_file_destroy(s);
|
||||
} else {
|
||||
buf->image_size = sz;
|
||||
|
@ -1172,15 +1176,6 @@ bool is_logical(const std::string& partition) {
|
|||
return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
|
||||
}
|
||||
|
||||
static std::string fb_fix_numeric_var(std::string var) {
|
||||
// Some bootloaders (angler, for example), send spurious leading whitespace.
|
||||
var = android::base::Trim(var);
|
||||
// Some bootloaders (hammerhead, for example) use implicit hex.
|
||||
// This code used to use strtol with base 16.
|
||||
if (!android::base::StartsWith(var, "0x")) var = "0x" + var;
|
||||
return var;
|
||||
}
|
||||
|
||||
static uint64_t get_partition_size(const std::string& partition) {
|
||||
std::string partition_size_str;
|
||||
if (fb->GetVar("partition-size:" + partition, &partition_size_str) != fastboot::SUCCESS) {
|
||||
|
@ -1252,6 +1247,9 @@ void flash_partition_files(const std::string& partition, const std::vector<Spars
|
|||
for (size_t i = 0; i < files.size(); i++) {
|
||||
sparse_file* s = files[i].get();
|
||||
int64_t sz = sparse_file_len(s, true, false);
|
||||
if (sz < 0) {
|
||||
LOG(FATAL) << "Could not compute length of sparse image for " << partition;
|
||||
}
|
||||
fb->FlashPartition(partition, s, sz, i + 1, files.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "filesystem.h"
|
||||
#include "super_flash_helper.h"
|
||||
|
||||
#include <android-base/parseint.h>
|
||||
|
||||
using namespace std::string_literals;
|
||||
FlashTask::FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname,
|
||||
const bool apply_vbmeta)
|
||||
|
@ -66,14 +68,18 @@ void RebootTask::Run() {
|
|||
|
||||
FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
|
||||
std::unique_ptr<SuperFlashHelper> helper,
|
||||
SparsePtr sparse_layout)
|
||||
SparsePtr sparse_layout, uint64_t super_size)
|
||||
: super_name_(super_name),
|
||||
helper_(std::move(helper)),
|
||||
sparse_layout_(std::move(sparse_layout)) {}
|
||||
sparse_layout_(std::move(sparse_layout)),
|
||||
super_size_(super_size) {}
|
||||
|
||||
void FlashSuperLayoutTask::Run() {
|
||||
// Use the reported super partition size as the upper limit, rather than
|
||||
// sparse_file_len, which (1) can fail and (2) is kind of expensive, since
|
||||
// it will map in all of the embedded fds.
|
||||
std::vector<SparsePtr> files;
|
||||
if (int limit = get_sparse_limit(sparse_file_len(sparse_layout_.get(), false, false))) {
|
||||
if (int limit = get_sparse_limit(super_size_)) {
|
||||
files = resparse_file(sparse_layout_.get(), limit);
|
||||
} else {
|
||||
files.emplace_back(std::move(sparse_layout_));
|
||||
|
@ -107,12 +113,19 @@ std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
|
|||
if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) {
|
||||
super_name = "super";
|
||||
}
|
||||
std::string partition_size_str;
|
||||
|
||||
uint64_t partition_size;
|
||||
std::string partition_size_str;
|
||||
if (fp->fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) {
|
||||
LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition";
|
||||
return nullptr;
|
||||
}
|
||||
partition_size_str = fb_fix_numeric_var(partition_size_str);
|
||||
if (!android::base::ParseUint(partition_size_str, &partition_size)) {
|
||||
LOG(VERBOSE) << "Could not parse " << super_name << " size: " << partition_size_str;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source);
|
||||
if (!helper->Open(fd)) {
|
||||
return nullptr;
|
||||
|
@ -136,7 +149,8 @@ std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
|
|||
};
|
||||
os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback),
|
||||
os_images.end());
|
||||
return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s));
|
||||
return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s),
|
||||
partition_size);
|
||||
}
|
||||
|
||||
UpdateSuperTask::UpdateSuperTask(FlashingPlan* fp) : fp_(fp) {}
|
||||
|
|
|
@ -58,7 +58,7 @@ class RebootTask : public Task {
|
|||
class FlashSuperLayoutTask : public Task {
|
||||
public:
|
||||
FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper,
|
||||
SparsePtr sparse_layout);
|
||||
SparsePtr sparse_layout, uint64_t super_size);
|
||||
static std::unique_ptr<FlashSuperLayoutTask> Initialize(FlashingPlan* fp,
|
||||
std::vector<ImageEntry>& os_images);
|
||||
using ImageEntry = std::pair<const Image*, std::string>;
|
||||
|
@ -68,6 +68,7 @@ class FlashSuperLayoutTask : public Task {
|
|||
const std::string super_name_;
|
||||
std::unique_ptr<SuperFlashHelper> helper_;
|
||||
SparsePtr sparse_layout_;
|
||||
uint64_t super_size_;
|
||||
};
|
||||
|
||||
class UpdateSuperTask : public Task {
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
using android::base::borrowed_fd;
|
||||
|
@ -106,3 +109,12 @@ int64_t get_file_size(borrowed_fd fd) {
|
|||
}
|
||||
return sb.st_size;
|
||||
}
|
||||
|
||||
std::string fb_fix_numeric_var(std::string var) {
|
||||
// Some bootloaders (angler, for example), send spurious leading whitespace.
|
||||
var = android::base::Trim(var);
|
||||
// Some bootloaders (hammerhead, for example) use implicit hex.
|
||||
// This code used to use strtol with base 16.
|
||||
if (!android::base::StartsWith(var, "0x")) var = "0x" + var;
|
||||
return var;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ bool should_flash_in_userspace(const android::fs_mgr::LpMetadata& metadata,
|
|||
const std::string& partition_name);
|
||||
bool is_sparse_file(android::base::borrowed_fd fd);
|
||||
int64_t get_file_size(android::base::borrowed_fd fd);
|
||||
std::string fb_fix_numeric_var(std::string var);
|
||||
|
||||
class ImageSource {
|
||||
public:
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
|
||||
#define container_of(inner, outer_t, elem) ((outer_t*)((char*)(inner)-offsetof(outer_t, elem)))
|
||||
|
||||
static constexpr size_t kMaxMmapSize = 256 * 1024 * 1024;
|
||||
|
||||
struct output_file_ops {
|
||||
int (*open)(struct output_file*, int fd);
|
||||
int (*skip)(struct output_file*, int64_t);
|
||||
|
@ -71,6 +73,7 @@ struct sparse_file_ops {
|
|||
int (*write_fill_chunk)(struct output_file* out, uint64_t len, uint32_t fill_val);
|
||||
int (*write_skip_chunk)(struct output_file* out, uint64_t len);
|
||||
int (*write_end_chunk)(struct output_file* out);
|
||||
int (*write_fd_chunk)(struct output_file* out, uint64_t len, int fd, int64_t offset);
|
||||
};
|
||||
|
||||
struct output_file {
|
||||
|
@ -318,6 +321,26 @@ int read_all(int fd, void* buf, size_t len) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool write_fd_chunk_range(int fd, int64_t offset, uint64_t len, T callback) {
|
||||
uint64_t bytes_written = 0;
|
||||
int64_t current_offset = offset;
|
||||
while (bytes_written < len) {
|
||||
size_t mmap_size = std::min(static_cast<uint64_t>(kMaxMmapSize), len - bytes_written);
|
||||
auto m = android::base::MappedFile::FromFd(fd, current_offset, mmap_size, PROT_READ);
|
||||
if (!m) {
|
||||
error("failed to mmap region of length %zu", mmap_size);
|
||||
return false;
|
||||
}
|
||||
if (!callback(m->data(), mmap_size)) {
|
||||
return false;
|
||||
}
|
||||
bytes_written += mmap_size;
|
||||
current_offset += mmap_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int write_sparse_skip_chunk(struct output_file* out, uint64_t skip_len) {
|
||||
chunk_header_t chunk_header;
|
||||
int ret;
|
||||
|
@ -424,6 +447,61 @@ static int write_sparse_data_chunk(struct output_file* out, uint64_t len, void*
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int write_sparse_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset) {
|
||||
chunk_header_t chunk_header;
|
||||
uint64_t rnd_up_len, zero_len;
|
||||
int ret;
|
||||
|
||||
/* Round up the data length to a multiple of the block size */
|
||||
rnd_up_len = ALIGN(len, out->block_size);
|
||||
zero_len = rnd_up_len - len;
|
||||
|
||||
/* Finally we can safely emit a chunk of data */
|
||||
chunk_header.chunk_type = CHUNK_TYPE_RAW;
|
||||
chunk_header.reserved1 = 0;
|
||||
chunk_header.chunk_sz = rnd_up_len / out->block_size;
|
||||
chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len;
|
||||
ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
|
||||
|
||||
if (ret < 0) return -1;
|
||||
bool ok = write_fd_chunk_range(fd, offset, len, [&ret, out](char* data, size_t size) -> bool {
|
||||
ret = out->ops->write(out, data, size);
|
||||
if (ret < 0) return false;
|
||||
if (out->use_crc) {
|
||||
out->crc32 = sparse_crc32(out->crc32, data, size);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!ok) return -1;
|
||||
if (zero_len) {
|
||||
uint64_t len = zero_len;
|
||||
uint64_t write_len;
|
||||
while (len) {
|
||||
write_len = std::min(len, (uint64_t)FILL_ZERO_BUFSIZE);
|
||||
ret = out->ops->write(out, out->zero_buf, write_len);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
len -= write_len;
|
||||
}
|
||||
|
||||
if (out->use_crc) {
|
||||
uint64_t len = zero_len;
|
||||
uint64_t write_len;
|
||||
while (len) {
|
||||
write_len = std::min(len, (uint64_t)FILL_ZERO_BUFSIZE);
|
||||
out->crc32 = sparse_crc32(out->crc32, out->zero_buf, write_len);
|
||||
len -= write_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out->cur_out_ptr += rnd_up_len;
|
||||
out->chunk_cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_sparse_end_chunk(struct output_file* out) {
|
||||
chunk_header_t chunk_header;
|
||||
int ret;
|
||||
|
@ -454,6 +532,7 @@ static struct sparse_file_ops sparse_file_ops = {
|
|||
.write_fill_chunk = write_sparse_fill_chunk,
|
||||
.write_skip_chunk = write_sparse_skip_chunk,
|
||||
.write_end_chunk = write_sparse_end_chunk,
|
||||
.write_fd_chunk = write_sparse_fd_chunk,
|
||||
};
|
||||
|
||||
static int write_normal_data_chunk(struct output_file* out, uint64_t len, void* data) {
|
||||
|
@ -495,6 +574,23 @@ static int write_normal_fill_chunk(struct output_file* out, uint64_t len, uint32
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int write_normal_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset) {
|
||||
int ret;
|
||||
uint64_t rnd_up_len = ALIGN(len, out->block_size);
|
||||
|
||||
bool ok = write_fd_chunk_range(fd, offset, len, [&ret, out](char* data, size_t size) -> bool {
|
||||
ret = out->ops->write(out, data, size);
|
||||
return ret >= 0;
|
||||
});
|
||||
if (!ok) return ret;
|
||||
|
||||
if (rnd_up_len > len) {
|
||||
ret = out->ops->skip(out, rnd_up_len - len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_normal_skip_chunk(struct output_file* out, uint64_t len) {
|
||||
return out->ops->skip(out, len);
|
||||
}
|
||||
|
@ -508,6 +604,7 @@ static struct sparse_file_ops normal_file_ops = {
|
|||
.write_fill_chunk = write_normal_fill_chunk,
|
||||
.write_skip_chunk = write_normal_skip_chunk,
|
||||
.write_end_chunk = write_normal_end_chunk,
|
||||
.write_fd_chunk = write_normal_fd_chunk,
|
||||
};
|
||||
|
||||
void output_file_close(struct output_file* out) {
|
||||
|
@ -670,10 +767,7 @@ int write_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
|
|||
}
|
||||
|
||||
int write_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset) {
|
||||
auto m = android::base::MappedFile::FromFd(fd, offset, len, PROT_READ);
|
||||
if (!m) return -errno;
|
||||
|
||||
return out->sparse_ops->write_data_chunk(out, m->size(), m->data());
|
||||
return out->sparse_ops->write_fd_chunk(out, len, fd, offset);
|
||||
}
|
||||
|
||||
/* Write a contiguous region of data blocks from a file */
|
||||
|
|
Loading…
Reference in a new issue