Merge "Add RKPD unit tests to trusty keymaster changes."
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 4eb7382..4043a6e 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -159,7 +159,8 @@
 }
 
 noinline void fprintf_null() {
-    fprintf(nullptr, "oops");
+    FILE* sneaky_null = nullptr;
+    fprintf(sneaky_null, "oops");
 }
 
 noinline void readdir_null() {
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 4d60ddb..517f2df 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -642,7 +642,7 @@
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
 
-  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 8 \(SEGV_MTEAERR\), fault addr --------)");
+  ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code [89] \(SEGV_MTE[AS]ERR\), fault addr)");
 #else
   GTEST_SKIP() << "Requires aarch64";
 #endif
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 430ff14..699d406 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -982,7 +982,7 @@
     fprintf(stderr, "--------------------------------------------\n");
 }
 
-static std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size) {
+std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size) {
     if (max_size <= 0 || max_size > std::numeric_limits<uint32_t>::max()) {
         die("invalid max size %" PRId64, max_size);
     }
@@ -1027,7 +1027,7 @@
     return value;
 }
 
-static int64_t get_sparse_limit(int64_t size) {
+int64_t get_sparse_limit(int64_t size) {
     int64_t limit = sparse_limit;
     if (limit == 0) {
         // Unlimited, so see what the target device's limit is.
@@ -1161,7 +1161,7 @@
 
 // Note: this only works in userspace fastboot. In the bootloader, use
 // should_flash_in_userspace().
-static bool is_logical(const std::string& partition) {
+bool is_logical(const std::string& partition) {
     std::string value;
     return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
 }
@@ -1243,8 +1243,7 @@
     lseek(buf->fd.get(), 0, SEEK_SET);
 }
 
-static void flash_partition_files(const std::string& partition,
-                                  const std::vector<SparsePtr>& files) {
+void flash_partition_files(const std::string& partition, const std::vector<SparsePtr>& files) {
     for (size_t i = 0; i < files.size(); i++) {
         sparse_file* s = files[i].get();
         int64_t sz = sparse_file_len(s, true, false);
@@ -1303,7 +1302,7 @@
     return count;
 }
 
-static bool supports_AB() {
+bool supports_AB() {
     return get_slot_count() >= 2;
 }
 
@@ -1426,7 +1425,7 @@
     }
 }
 
-static bool is_retrofit_device() {
+bool is_retrofit_device() {
     std::string value;
     if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) {
         return false;
@@ -1562,6 +1561,20 @@
     }
 }
 
+std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot) {
+    auto slot = entry.second;
+    if (slot.empty()) {
+        slot = current_slot;
+    }
+    if (slot.empty()) {
+        return entry.first->part_name;
+    }
+    if (slot == "all") {
+        LOG(FATAL) << "Cannot retrieve a singular name when using all slots";
+    }
+    return entry.first->part_name + "_" + slot;
+}
+
 class FlashAllTool {
   public:
     FlashAllTool(FlashingPlan* fp);
@@ -1574,16 +1587,12 @@
     void CollectImages();
     void FlashImages(const std::vector<std::pair<const Image*, std::string>>& images);
     void FlashImage(const Image& image, const std::string& slot, fastboot_buffer* buf);
-    void UpdateSuperPartition();
-    bool OptimizedFlashSuper();
 
     // If the image uses the default slot, or the user specified "all", then
     // the paired string will be empty. If the image requests a specific slot
     // (for example, system_other) it is specified instead.
     using ImageEntry = std::pair<const Image*, std::string>;
 
-    std::string GetPartitionName(const ImageEntry& entry);
-
     std::vector<ImageEntry> boot_images_;
     std::vector<ImageEntry> os_images_;
     FlashingPlan* fp_;
@@ -1612,92 +1621,41 @@
     // or in bootloader fastboot.
     FlashImages(boot_images_);
 
-    if (!OptimizedFlashSuper()) {
-        // Sync the super partition. This will reboot to userspace fastboot if needed.
-        UpdateSuperPartition();
+    auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_);
 
+    if (flash_super_task) {
+        flash_super_task->Run();
+    } else {
+        // Sync the super partition. This will reboot to userspace fastboot if needed.
+        std::unique_ptr<UpdateSuperTask> update_super_task = std::make_unique<UpdateSuperTask>(fp_);
+        update_super_task->Run();
         // Resize any logical partition to 0, so each partition is reset to 0
         // extents, and will achieve more optimal allocation.
+        std::vector<std::unique_ptr<ResizeTask>> resize_tasks;
         for (const auto& [image, slot] : os_images_) {
-            auto resize_partition = [](const std::string& partition) -> void {
-                if (is_logical(partition)) {
-                    fb->ResizePartition(partition, "0");
+            // Retrofit devices have two super partitions, named super_a and super_b.
+            // On these devices, secondary slots must be flashed as physical
+            // partitions (otherwise they would not mount on first boot). To enforce
+            // this, we delete any logical partitions for the "other" slot.
+            if (is_retrofit_device()) {
+                std::string partition_name = image->part_name + "_"s + slot;
+                if (image->IsSecondary() && is_logical(partition_name)) {
+                    fp_->fb->DeletePartition(partition_name);
+                    std::unique_ptr<DeleteTask> delete_task =
+                            std::make_unique<DeleteTask>(fp_, partition_name);
+                    delete_task->Run();
                 }
-            };
-            do_for_partitions(image->part_name, slot, resize_partition, false);
+            }
+            resize_tasks.emplace_back(
+                    std::make_unique<ResizeTask>(fp_, image->part_name, "0", slot));
+        }
+        for (auto& i : resize_tasks) {
+            i->Run();
         }
     }
-
-    // Flash OS images, resizing logical partitions as needed.
     FlashImages(os_images_);
 }
 
-bool FlashAllTool::OptimizedFlashSuper() {
-    if (!supports_AB()) {
-        LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device";
-        return false;
-    }
-    if (fp_->slot == "all") {
-        LOG(VERBOSE) << "Cannot optimize flashing super for all slots";
-        return false;
-    }
-
-    // Does this device use dynamic partitions at all?
-    unique_fd fd = fp_->source->OpenFile("super_empty.img");
-    if (fd < 0) {
-        LOG(VERBOSE) << "could not open super_empty.img";
-        return false;
-    }
-
-    // Try to find whether there is a super partition.
-    std::string super_name;
-    if (fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) {
-        super_name = "super";
-    }
-    std::string partition_size_str;
-    if (fb->GetVar("partition-size:" + super_name, &partition_size_str) != fastboot::SUCCESS) {
-        LOG(VERBOSE) << "Cannot optimize super flashing: could not determine super partition";
-        return false;
-    }
-
-    SuperFlashHelper helper(*fp_->source);
-    if (!helper.Open(fd)) {
-        return false;
-    }
-
-    for (const auto& entry : os_images_) {
-        auto partition = GetPartitionName(entry);
-        auto image = entry.first;
-
-        if (!helper.AddPartition(partition, image->img_name, image->optional_if_no_image)) {
-            return false;
-        }
-    }
-
-    auto s = helper.GetSparseLayout();
-    if (!s) {
-        return false;
-    }
-
-    std::vector<SparsePtr> files;
-    if (int limit = get_sparse_limit(sparse_file_len(s.get(), false, false))) {
-        files = resparse_file(s.get(), limit);
-    } else {
-        files.emplace_back(std::move(s));
-    }
-
-    // Send the data to the device.
-    flash_partition_files(super_name, files);
-
-    // Remove images that we already flashed, just in case we have non-dynamic OS images.
-    auto remove_if_callback = [&, this](const ImageEntry& entry) -> bool {
-        return helper.WillFlash(GetPartitionName(entry));
-    };
-    os_images_.erase(std::remove_if(os_images_.begin(), os_images_.end(), remove_if_callback),
-                     os_images_.end());
-    return true;
-}
-
 void FlashAllTool::CheckRequirements() {
     std::vector<char> contents;
     if (!fp_->source->ReadFile("android-info.txt", &contents)) {
@@ -1776,55 +1734,6 @@
     do_for_partitions(image.part_name, slot, flash, false);
 }
 
-void FlashAllTool::UpdateSuperPartition() {
-    unique_fd fd = fp_->source->OpenFile("super_empty.img");
-    if (fd < 0) {
-        return;
-    }
-    if (!is_userspace_fastboot()) {
-        reboot_to_userspace_fastboot();
-    }
-
-    std::string super_name;
-    if (fb->GetVar("super-partition-name", &super_name) != fastboot::RetCode::SUCCESS) {
-        super_name = "super";
-    }
-    fb->Download(super_name, fd, get_file_size(fd));
-
-    std::string command = "update-super:" + super_name;
-    if (fp_->wants_wipe) {
-        command += ":wipe";
-    }
-    fb->RawCommand(command, "Updating super partition");
-
-    // Retrofit devices have two super partitions, named super_a and super_b.
-    // On these devices, secondary slots must be flashed as physical
-    // partitions (otherwise they would not mount on first boot). To enforce
-    // this, we delete any logical partitions for the "other" slot.
-    if (is_retrofit_device()) {
-        for (const auto& [image, slot] : os_images_) {
-            std::string partition_name = image->part_name + "_"s + slot;
-            if (image->IsSecondary() && is_logical(partition_name)) {
-                fb->DeletePartition(partition_name);
-            }
-        }
-    }
-}
-
-std::string FlashAllTool::GetPartitionName(const ImageEntry& entry) {
-    auto slot = entry.second;
-    if (slot.empty()) {
-        slot = fp_->current_slot;
-    }
-    if (slot.empty()) {
-        return entry.first->part_name;
-    }
-    if (slot == "all") {
-        LOG(FATAL) << "Cannot retrieve a singular name when using all slots";
-    }
-    return entry.first->part_name + "_" + slot;
-}
-
 class ZipImageSource final : public ImageSource {
   public:
     explicit ZipImageSource(ZipArchiveHandle zip) : zip_(zip) {}
@@ -2456,11 +2365,14 @@
             fb->CreatePartition(partition, size);
         } else if (command == FB_CMD_DELETE_PARTITION) {
             std::string partition = next_arg(&args);
+            auto delete_task = std::make_unique<DeleteTask>(fp.get(), partition);
             fb->DeletePartition(partition);
         } else if (command == FB_CMD_RESIZE_PARTITION) {
             std::string partition = next_arg(&args);
             std::string size = next_arg(&args);
-            fb->ResizePartition(partition, size);
+            std::unique_ptr<ResizeTask> resize_task =
+                    std::make_unique<ResizeTask>(fp.get(), partition, size, slot_override);
+            resize_task->Run();
         } else if (command == "gsi") {
             std::string arg = next_arg(&args);
             if (arg == "wipe") {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 09666aa..2264ca3 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -29,6 +29,7 @@
 
 #include <string>
 #include "fastboot_driver.h"
+#include "super_flash_helper.h"
 #include "util.h"
 
 #include <bootimg.h>
@@ -82,7 +83,6 @@
     std::string current_slot;
     std::string secondary_slot;
     fastboot::FastBootDriver* fb;
-
 };
 
 bool should_flash_in_userspace(const std::string& partition_name);
@@ -100,4 +100,12 @@
     int port;
 };
 
-Result<NetworkSerial, FastbootError> ParseNetworkSerial(const std::string& serial);
\ No newline at end of file
+Result<NetworkSerial, FastbootError> ParseNetworkSerial(const std::string& serial);
+bool supports_AB();
+std::string GetPartitionName(const ImageEntry& entry, std::string& current_slot_);
+void flash_partition_files(const std::string& partition, const std::vector<SparsePtr>& files);
+int64_t get_sparse_limit(int64_t size);
+std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size);
+
+bool is_retrofit_device();
+bool is_logical(const std::string& partition);
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index a4aa637..6233c90 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -14,14 +14,15 @@
 // limitations under the License.
 //
 #include "task.h"
+#include <iostream>
 #include "fastboot.h"
-#include "util.h"
+#include "filesystem.h"
+#include "super_flash_helper.h"
 
-#include "fastboot.h"
-#include "util.h"
+using namespace std::string_literals;
 
-FlashTask::FlashTask(const std::string& _slot, const std::string& _pname)
-    : pname_(_pname), fname_(find_item(_pname)), slot_(_slot) {
+FlashTask::FlashTask(const std::string& slot, const std::string& pname)
+    : pname_(pname), fname_(find_item(pname)), slot_(slot) {
     if (fname_.empty()) die("cannot determine image filename for '%s'", pname_.c_str());
 }
 FlashTask::FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname)
@@ -43,9 +44,9 @@
     do_for_partitions(pname_, slot_, flash, true);
 }
 
-RebootTask::RebootTask(FlashingPlan* _fp) : fp_(_fp){};
-RebootTask::RebootTask(FlashingPlan* _fp, const std::string& _reboot_target)
-    : reboot_target_(_reboot_target), fp_(_fp){};
+RebootTask::RebootTask(FlashingPlan* fp) : fp_(fp){};
+RebootTask::RebootTask(FlashingPlan* fp, const std::string& reboot_target)
+    : reboot_target_(reboot_target), fp_(fp){};
 
 void RebootTask::Run() {
     if ((reboot_target_ == "userspace" || reboot_target_ == "fastboot")) {
@@ -66,3 +67,122 @@
         syntax_error("unknown reboot target %s", reboot_target_.c_str());
     }
 }
+
+FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
+                                           std::unique_ptr<SuperFlashHelper> helper,
+                                           SparsePtr sparse_layout)
+    : super_name_(super_name),
+      helper_(std::move(helper)),
+      sparse_layout_(std::move(sparse_layout)) {}
+
+void FlashSuperLayoutTask::Run() {
+    std::vector<SparsePtr> files;
+    if (int limit = get_sparse_limit(sparse_file_len(sparse_layout_.get(), false, false))) {
+        files = resparse_file(sparse_layout_.get(), limit);
+    } else {
+        files.emplace_back(std::move(sparse_layout_));
+    }
+
+    // Send the data to the device.
+    flash_partition_files(super_name_, files);
+}
+
+std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
+        FlashingPlan* fp, std::vector<ImageEntry>& os_images) {
+    if (!supports_AB()) {
+        LOG(VERBOSE) << "Cannot optimize flashing super on non-AB device";
+        return nullptr;
+    }
+    if (fp->slot == "all") {
+        LOG(VERBOSE) << "Cannot optimize flashing super for all slots";
+        return nullptr;
+    }
+
+    // Does this device use dynamic partitions at all?
+    unique_fd fd = fp->source->OpenFile("super_empty.img");
+
+    if (fd < 0) {
+        LOG(VERBOSE) << "could not open super_empty.img";
+        return nullptr;
+    }
+
+    std::string super_name;
+    // Try to find whether there is a super partition.
+    if (fp->fb->GetVar("super-partition-name", &super_name) != fastboot::SUCCESS) {
+        super_name = "super";
+    }
+    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;
+    }
+    std::unique_ptr<SuperFlashHelper> helper = std::make_unique<SuperFlashHelper>(*fp->source);
+    if (!helper->Open(fd)) {
+        return nullptr;
+    }
+
+    for (const auto& entry : os_images) {
+        auto partition = GetPartitionName(entry, fp->current_slot);
+        auto image = entry.first;
+
+        if (!helper->AddPartition(partition, image->img_name, image->optional_if_no_image)) {
+            return nullptr;
+        }
+    }
+
+    auto s = helper->GetSparseLayout();
+    if (!s) return nullptr;
+
+    // Remove images that we already flashed, just in case we have non-dynamic OS images.
+    auto remove_if_callback = [&](const ImageEntry& entry) -> bool {
+        return helper->WillFlash(GetPartitionName(entry, fp->current_slot));
+    };
+    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));
+}
+
+UpdateSuperTask::UpdateSuperTask(FlashingPlan* fp)
+    : fp_(fp) {}
+
+void UpdateSuperTask::Run() {
+    unique_fd fd = fp_->source->OpenFile("super_empty.img");
+    if (fd < 0) {
+        return;
+    }
+    if (!is_userspace_fastboot()) {
+        reboot_to_userspace_fastboot();
+    }
+
+    std::string super_name;
+    if (fp_->fb->GetVar("super-partition-name", &super_name) != fastboot::RetCode::SUCCESS) {
+        super_name = "super";
+    }
+    fp_->fb->Download(super_name, fd, get_file_size(fd));
+
+    std::string command = "update-super:" + super_name;
+    if (fp_->wants_wipe) {
+        command += ":wipe";
+    }
+    fp_->fb->RawCommand(command, "Updating super partition");
+}
+
+ResizeTask::ResizeTask(FlashingPlan* fp, const std::string& pname, const std::string& size,
+                       const std::string& slot)
+    : fp_(fp), pname_(pname), size_(size), slot_(slot) {}
+
+void ResizeTask::Run() {
+    auto resize_partition = [this](const std::string& partition) -> void {
+        if (is_logical(partition)) {
+            fp_->fb->ResizePartition(partition, size_);
+        }
+    };
+    do_for_partitions(pname_, slot_, resize_partition, false);
+}
+
+DeleteTask::DeleteTask(FlashingPlan* fp, const std::string& pname) : fp_(fp), pname_(pname){};
+
+void DeleteTask::Run() {
+    fp_->fb->DeletePartition(pname_);
+}
\ No newline at end of file
diff --git a/fastboot/task.h b/fastboot/task.h
index d8b9e21..0af771e 100644
--- a/fastboot/task.h
+++ b/fastboot/task.h
@@ -20,6 +20,8 @@
 
 #include "fastboot.h"
 #include "fastboot_driver.h"
