Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f6e8856 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Support ZSTD in userspace COW"

parents c6ec1017 32dcac78
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -196,6 +196,7 @@ cc_binary {
        "libfastbootshim",
        "libsnapshot_cow",
        "liblz4",
        "libzstd",
        "libsnapshot_nobinder",
        "update_metadata-protos",
        "liburing",
+1 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ cc_defaults {
        "libbrotli",
        "libz",
        "liblz4",
        "libzstd",
    ],
    export_include_dirs: ["include"],
}
+2 −1
Original line number Diff line number Diff line
@@ -157,7 +157,8 @@ enum CowCompressionAlgorithm : uint8_t {
    kCowCompressNone = 0,
    kCowCompressGz = 1,
    kCowCompressBrotli = 2,
    kCowCompressLz4 = 3
    kCowCompressLz4 = 3,
    kCowCompressZstd = 4,
};

static constexpr uint8_t kCowReadAheadNotStarted = 0;
+20 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <libsnapshot/cow_writer.h>
#include <lz4.h>
#include <zlib.h>
#include <zstd.h>

namespace android {
namespace snapshot {
@@ -40,6 +41,8 @@ std::optional<CowCompressionAlgorithm> CompressionAlgorithmFromString(std::strin
        return {kCowCompressBrotli};
    } else if (name == "lz4") {
        return {kCowCompressLz4};
    } else if (name == "zstd") {
        return {kCowCompressZstd};
    } else if (name == "none" || name.empty()) {
        return {kCowCompressNone};
    } else {
@@ -112,6 +115,23 @@ std::basic_string<uint8_t> CompressWorker::Compress(CowCompressionAlgorithm comp
            }
            return buffer;
        }
        case kCowCompressZstd: {
            std::basic_string<uint8_t> buffer(ZSTD_compressBound(length), '\0');
            const auto compressed_size =
                    ZSTD_compress(buffer.data(), buffer.size(), data, length, 0);
            if (compressed_size <= 0) {
                LOG(ERROR) << "ZSTD compression failed " << compressed_size;
                return {};
            }
            // Don't run compression if the compressed output is larger
            if (compressed_size >= length) {
                buffer.resize(length);
                memcpy(buffer.data(), data, length);
            } else {
                buffer.resize(compressed_size);
            }
            return buffer;
        }
        default:
            LOG(ERROR) << "unhandled compression type: " << compression;
            break;
+50 −0
Original line number Diff line number Diff line
@@ -17,12 +17,15 @@
#include "cow_decompress.h"

#include <array>
#include <cstring>
#include <utility>
#include <vector>

#include <android-base/logging.h>
#include <brotli/decode.h>
#include <lz4.h>
#include <zlib.h>
#include <zstd.h>

namespace android {
namespace snapshot {
@@ -336,9 +339,56 @@ class Lz4Decompressor final : public IDecompressor {
    }
};

class ZstdDecompressor final : public IDecompressor {
  public:
    ssize_t Decompress(void* buffer, size_t buffer_size, size_t decompressed_size,
                       size_t ignore_bytes = 0) override {
        if (buffer_size < decompressed_size - ignore_bytes) {
            LOG(INFO) << "buffer size " << buffer_size
                      << " is not large enough to hold decompressed data. Decompressed size "
                      << decompressed_size << ", ignore_bytes " << ignore_bytes;
            return -1;
        }
        if (ignore_bytes == 0) {
            if (!Decompress(buffer, decompressed_size)) {
                return -1;
            }
            return decompressed_size;
        }
        std::vector<unsigned char> ignore_buf(decompressed_size);
        if (!Decompress(buffer, decompressed_size)) {
            return -1;
        }
        memcpy(buffer, ignore_buf.data() + ignore_bytes, buffer_size);
        return decompressed_size;
    }
    bool Decompress(void* output_buffer, const size_t output_size) {
        std::string input_buffer;
        input_buffer.resize(stream_->Size());
        size_t bytes_read = stream_->Read(input_buffer.data(), input_buffer.size());
        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 auto bytes_decompressed = ZSTD_decompress(output_buffer, output_size,
                                                        input_buffer.data(), input_buffer.size());
        if (bytes_decompressed != output_size) {
            LOG(ERROR) << "Failed to decompress ZSTD block, expected output size: " << output_size
                       << ", actual: " << bytes_decompressed;
            return false;
        }
        return true;
    }
};

std::unique_ptr<IDecompressor> IDecompressor::Lz4() {
    return std::make_unique<Lz4Decompressor>();
}

std::unique_ptr<IDecompressor> IDecompressor::Zstd() {
    return std::make_unique<ZstdDecompressor>();
}

}  // namespace snapshot
}  // namespace android
Loading