Merge "Use libcutils_headers for android_filesystem_config.h"
diff --git a/adb/apex/apex_manifest.json b/adb/apex/apex_manifest.json
index 0444409..4a07bdc 100644
--- a/adb/apex/apex_manifest.json
+++ b/adb/apex/apex_manifest.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.adbd",
-  "version": 300000000
+  "version": 300900700
 }
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a663871..50d7364 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -584,12 +584,11 @@
                 incoming_header_ = msg;
             } else {
                 size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
-                Block payload = std::move(block->payload);
                 if (block->payload.size() > bytes_left) {
                     HandleError("received too many bytes while waiting for payload");
                     return false;
                 }
-                incoming_payload_.append(std::move(payload));
+                incoming_payload_.append(std::move(block->payload));
             }
 
             if (incoming_header_->data_length == incoming_payload_.size()) {
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ad10a1f..99cabdd 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -343,6 +343,12 @@
     apex_available: [
         "com.android.runtime",
     ],
+
+    product_variables: {
+        experimental_mte: {
+            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+        },
+    },
 }
 
 cc_binary {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index d7cb972..c52c6f7 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -40,6 +40,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic/mte_kernel.h>
 #include <bionic/reserved_signals.h>
 #include <cutils/sockets.h>
 #include <log/log.h>
@@ -486,6 +487,17 @@
         continue;
       }
 
+#ifdef ANDROID_EXPERIMENTAL_MTE
+      struct iovec iov = {
+          &info.tagged_addr_ctrl,
+          sizeof(info.tagged_addr_ctrl),
+      };
+      if (ptrace(PTRACE_GETREGSET, thread, NT_ARM_TAGGED_ADDR_CTRL,
+                 reinterpret_cast<void*>(&iov)) == -1) {
+        info.tagged_addr_ctrl = -1;
+      }
+#endif
+
       if (thread == g_target_thread) {
         // Read the thread's registers along with the rest of the crash info out of the pipe.
         ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info);
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 108787e..5ed9e57 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -309,6 +309,11 @@
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
   ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
+
+  if (mte_supported()) {
+    // Test that the default TAGGED_ADDR_CTRL value is set.
+    ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)");
+  }
 }
 
 TEST_F(CrasherTest, tagged_fault_addr) {
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 04c4b5c..30e75e1 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -23,6 +23,7 @@
 
 struct ThreadInfo {
   std::unique_ptr<unwindstack::Regs> registers;
+  long tagged_addr_ctrl = -1;
 
   pid_t uid;
 
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 7af99c9..e1fe82b 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -180,6 +180,9 @@
   _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", thread_info.pid,
        thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
   _LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid);
+  if (thread_info.tagged_addr_ctrl != -1) {
+    _LOG(log, logtype::HEADER, "tagged_addr_ctrl: %016lx\n", thread_info.tagged_addr_ctrl);
+  }
 }
 
 static std::string get_addr_string(uint64_t addr) {
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index bdf1da6..0bb1b87 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -152,6 +152,7 @@
         "liblog",
     ],
     static_libs: [
+        "libbrotli",
         "libz",
     ],
     ramdisk_available: true,
@@ -362,10 +363,11 @@
 
     static_libs: [
         "libbase",
+        "libbrotli",
         "liblog",
         "libdm",
-	"libz",
-	"libsnapshot_cow",
+        "libz",
+        "libsnapshot_cow",
     ],
 }
 
@@ -403,12 +405,14 @@
         "libz",
     ],
     static_libs: [
+        "libbrotli",
         "libgtest",
         "libsnapshot_cow",
     ],
     test_min_api_level: 30,
     auto_gen_config: true,
     require_root: false,
+    host_supported: true,
 }
 
 cc_binary {
@@ -494,11 +498,12 @@
     shared_libs: [
         "libbase",
         "liblog",
-        "libz",
     ],
     static_libs: [
+        "libbrotli",
         "libgtest",
         "libsnapshot_cow",
+        "libz",
     ],
     header_libs: [
         "libstorage_literals_headers",
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index d98fe59..40d5efb 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -30,12 +30,12 @@
 
 class CowTest : public ::testing::Test {
   protected:
-    void SetUp() override {
+    virtual void SetUp() override {
         cow_ = std::make_unique<TemporaryFile>();
         ASSERT_GE(cow_->fd, 0) << strerror(errno);
     }
 
-    void TearDown() override { cow_ = nullptr; }
+    virtual void TearDown() override { cow_ = nullptr; }
 
     std::unique_ptr<TemporaryFile> cow_;
 };
@@ -70,7 +70,7 @@
     ASSERT_TRUE(writer.AddCopy(10, 20));
     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
     ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
-    ASSERT_TRUE(writer.Finalize());
+    ASSERT_TRUE(writer.Flush());
 
     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
 
@@ -105,7 +105,7 @@
     ASSERT_EQ(op->compression, kCowCompressNone);
     ASSERT_EQ(op->data_length, 4096);
     ASSERT_EQ(op->new_block, 50);
-    ASSERT_EQ(op->source, 104);
+    ASSERT_EQ(op->source, 106);
     ASSERT_TRUE(reader.ReadData(*op, &sink));
     ASSERT_EQ(sink.stream(), data);
 
@@ -145,7 +145,7 @@
     data.resize(options.block_size, '\0');
 
     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
-    ASSERT_TRUE(writer.Finalize());
+    ASSERT_TRUE(writer.Flush());
 
     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
 
@@ -163,7 +163,7 @@
     ASSERT_EQ(op->compression, kCowCompressGz);
     ASSERT_EQ(op->data_length, 56);  // compressed!
     ASSERT_EQ(op->new_block, 50);
-    ASSERT_EQ(op->source, 104);
+    ASSERT_EQ(op->source, 106);
     ASSERT_TRUE(reader.ReadData(*op, &sink));
     ASSERT_EQ(sink.stream(), data);
 
@@ -182,7 +182,7 @@
     data.resize(options.block_size * 2, '\0');
 
     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
-    ASSERT_TRUE(writer.Finalize());
+    ASSERT_TRUE(writer.Flush());
 
     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
 
@@ -211,9 +211,11 @@
     void* GetBuffer(size_t, size_t* actual) override { return StringSink::GetBuffer(1, actual); }
 };
 
-TEST_F(CowTest, HorribleSink) {
+class CompressionTest : public CowTest, public testing::WithParamInterface<const char*> {};
+
+TEST_P(CompressionTest, HorribleSink) {
     CowOptions options;
-    options.compression = "gz";
+    options.compression = GetParam();
     CowWriter writer(options);
 
     ASSERT_TRUE(writer.Initialize(cow_->fd));
@@ -222,7 +224,7 @@
     data.resize(options.block_size, '\0');
 
     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
-    ASSERT_TRUE(writer.Finalize());
+    ASSERT_TRUE(writer.Flush());
 
     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
 
@@ -239,6 +241,8 @@
     ASSERT_EQ(sink.stream(), data);
 }
 
+INSTANTIATE_TEST_SUITE_P(CowApi, CompressionTest, testing::Values("none", "gz", "brotli"));
+
 TEST_F(CowTest, GetSize) {
     CowOptions options;
     CowWriter writer(options);
@@ -255,7 +259,7 @@
     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
     ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
     auto size_before = writer.GetCowSize();
-    ASSERT_TRUE(writer.Finalize());
+    ASSERT_TRUE(writer.Flush());
     auto size_after = writer.GetCowSize();
     ASSERT_EQ(size_before, size_after);
     struct stat buf;
@@ -267,6 +271,60 @@
     ASSERT_EQ(buf.st_size, writer.GetCowSize());
 }
 
+TEST_F(CowTest, Append) {
+    CowOptions options;
+    auto writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
+    ASSERT_TRUE(writer->Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd, CowWriter::OpenMode::APPEND));
+
+    std::string data2 = "More data!";
+    data2.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
+    ASSERT_TRUE(writer->Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    struct stat buf;
+    ASSERT_EQ(fstat(cow_->fd, &buf), 0);
+    ASSERT_EQ(buf.st_size, writer->GetCowSize());
+
+    // Read back both operations.
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    StringSink sink;
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+
+    ASSERT_FALSE(iter->Done());
+    auto op = &iter->Get();
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data);
+
+    iter->Next();
+    sink.Reset();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data2);
+
+    iter->Next();
+    ASSERT_TRUE(iter->Done());
+}
+
 }  // namespace snapshot
 }  // namespace android
 
diff --git a/fs_mgr/libsnapshot/cow_decompress.cpp b/fs_mgr/libsnapshot/cow_decompress.cpp
index f480b85..faceafe 100644
--- a/fs_mgr/libsnapshot/cow_decompress.cpp
+++ b/fs_mgr/libsnapshot/cow_decompress.cpp
@@ -19,6 +19,7 @@
 #include <utility>
 
 #include <android-base/logging.h>
+#include <brotli/decode.h>
 #include <zlib.h>
 
 namespace android {
@@ -207,5 +208,57 @@
     return std::unique_ptr<IDecompressor>(new GzDecompressor());
 }
 
+class BrotliDecompressor final : public StreamDecompressor {
+  public:
+    ~BrotliDecompressor();
+
+    bool Init() override;
+    bool DecompressInput(const uint8_t* data, size_t length) override;
+    bool Done() override { return BrotliDecoderIsFinished(decoder_); }
+
+  private:
+    BrotliDecoderState* decoder_ = nullptr;
+};
+
+bool BrotliDecompressor::Init() {
+    decoder_ = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
+    return true;
+}
+
+BrotliDecompressor::~BrotliDecompressor() {
+    if (decoder_) {
+        BrotliDecoderDestroyInstance(decoder_);
+    }
+}
+
+bool BrotliDecompressor::DecompressInput(const uint8_t* data, size_t length) {
+    size_t available_in = length;
+    const uint8_t* next_in = data;
+
+    bool needs_more_output = false;
+    while (available_in || needs_more_output) {
+        if (!output_buffer_remaining_ && !GetFreshBuffer()) {
+            return false;
+        }
+
+        auto output_buffer = output_buffer_;
+        auto r = BrotliDecoderDecompressStream(decoder_, &available_in, &next_in,
+                                               &output_buffer_remaining_, &output_buffer_, nullptr);
+        if (r == BROTLI_DECODER_RESULT_ERROR) {
+            LOG(ERROR) << "brotli decode failed";
+            return false;
+        }
+        if (!sink_->ReturnData(output_buffer, output_buffer_ - output_buffer)) {
+            return false;
+        }
+        needs_more_output = (r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
+    }
+    return true;
+}
+
+std::unique_ptr<IDecompressor> IDecompressor::Brotli() {
+    return std::unique_ptr<IDecompressor>(new BrotliDecompressor());
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/cow_decompress.h b/fs_mgr/libsnapshot/cow_decompress.h
index 1c8c40d..f485256 100644
--- a/fs_mgr/libsnapshot/cow_decompress.h
+++ b/fs_mgr/libsnapshot/cow_decompress.h
@@ -40,6 +40,7 @@
     // Factory methods for decompression methods.
     static std::unique_ptr<IDecompressor> Uncompressed();
     static std::unique_ptr<IDecompressor> Gz();
+    static std::unique_ptr<IDecompressor> Brotli();
 
     // |output_bytes| is the expected total number of bytes to sink.
     virtual bool Decompress(size_t output_bytes) = 0;
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 1aea3a9..60093ab 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -78,6 +78,11 @@
                    << "Expected: " << kCowMagicNumber;
         return false;
     }
+    if (header_.header_size != sizeof(CowHeader)) {
+        LOG(ERROR) << "Header size unknown, read " << header_.header_size << ", expected "
+                   << sizeof(CowHeader);
+        return false;
+    }
 
     if ((header_.major_version != kCowVersionMajor) ||
         (header_.minor_version != kCowVersionMinor)) {
@@ -233,6 +238,9 @@
         case kCowCompressGz:
             decompressor = IDecompressor::Gz();
             break;
+        case kCowCompressBrotli:
+            decompressor = IDecompressor::Brotli();
+            break;
         default:
             LOG(ERROR) << "Unknown compression type: " << op.compression;
             return false;
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 6970ec1..80acb4a 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -162,7 +162,7 @@
     ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_2_.get(), size_));
 
     // Flush operations
-    ASSERT_TRUE(writer.Finalize());
+    ASSERT_TRUE(writer.Flush());
 
     ASSERT_EQ(lseek(cow->fd, 0, SEEK_SET), 0);
 }
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index 76238c2..4cf2119 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -22,6 +22,8 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
+#include <brotli/encode.h>
+#include <libsnapshot/cow_reader.h>
 #include <libsnapshot/cow_writer.h>
 #include <zlib.h>
 
@@ -39,17 +41,48 @@
     header_.magic = kCowMagicNumber;
     header_.major_version = kCowVersionMajor;
     header_.minor_version = kCowVersionMinor;
+    header_.header_size = sizeof(CowHeader);
     header_.block_size = options_.block_size;
 }
 
-bool CowWriter::Initialize(android::base::unique_fd&& fd) {
-    owned_fd_ = std::move(fd);
-    return Initialize(android::base::borrowed_fd{owned_fd_});
+bool CowWriter::ParseOptions() {
+    if (options_.compression == "gz") {
+        compression_ = kCowCompressGz;
+    } else if (options_.compression == "brotli") {
+        compression_ = kCowCompressBrotli;
+    } else if (options_.compression == "none") {
+        compression_ = kCowCompressNone;
+    } else if (!options_.compression.empty()) {
+        LOG(ERROR) << "unrecognized compression: " << options_.compression;
+        return false;
+    }
+    return true;
 }
 
-bool CowWriter::Initialize(android::base::borrowed_fd fd) {
+bool CowWriter::Initialize(android::base::unique_fd&& fd, OpenMode mode) {
+    owned_fd_ = std::move(fd);
+    return Initialize(android::base::borrowed_fd{owned_fd_}, mode);
+}
+
+bool CowWriter::Initialize(android::base::borrowed_fd fd, OpenMode mode) {
     fd_ = fd;
 
+    if (!ParseOptions()) {
+        return false;
+    }
+
+    switch (mode) {
+        case OpenMode::WRITE:
+            return OpenForWrite();
+        case OpenMode::APPEND:
+            return OpenForAppend();
+        default:
+            LOG(ERROR) << "Unknown open mode in CowWriter";
+            return false;
+    }
+}
+
+bool CowWriter::OpenForWrite() {
     // This limitation is tied to the data field size in CowOperation.
     if (header_.block_size > std::numeric_limits<uint16_t>::max()) {
         LOG(ERROR) << "Block size is too large";
@@ -61,31 +94,52 @@
         return false;
     }
 
-    if (options_.compression == "gz") {
-        compression_ = kCowCompressGz;
-    } else if (!options_.compression.empty()) {
-        LOG(ERROR) << "unrecognized compression: " << options_.compression;
+    // Headers are not complete, but this ensures the file is at the right
+    // position.
+    if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) {
+        PLOG(ERROR) << "write failed";
         return false;
     }
 
-    // Headers are not complete, but this ensures the file is at the right
-    // position.
-    if (!WriteFully(fd_, &header_, sizeof(header_))) {
-        PLOG(ERROR) << "write failed";
+    header_.ops_offset = header_.header_size;
+    return true;
+}
+
+bool CowWriter::OpenForAppend() {
+    auto reader = std::make_unique<CowReader>();
+    if (!reader->Parse(fd_) || !reader->GetHeader(&header_)) {
+        return false;
+    }
+    options_.block_size = header_.block_size;
+
+    // Reset this, since we're going to reimport all operations.
+    header_.num_ops = 0;
+
+    auto iter = reader->GetOpIter();
+    while (!iter->Done()) {
+        auto& op = iter->Get();
+        AddOperation(op);
+
+        iter->Next();
+    }
+
+    // Free reader so we own the descriptor position again.
+    reader = nullptr;
+
+    // Seek to the end of the data section.
+    if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek failed";
         return false;
     }
     return true;
 }
 
 bool CowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
-    header_.num_ops++;
-
     CowOperation op = {};
     op.type = kCowCopyOp;
     op.new_block = new_block;
     op.source = old_block;
-    ops_ += std::basic_string<uint8_t>(reinterpret_cast<uint8_t*>(&op), sizeof(op));
-
+    AddOperation(op);
     return true;
 }
 
@@ -103,8 +157,6 @@
 
     const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
     for (size_t i = 0; i < size / header_.block_size; i++) {
-        header_.num_ops++;
-
         CowOperation op = {};
         op.type = kCowReplaceOp;
         op.new_block = new_block_start + i;
@@ -120,7 +172,7 @@
                 LOG(ERROR) << "Compressed block is too large: " << data.size() << " bytes";
                 return false;
             }
-            if (!WriteFully(fd_, data.data(), data.size())) {
+            if (!WriteRawData(data.data(), data.size())) {
                 PLOG(ERROR) << "AddRawBlocks: write failed";
                 return false;
             }
@@ -132,11 +184,11 @@
             pos += header_.block_size;
         }
 
-        ops_ += std::basic_string<uint8_t>(reinterpret_cast<uint8_t*>(&op), sizeof(op));
+        AddOperation(op);
         iter += header_.block_size;
     }
 
