Merge "Add lz4 support for VABC"
This commit is contained in:
commit
3854a69d39
10 changed files with 118 additions and 30 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue