Merge "Add lz4 support for VABC"

This commit is contained in:
Treehugger Robot 2022-06-30 00:15:42 +00:00 committed by Gerrit Code Review
commit 3854a69d39
10 changed files with 118 additions and 30 deletions

View file

@ -190,6 +190,7 @@ cc_binary {
"libhealthhalutils",
"libhealthshim",
"libsnapshot_cow",
"liblz4",
"libsnapshot_nobinder",
"update_metadata-protos",
],
@ -254,6 +255,7 @@ cc_defaults {
"libsparse",
"libutils",
"liblog",
"liblz4",
"libz",
"libdiagnose_usb",
"libbase",

View file

@ -44,7 +44,6 @@ cc_defaults {
"libext2_uuid",
"libext4_utils",
"libfstab",
"libsnapshot_cow",
"libsnapshot_snapuserd",
"libz",
],
@ -154,22 +153,6 @@ cc_defaults {
"-Wall",
"-Werror",
],
export_include_dirs: ["include"],
srcs: [
"cow_decompress.cpp",
"cow_reader.cpp",
"cow_writer.cpp",
"cow_format.cpp",
],
}
cc_library_static {
name: "libsnapshot_cow",
defaults: [
"libsnapshot_cow_defaults",
],
host_supported: true,
recovery_available: true,
shared_libs: [
"libbase",
"liblog",
@ -177,7 +160,24 @@ cc_library_static {
static_libs: [
"libbrotli",
"libz",
"liblz4",
],
export_include_dirs: ["include"],
}
cc_library_static {
name: "libsnapshot_cow",
defaults: [
"libsnapshot_cow_defaults",
],
srcs: [
"cow_decompress.cpp",
"cow_reader.cpp",
"cow_writer.cpp",
"cow_format.cpp",
],
host_supported: true,
recovery_available: true,
ramdisk_available: true,
vendor_ramdisk_available: true,
}
@ -214,7 +214,7 @@ cc_library_static {
cc_defaults {
name: "libsnapshot_test_defaults",
defaults: ["libsnapshot_defaults"],
defaults: ["libsnapshot_defaults", "libsnapshot_cow_defaults"],
srcs: [
"partition_cow_creator_test.cpp",
"snapshot_metadata_updater_test.cpp",
@ -295,6 +295,7 @@ cc_test {
cc_binary {
name: "snapshotctl",
defaults: ["libsnapshot_cow_defaults", "libsnapshot_hal_deps"],
srcs: [
"snapshotctl.cpp",
],
@ -343,6 +344,9 @@ cc_test {
cc_defaults {
name: "libsnapshot_fuzzer_defaults",
defaults: [
"libsnapshot_cow_defaults",
],
native_coverage : true,
srcs: [
// Compile the protobuf definition again with type full.
@ -416,6 +420,7 @@ cc_test {
name: "cow_api_test",
defaults: [
"fs_mgr_defaults",
"libsnapshot_cow_defaults",
],
srcs: [
"cow_api_test.cpp",
@ -471,6 +476,7 @@ cc_binary {
"libsparse",
"libxz",
"libz",
"liblz4",
"libziparchive",
"update_metadata-protos",
],
@ -486,6 +492,9 @@ cc_binary {
cc_binary {
name: "estimate_cow_from_nonab_ota",
defaults: [
"libsnapshot_cow_defaults",
],
host_supported: true,
device_supported: false,
cflags: [
@ -519,6 +528,7 @@ cc_binary {
name: "inspect_cow",
host_supported: true,
device_supported: true,
defaults: ["libsnapshot_cow_defaults"],
cflags: [
"-D_FILE_OFFSET_BITS=64",
"-Wall",

View file

@ -20,6 +20,7 @@
#include <android-base/logging.h>
#include <brotli/decode.h>
#include <lz4.h>
#include <zlib.h>
namespace android {
@ -260,5 +261,43 @@ std::unique_ptr<IDecompressor> IDecompressor::Brotli() {
return std::unique_ptr<IDecompressor>(new BrotliDecompressor());
}
class Lz4Decompressor final : public IDecompressor {
public:
~Lz4Decompressor() override = default;
bool Decompress(const size_t output_size) override {
size_t actual_buffer_size = 0;
auto&& output_buffer = sink_->GetBuffer(output_size, &actual_buffer_size);
if (actual_buffer_size != output_size) {
LOG(ERROR) << "Failed to allocate buffer of size " << output_size << " only got "
<< actual_buffer_size << " bytes";
return false;
}
std::string input_buffer;
input_buffer.resize(stream_->Size());
size_t bytes_read = 0;
stream_->Read(input_buffer.data(), input_buffer.size(), &bytes_read);
if (bytes_read != input_buffer.size()) {
LOG(ERROR) << "Failed to read all input at once. Expected: " << input_buffer.size()
<< " actual: " << bytes_read;
return false;
}
const int bytes_decompressed =
LZ4_decompress_safe(input_buffer.data(), static_cast<char*>(output_buffer),
input_buffer.size(), output_size);
if (bytes_decompressed != output_size) {
LOG(ERROR) << "Failed to decompress LZ4 block, expected output size: " << output_size
<< ", actual: " << bytes_decompressed;
return false;
}
sink_->ReturnData(output_buffer, output_size);
return true;
}
};
std::unique_ptr<IDecompressor> IDecompressor::Lz4() {
return std::make_unique<Lz4Decompressor>();
}
} // namespace snapshot
} // namespace android

View file

@ -41,6 +41,7 @@ class IDecompressor {
static std::unique_ptr<IDecompressor> Uncompressed();
static std::unique_ptr<IDecompressor> Gz();
static std::unique_ptr<IDecompressor> Brotli();
static std::unique_ptr<IDecompressor> Lz4();
// |output_bytes| is the expected total number of bytes to sink.
virtual bool Decompress(size_t output_bytes) = 0;

View file

@ -775,6 +775,9 @@ bool CowReader::ReadData(const CowOperation& op, IByteSink* sink) {
case kCowCompressBrotli:
decompressor = IDecompressor::Brotli();
break;
case kCowCompressLz4:
decompressor = IDecompressor::Lz4();
break;
default:
LOG(ERROR) << "Unknown compression type: " << op.compression;
return false;

View file

@ -24,8 +24,10 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <brotli/encode.h>
#include <libsnapshot/cow_format.h>
#include <libsnapshot/cow_reader.h>
#include <libsnapshot/cow_writer.h>
#include <lz4.h>
#include <zlib.h>
namespace android {
@ -129,6 +131,8 @@ bool CowWriter::ParseOptions() {
compression_ = kCowCompressGz;
} else if (options_.compression == "brotli") {
compression_ = kCowCompressBrotli;
} else if (options_.compression == "lz4") {
compression_ = kCowCompressLz4;
} else if (options_.compression == "none") {
compression_ = kCowCompressNone;
} else if (!options_.compression.empty()) {
@ -403,35 +407,56 @@ bool CowWriter::EmitClusterIfNeeded() {
std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
switch (compression_) {
case kCowCompressGz: {
auto bound = compressBound(length);
auto buffer = std::make_unique<uint8_t[]>(bound);
const auto bound = compressBound(length);
std::basic_string<uint8_t> buffer(bound, '\0');
uLongf dest_len = bound;
auto rv = compress2(buffer.get(), &dest_len, reinterpret_cast<const Bytef*>(data),
auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast<const Bytef*>(data),
length, Z_BEST_COMPRESSION);
if (rv != Z_OK) {
LOG(ERROR) << "compress2 returned: " << rv;
return {};
}
return std::basic_string<uint8_t>(buffer.get(), dest_len);
buffer.resize(dest_len);
return buffer;
}
case kCowCompressBrotli: {
auto bound = BrotliEncoderMaxCompressedSize(length);
const auto bound = BrotliEncoderMaxCompressedSize(length);
if (!bound) {
LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
return {};
}
auto buffer = std::make_unique<uint8_t[]>(bound);
std::basic_string<uint8_t> buffer(bound, '\0');
size_t encoded_size = bound;
auto rv = BrotliEncoderCompress(
BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length,
reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.get());
reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.data());
if (!rv) {
LOG(ERROR) << "BrotliEncoderCompress failed";
return {};
}
return std::basic_string<uint8_t>(buffer.get(), encoded_size);
buffer.resize(encoded_size);
return buffer;
}
case kCowCompressLz4: {
const auto bound = LZ4_compressBound(length);
if (!bound) {
LOG(ERROR) << "LZ4_compressBound returned 0";
return {};
}
std::basic_string<uint8_t> buffer(bound, '\0');
const auto compressed_size = LZ4_compress_default(
static_cast<const char*>(data), reinterpret_cast<char*>(buffer.data()), length,
buffer.size());
if (compressed_size <= 0) {
LOG(ERROR) << "LZ4_compress_default failed, input size: " << length
<< ", compression bound: " << bound << ", ret: " << compressed_size;
return {};
}
buffer.resize(compressed_size);
return buffer;
}
default:
LOG(ERROR) << "unhandled compression type: " << compression_;

View file

@ -154,9 +154,12 @@ static constexpr uint8_t kCowXorOp = 6;
static constexpr uint8_t kCowSequenceOp = 7;
static constexpr uint8_t kCowFooterOp = -1;
static constexpr uint8_t kCowCompressNone = 0;
static constexpr uint8_t kCowCompressGz = 1;
static constexpr uint8_t kCowCompressBrotli = 2;
enum CowCompressionAlgorithm : uint8_t {
kCowCompressNone = 0,
kCowCompressGz = 1,
kCowCompressBrotli = 2,
kCowCompressLz4 = 3
};
static constexpr uint8_t kCowReadAheadNotStarted = 0;
static constexpr uint8_t kCowReadAheadInProgress = 1;

View file

@ -155,7 +155,7 @@ class CowWriter : public ICowWriter {
android::base::borrowed_fd fd_;
CowHeader header_{};
CowFooter footer_{};
int compression_ = 0;
CowCompressionAlgorithm compression_ = kCowCompressNone;
uint64_t next_op_pos_ = 0;
uint64_t next_data_pos_ = 0;
uint32_t cluster_size_ = 0;

View file

@ -87,6 +87,7 @@ cc_defaults {
"liblog",
"libsnapshot_cow",
"libz",
"liblz4",
"libext4_utils",
"liburing",
],
@ -145,6 +146,7 @@ cc_test {
name: "cow_snapuserd_test",
defaults: [
"fs_mgr_defaults",
"libsnapshot_cow_defaults",
],
srcs: [
"dm-snapshot-merge/cow_snapuserd_test.cpp",
@ -186,6 +188,7 @@ cc_test {
name: "snapuserd_test",
defaults: [
"fs_mgr_defaults",
"libsnapshot_cow_defaults",
],
srcs: [
"user-space-merge/snapuserd_test.cpp",

View file

@ -164,6 +164,7 @@ libinit_cc_defaults {
"libcgrouprc_format",
"libfsverity_init",
"liblmkd_utils",
"liblz4",
"libmini_keyctl_static",
"libmodprobe",
"libprocinfo",
@ -362,6 +363,7 @@ cc_binary {
"libext2_uuid",
"libprotobuf-cpp-lite",
"libsnapshot_cow",
"liblz4",
"libsnapshot_init",
"update_metadata-protos",
"libprocinfo",