-    if (!compression_ && !WriteFully(fd_, data, size)) {
+    if (!compression_ && !WriteRawData(data, size)) {
         PLOG(ERROR) << "AddRawBlocks: write failed";
         return false;
     }
@@ -145,13 +197,11 @@
 
 bool CowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
     for (uint64_t i = 0; i < num_blocks; i++) {
-        header_.num_ops++;
-
         CowOperation op = {};
         op.type = kCowZeroOp;
         op.new_block = new_block_start + i;
         op.source = 0;
-        ops_ += std::basic_string<uint8_t>(reinterpret_cast<uint8_t*>(&op), sizeof(op));
+        AddOperation(op);
     }
     return true;
 }
@@ -171,6 +221,24 @@
             }
             return std::basic_string<uint8_t>(buffer.get(), dest_len);
         }
+        case kCowCompressBrotli: {
+            auto bound = BrotliEncoderMaxCompressedSize(length);
+            if (!bound) {
+                LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
+                return {};
+            }
+            auto buffer = std::make_unique<uint8_t[]>(bound);
+
+            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());
+            if (!rv) {
+                LOG(ERROR) << "BrotliEncoderCompress failed";
+                return {};
+            }
+            return std::basic_string<uint8_t>(buffer.get(), encoded_size);
+        }
         default:
             LOG(ERROR) << "unhandled compression type: " << compression_;
             break;
@@ -189,17 +257,7 @@
 #endif
 }
 
-bool CowWriter::Finalize() {
-    // If both fields are set then Finalize is already called.
-    if (header_.ops_offset > 0 && header_.ops_size > 0) {
-        return true;
-    }
-    auto offs = lseek(fd_.get(), 0, SEEK_CUR);
-    if (offs < 0) {
-        PLOG(ERROR) << "lseek failed";
-        return false;
-    }
-    header_.ops_offset = offs;
+bool CowWriter::Flush() {
     header_.ops_size = ops_.size();
 
     memset(header_.ops_checksum, 0, sizeof(uint8_t) * 32);
@@ -212,8 +270,6 @@
         PLOG(ERROR) << "lseek failed";
         return false;
     }
-    // Header is already written, calling WriteFully will increment
-    // bytes_written_. So use android::base::WriteFully() here.
     if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) {
         PLOG(ERROR) << "write header failed";
         return false;
@@ -227,13 +283,16 @@
         return false;
     }
 
-    // clear ops_ so that subsequent calls to GetSize() still works.
-    ops_.clear();
+    // Re-position for any subsequent writes.
+    if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek ops failed";
+        return false;
+    }
     return true;
 }
 
 size_t CowWriter::GetCowSize() {
-    return bytes_written_ + ops_.size() * sizeof(ops_[0]);
+    return header_.ops_offset + header_.num_ops * sizeof(CowOperation);
 }
 
 bool CowWriter::GetDataPos(uint64_t* pos) {
@@ -246,9 +305,17 @@
     return true;
 }
 