+#include "super_flash_helper.h"
+#include "util.h"
 
 class Task {
   public:
@@ -30,11 +32,10 @@
 
 class FlashTask : public Task {
   public:
-    FlashTask(const std::string& _slot, const std::string& _pname);
-    FlashTask(const std::string& _slot, const std::string& _pname, const std::string& _fname);
+    FlashTask(const std::string& slot, const std::string& pname);
+    FlashTask(const std::string& slot, const std::string& pname, const std::string& fname);
 
     void Run() override;
-    ~FlashTask() {}
 
   private:
     const std::string pname_;
@@ -44,12 +45,58 @@
 
 class RebootTask : public Task {
   public:
-    RebootTask(FlashingPlan* _fp);
-    RebootTask(FlashingPlan* _fp, const std::string& _reboot_target);
+    RebootTask(FlashingPlan* fp);
+    RebootTask(FlashingPlan* fp, const std::string& reboot_target);
     void Run() override;
-    ~RebootTask() {}
 
   private:
     const std::string reboot_target_ = "";
-    FlashingPlan* fp_;
-};
\ No newline at end of file
+    const FlashingPlan* fp_;
+};
+
+class FlashSuperLayoutTask : public Task {
+  public:
+    FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper,
+                         SparsePtr sparse_layout);
+    static std::unique_ptr<FlashSuperLayoutTask> Initialize(FlashingPlan* fp,
+                                                            std::vector<ImageEntry>& os_images);
+    using ImageEntry = std::pair<const Image*, std::string>;
+    void Run() override;
+
+  private:
+    const std::string super_name_;
+    std::unique_ptr<SuperFlashHelper> helper_;
+    SparsePtr sparse_layout_;
+};
+
+class UpdateSuperTask : public Task {
+  public:
+    UpdateSuperTask(FlashingPlan* fp);
+    void Run() override;
+
+  private:
+    const FlashingPlan* fp_;
+};
+
+class ResizeTask : public Task {
+  public:
+    ResizeTask(FlashingPlan* fp, const std::string& pname, const std::string& size,
+               const std::string& slot);
+    void Run() override;
+
+  private:
+    const FlashingPlan* fp_;
+    const std::string pname_;
+    const std::string size_;
+    const std::string slot_;
+};
+
+class DeleteTask : public Task {
+  public:
+    DeleteTask(FlashingPlan* _fp, const std::string& _pname);
+    void Run() override;
+
+  private:
+    const FlashingPlan* fp_;
+    const std::string pname_;
+};
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 15f025c..f655522 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -3216,6 +3216,8 @@
         vabc_disable_reason = "recovery";
     } else if (!cow_format_support) {
         vabc_disable_reason = "cow format not supported";
+    } else if (!KernelSupportsCompressedSnapshots()) {
+        vabc_disable_reason = "kernel missing userspace block device support";
     }
 
     if (!vabc_disable_reason.empty()) {
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 13314da..460d49d 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -124,6 +124,10 @@
         SKIP_IF_NON_VIRTUAL_AB();
 
         SetupProperties();
+        if (!DeviceSupportsMode()) {
+            GTEST_SKIP() << "Mode not supported on this device";
+        }
+
         InitializeState();
         CleanupTestArtifacts();
         FormatFakeSuper();
@@ -159,7 +163,13 @@
         IPropertyFetcher::OverrideForTesting(std::move(fetcher));
 
         if (GetLegacyCompressionEnabledProperty() || CanUseUserspaceSnapshots()) {
-            snapuserd_required_ = true;
+            // If we're asked to test the device's actual configuration, then it
+            // may be misconfigured, so check for kernel support as libsnapshot does.
+            if (FLAGS_force_mode.empty()) {
+                snapuserd_required_ = KernelSupportsCompressedSnapshots();
+            } else {
+                snapuserd_required_ = true;
+            }
         }
     }
 