-bool CowWriter::WriteFully(base::borrowed_fd fd, const void* data, size_t size) {
-    bytes_written_ += size;
-    return android::base::WriteFully(fd, data, size);
+void CowWriter::AddOperation(const CowOperation& op) {
+    header_.num_ops++;
+    ops_.insert(ops_.size(), reinterpret_cast<const uint8_t*>(&op), sizeof(op));
+}
+
+bool CowWriter::WriteRawData(const void* data, size_t size) {
+    if (!android::base::WriteFully(fd_, data, size)) {
+        return false;
+    }
+    header_.ops_offset += size;
+    return true;
 }
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp b/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
index 45833e1..2a0136b 100644
--- a/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
+++ b/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
@@ -375,7 +375,7 @@
         }
     }
 
-    if (!writer->Finalize()) {
+    if (!writer->Flush()) {
         return false;
     }
 
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 6d500e7..4a6bd4e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -45,6 +45,9 @@
     uint16_t major_version;
     uint16_t minor_version;
 
+    // Size of this struct.
+    uint16_t header_size;
+
     // Offset to the location of the operation sequence, and size of the
     // operation sequence buffer. |ops_offset| is also the end of the
     // raw data region.
@@ -98,6 +101,7 @@
 
 static constexpr uint8_t kCowCompressNone = 0;
 static constexpr uint8_t kCowCompressGz = 1;
+static constexpr uint8_t kCowCompressBrotli = 2;
 
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 8826b7a..8569161 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -47,12 +47,11 @@
     // Encode a sequence of zeroed blocks. |size| must be a multiple of the block size.
     virtual bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0;
 
-    // Finalize all COW operations and flush pending writes.
-    // Return true if successful.
-    virtual bool Finalize() = 0;
+    // Flush all pending writes. This must be called before closing the writer
+    // to ensure that the correct headers and footers are written.
+    virtual bool Flush() = 0;
 
-    // Return 0 if failed, on success return number of bytes the cow image would be
-    // after calling Finalize();
+    // Return number of bytes the cow image occupies on disk.
     virtual size_t GetCowSize() = 0;
 
   protected:
@@ -61,24 +60,30 @@
 
 class CowWriter : public ICowWriter {
   public:
+    enum class OpenMode { WRITE, APPEND };
+
     explicit CowWriter(const CowOptions& options);
 
     // Set up the writer.
-    bool Initialize(android::base::unique_fd&& fd);
-    bool Initialize(android::base::borrowed_fd fd);
+    bool Initialize(android::base::unique_fd&& fd, OpenMode mode = OpenMode::WRITE);
+    bool Initialize(android::base::borrowed_fd fd, OpenMode mode = OpenMode::WRITE);
 
     bool AddCopy(uint64_t new_block, uint64_t old_block) override;
     bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
     bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
 
-    bool Finalize() override;
+    bool Flush() override;
 
     size_t GetCowSize() override;
 
   private:
     void SetupHeaders();
+    bool ParseOptions();
+    bool OpenForWrite();
+    bool OpenForAppend();
     bool GetDataPos(uint64_t* pos);
-    bool WriteFully(base::borrowed_fd fd, const void* data, size_t size);
+    bool WriteRawData(const void* data, size_t size);
+    void AddOperation(const CowOperation& op);
     std::basic_string<uint8_t> Compress(const void* data, size_t length);
 
   private:
@@ -90,7 +95,6 @@
     // :TODO: this is not efficient, but stringstream ubsan aborts because some
     // bytes overflow a signed char.
     std::basic_string<uint8_t> ops_;
-    std::atomic<size_t> bytes_written_ = 0;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
index d0b8f52..f761077 100644
--- a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
+++ b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
@@ -204,7 +204,7 @@
         }
     }
 