@@ -176,6 +186,16 @@
         LOG(INFO) << "Teardown complete for test: " << test_name_;
     }
 
+    bool DeviceSupportsMode() {
+        if (FLAGS_force_mode.empty()) {
+            return true;
+        }
+        if (snapuserd_required_ && !KernelSupportsCompressedSnapshots()) {
+            return false;
+        }
+        return true;
+    }
+
     void InitializeState() {
         ASSERT_TRUE(sm->EnsureImageManager());
         image_manager_ = sm->image_manager();
@@ -193,6 +213,11 @@
         // get an accurate list to remove.
         lock_ = nullptr;
 
+        // If there is no image manager, the test was skipped.
+        if (!image_manager_) {
+            return;
+        }
+
         std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a",
                                               "test_partition_b"};
         for (const auto& snapshot : snapshots) {
@@ -946,6 +971,11 @@
         SKIP_IF_NON_VIRTUAL_AB();
 
         SnapshotTest::SetUp();
+        if (!image_manager_) {
+            // Test was skipped.
+            return;
+        }
+
         Cleanup();
 
         // Cleanup() changes slot suffix, so initialize it again.
@@ -2680,6 +2710,9 @@
         CleanUp();
     }
     void CleanUp() {
+        if (!image_manager_) {
+            return;
+        }
         EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
                     image_manager_->DeleteBackingImage(kImageName));
     }
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index a98bf0e..1ffa89c 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -29,6 +29,7 @@
 #include <fs_mgr/roots.h>
 #include <liblp/property_fetcher.h>
 
+using android::dm::DeviceMapper;
 using android::dm::kSectorSize;
 using android::fiemap::FiemapStatus;
 using android::fs_mgr::EnsurePathMounted;
@@ -251,7 +252,10 @@
         LOG(INFO) << "Userspace snapshots disabled for testing";
         return false;
     }
-
+    if (!KernelSupportsCompressedSnapshots()) {
+        LOG(ERROR) << "Userspace snapshots requested, but no kernel support is available.";
+        return false;
+    }
     return true;
 }
 
@@ -278,5 +282,10 @@
     return fetcher->GetBoolProperty("snapuserd.test.dm.snapshots", false);
 }
 
+bool KernelSupportsCompressedSnapshots() {
+    auto& dm = DeviceMapper::Instance();
+    return dm.GetTargetByName("user", nullptr);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 8c4c7c6..370f3c4 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -127,6 +127,8 @@
 void AppendExtent(google::protobuf::RepeatedPtrField<chromeos_update_engine::Extent>* extents,
                   uint64_t start_block, uint64_t num_blocks);
 
+bool KernelSupportsCompressedSnapshots();
+
 bool GetLegacyCompressionEnabledProperty();
 bool GetUserspaceSnapshotsEnabledProperty();
 bool GetIouringEnabledProperty();
diff --git a/gatekeeperd/OWNERS b/gatekeeperd/OWNERS
index 9c99c6e..04cd19e 100644
--- a/gatekeeperd/OWNERS
+++ b/gatekeeperd/OWNERS
@@ -1,2 +1,5 @@
+# Bug component: 1124862
+drysdale@google.com
+oarbildo@google.com
+subrahmanyaman@google.com
 swillden@google.com
-jdanis@google.com
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 76fcd55..eb43a33 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -151,7 +151,7 @@
     void clear_sid(uint32_t userId) {
         char filename[21];
         snprintf(filename, sizeof(filename), "%u", userId);
-        if (remove(filename) < 0) {
+        if (remove(filename) < 0 && errno != ENOENT) {
             ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno));
             store_sid(userId, 0);
         }