-    if (!writer_->Finalize()) {
+    if (!writer_->Flush()) {
         LOG(ERROR) << "Unable to finalize COW for " << partition_name;
         return false;
     }
diff --git a/include/sysutils b/include/sysutils
deleted file mode 120000
index 1c8e85b..0000000
--- a/include/sysutils
+++ /dev/null
@@ -1 +0,0 @@
-../libsysutils/include/sysutils/
\ No newline at end of file
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index 053ebf8..0f584b2 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -86,6 +86,8 @@
 for a file matching the uevent `FIRMWARE`. It then forks a process to serve this firmware to the
 kernel.
 
+`/apex/*/firmware` is also searched after a list of firmware directories.
+
 The list of firmware directories is customized by a `firmware_directories` line in a ueventd.rc
 file. This line takes the format of
 
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index dff7b69..b50b4ef 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -17,6 +17,7 @@
 #include "firmware_handler.h"
 
 #include <fcntl.h>
+#include <glob.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -30,6 +31,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
@@ -203,25 +205,28 @@
     }
 
     std::vector<std::string> attempted_paths_and_errors;
-
-    int booting = IsBooting();
-try_loading_again:
-    attempted_paths_and_errors.clear();
-    for (const auto& firmware_directory : firmware_directories_) {
+    auto TryLoadFirmware = [&](const std::string& firmware_directory) {
         std::string file = firmware_directory + firmware;
         unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
         if (fw_fd == -1) {
             attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
                                                     ", open failed: " + strerror(errno));
-            continue;
+            return false;
         }
         struct stat sb;
         if (fstat(fw_fd, &sb) == -1) {
             attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
                                                     ", fstat failed: " + strerror(errno));
-            continue;
+            return false;
         }
         LoadFirmware(firmware, root, fw_fd, sb.st_size, loading_fd, data_fd);
+        return true;
+    };
+
+    int booting = IsBooting();
+try_loading_again:
+    attempted_paths_and_errors.clear();
+    if (ForEachFirmwareDirectory(TryLoadFirmware)) {
         return;
     }
 
@@ -242,6 +247,33 @@
     write(loading_fd, "-1", 2);
 }
 
+bool FirmwareHandler::ForEachFirmwareDirectory(
+        std::function<bool(const std::string&)> handler) const {
+    for (const std::string& firmware_directory : firmware_directories_) {
+        if (std::invoke(handler, firmware_directory)) {
+            return true;
+        }
+    }
+
+    glob_t glob_result;
+    glob("/apex/*/firmware/", GLOB_MARK, nullptr, &glob_result);
+    auto free_glob = android::base::make_scope_guard(std::bind(&globfree, &glob_result));
+    for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+        char* apex_firmware_directory = glob_result.gl_pathv[i];
+        // Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
+        // /apex/<name> paths, so unless we filter them out, we will look into the
+        // same apex twice.
+        if (strchr(apex_firmware_directory, '@')) {
+            continue;
+        }
+        if (std::invoke(handler, apex_firmware_directory)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void FirmwareHandler::HandleUevent(const Uevent& uevent) {
     if (uevent.subsystem != "firmware" || uevent.action != "add") return;
 
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index b4138f1..8b758ae 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -18,6 +18,7 @@
 
 #include <pwd.h>
 
+#include <functional>
 #include <string>
 #include <vector>
 
@@ -52,6 +53,7 @@
                                            const Uevent& uevent) const;
     std::string GetFirmwarePath(const Uevent& uevent) const;
     void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const;
+    bool ForEachFirmwareDirectory(std::function<bool(const std::string&)> handler) const;
 
     std::vector<std::string> firmware_directories_;
     std::vector<ExternalFirmwareHandler> external_firmware_handlers_;
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 9c1c463..8f15541 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -43,6 +43,7 @@
         "//apex_available:anyapex",
     ],
     min_sdk_version: "29",
+    sdk_version: "minimum",
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     system_shared_libs: [],
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index c9e245d..26d9f65 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -141,15 +141,14 @@
     return false;
   }
 
-  uint16_t data2;
-  if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+  uint8_t data2;
+  if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x05) {
     return false;
   }
 
   // __restore_rt:
   // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
   // 0x0f 0x05                            syscall
-  // 0x0f                                 nopl 0x0($rax)
 
   // Read the mcontext data from the stack.
   // sp points to the ucontext data structure, read only the mcontext part.