Merge "libfs_avb: verifying vbmeta digest early"
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 6e43b08..bc2d33d 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -408,12 +408,21 @@
   }
 }
 
-static bool link_fd(borrowed_fd fd, borrowed_fd dirfd, const std::string& path) {
-  std::string fd_path = StringPrintf("/proc/self/fd/%d", fd.get());
+static bool rename_tombstone_fd(borrowed_fd fd, borrowed_fd dirfd, const std::string& path) {
+  // Always try to unlink the tombstone file.
+  // linkat doesn't let us replace a file, so we need to unlink before linking
+  // our results onto disk, and if we fail for some reason, we should delete
+  // stale tombstones to avoid confusing inconsistency.
+  int rc = unlinkat(dirfd.get(), path.c_str(), 0);
+  if (rc != 0 && errno != ENOENT) {
+    PLOG(ERROR) << "failed to unlink tombstone at " << path;
+    return false;
+  }
 
-  int rc = linkat(AT_FDCWD, fd_path.c_str(), dirfd.get(), path.c_str(), AT_SYMLINK_FOLLOW);
+  std::string fd_path = StringPrintf("/proc/self/fd/%d", fd.get());
+  rc = linkat(AT_FDCWD, fd_path.c_str(), dirfd.get(), path.c_str(), AT_SYMLINK_FOLLOW);
   if (rc != 0) {
-    PLOG(ERROR) << "failed to link file descriptor";
+    PLOG(ERROR) << "failed to link tombstone at " << path;
     return false;
   }
   return true;
@@ -446,36 +455,22 @@
 
   CrashArtifactPaths paths = queue->get_next_artifact_paths();
 
-  // Always try to unlink the tombstone file.
-  // linkat doesn't let us replace a file, so we need to unlink before linking
-  // our results onto disk, and if we fail for some reason, we should delete
-  // stale tombstones to avoid confusing inconsistency.
-  rc = unlinkat(queue->dir_fd().get(), paths.text.c_str(), 0);
-  if (rc != 0 && errno != ENOENT) {
-    PLOG(ERROR) << "failed to unlink tombstone at " << paths.text;
-    return;
-  }
-
-  if (crash->output.text.fd != -1) {
-    if (!link_fd(crash->output.text.fd, queue->dir_fd(), paths.text)) {
-      LOG(ERROR) << "failed to link tombstone";
+  if (rename_tombstone_fd(crash->output.text.fd, queue->dir_fd(), paths.text)) {
+    if (crash->crash_type == kDebuggerdJavaBacktrace) {
+      LOG(ERROR) << "Traces for pid " << crash->crash_pid << " written to: " << paths.text;
     } else {
-      if (crash->crash_type == kDebuggerdJavaBacktrace) {
-        LOG(ERROR) << "Traces for pid " << crash->crash_pid << " written to: " << paths.text;
-      } else {
-        // NOTE: Several tools parse this log message to figure out where the
-        // tombstone associated with a given native crash was written. Any changes
-        // to this message must be carefully considered.
-        LOG(ERROR) << "Tombstone written to: " << paths.text;
-      }
+      // NOTE: Several tools parse this log message to figure out where the
+      // tombstone associated with a given native crash was written. Any changes
+      // to this message must be carefully considered.
+      LOG(ERROR) << "Tombstone written to: " << paths.text;
     }
   }
 
   if (crash->output.proto && crash->output.proto->fd != -1) {
     if (!paths.proto) {
       LOG(ERROR) << "missing path for proto tombstone";
-    } else if (!link_fd(crash->output.proto->fd, queue->dir_fd(), *paths.proto)) {
-      LOG(ERROR) << "failed to link proto tombstone";
+    } else {
+      rename_tombstone_fd(crash->output.proto->fd, queue->dir_fd(), *paths.proto);
     }
   }
 
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 2b2a0bf..b2b6a9e 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -659,7 +659,7 @@
             return device->WriteFail("No snapshot merge is in progress");
         }
 
-        auto sm = SnapshotManager::NewForFirstStageMount();
+        auto sm = SnapshotManager::New();
         if (!sm) {
             return device->WriteFail("Unable to create SnapshotManager");
         }
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 36e1169..42bff14 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -156,7 +156,7 @@
     MergePhase merge_phase = 6;
 }
 
-// Next: 4
+// Next: 5
 message SnapshotMergeReport {
     // Status of the update after the merge attempts.
     UpdateState state = 1;
@@ -167,4 +167,7 @@
 
     // Total size of all the COW images before the update.
     uint64 cow_file_size = 3;
+
+    // Whether compression/dm-user was used for any snapshots.
+    bool compression_enabled = 4;
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index 92e7910..1e420cb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -32,6 +32,7 @@
                 (const std::function<bool()>& callback, const std::function<bool()>& before_cancel),
                 (override));
     MOCK_METHOD(UpdateState, GetUpdateState, (double* progress), (override));
+    MOCK_METHOD(bool, UpdateUsesCompression, (), (override));
     MOCK_METHOD(Return, CreateUpdateSnapshots,
                 (const chromeos_update_engine::DeltaArchiveManifest& manifest), (override));
     MOCK_METHOD(bool, MapUpdateSnapshot,
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index ff7a727..0d90f6c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -170,6 +170,10 @@
     //   Other: 0
     virtual UpdateState GetUpdateState(double* progress = nullptr) = 0;
 
+    // Returns true if compression is enabled for the current update. This always returns false if
+    // UpdateState is None, or no snapshots have been created.
+    virtual bool UpdateUsesCompression() = 0;
+
     // Create necessary COW device / files for OTA clients. New logical partitions will be added to
     // group "cow" in target_metadata. Regions of partitions of current_metadata will be
     // "write-protected" and snapshotted.
@@ -326,6 +330,7 @@
     UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
                                    const std::function<bool()>& before_cancel = {}) override;
     UpdateState GetUpdateState(double* progress = nullptr) override;
+    bool UpdateUsesCompression() override;
     Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                            std::string* snapshot_path) override;
@@ -720,6 +725,9 @@
 
     SnapuserdClient* snapuserd_client() const { return snapuserd_client_.get(); }
 
+    // Helper of UpdateUsesCompression
+    bool UpdateUsesCompression(LockedFile* lock);
+
     std::string gsid_dir_;
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index d691d4f..96d2deb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -28,7 +28,7 @@
     virtual ~ISnapshotMergeStats() = default;
     // Called when merge starts or resumes.
     virtual bool Start() = 0;
-    virtual void set_state(android::snapshot::UpdateState state) = 0;
+    virtual void set_state(android::snapshot::UpdateState state, bool using_compression) = 0;
     virtual void set_cow_file_size(uint64_t cow_file_size) = 0;
     virtual uint64_t cow_file_size() = 0;
 
@@ -51,7 +51,7 @@
 
     // ISnapshotMergeStats overrides
     bool Start() override;
-    void set_state(android::snapshot::UpdateState state) override;
+    void set_state(android::snapshot::UpdateState state, bool using_compression) override;
     void set_cow_file_size(uint64_t cow_file_size) override;
     uint64_t cow_file_size() override;
     std::unique_ptr<Result> Finish() override;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index cba3560..3365ceb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -32,6 +32,7 @@
     UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
                                    const std::function<bool()>& before_cancel = {}) override;
     UpdateState GetUpdateState(double* progress = nullptr) override;
+    bool UpdateUsesCompression() override;
     Return CreateUpdateSnapshots(
             const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 9329725..90225f8 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -94,7 +94,11 @@
     if (!info) {
         info = new DeviceInfo();
     }
-    return std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
+    auto sm = std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
+    if (info->IsRecovery()) {
+        sm->ForceLocalImageManager();
+    }
+    return sm;
 }
 
 std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceInfo* info) {
@@ -1683,6 +1687,17 @@
     return state;
 }
 
+bool SnapshotManager::UpdateUsesCompression() {
+    auto lock = LockShared();
+    if (!lock) return false;
+    return UpdateUsesCompression(lock.get());
+}
+
+bool SnapshotManager::UpdateUsesCompression(LockedFile* lock) {
+    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
+    return update_status.compression_enabled();
+}
+
 bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots) {
     CHECK(lock);
 
@@ -2109,7 +2124,7 @@
 
     auto& dm = DeviceMapper::Instance();
 
-    if (IsCompressionEnabled() && !UnmapDmUserDevice(name)) {
+    if (UpdateUsesCompression(lock) && !UnmapDmUserDevice(name)) {
         return false;
     }
 
@@ -3087,7 +3102,8 @@
     std::stringstream ss;
 
     ss << "Update state: " << ReadUpdateState(file.get()) << std::endl;
-
+    ss << "Compression: " << ReadSnapshotUpdateStatus(file.get()).compression_enabled()
+       << std::endl;
     ss << "Current slot: " << device_->GetSlotSuffix() << std::endl;
     ss << "Boot indicator: booting from " << GetCurrentSlot() << " slot" << std::endl;
     ss << "Rollback indicator: "
@@ -3169,7 +3185,7 @@
 
     auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
     auto super_path = device_->GetSuperDevice(slot_number);
-    if (!CreateLogicalAndSnapshotPartitions(super_path)) {
+    if (!CreateLogicalAndSnapshotPartitions(super_path, 20s)) {
         LOG(ERROR) << "Unable to map partitions to complete merge.";
         return false;
     }
@@ -3209,7 +3225,7 @@
 
     auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
     auto super_path = device_->GetSuperDevice(slot_number);
-    if (!CreateLogicalAndSnapshotPartitions(super_path)) {
+    if (!CreateLogicalAndSnapshotPartitions(super_path, 20s)) {
         LOG(ERROR) << "Unable to map partitions to complete merge.";
         return false;
     }
@@ -3355,7 +3371,7 @@
     auto slot_suffix = device_->GetOtherSlotSuffix();
     auto slot_number = SlotNumberForSlotSuffix(slot_suffix);
     auto super_path = device_->GetSuperDevice(slot_number);
-    if (!CreateLogicalAndSnapshotPartitions(super_path)) {
+    if (!CreateLogicalAndSnapshotPartitions(super_path, 20s)) {
         LOG(ERROR) << "Unable to map partitions.";
         return CreateResult::ERROR;
     }
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 3723730..513700d 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -84,8 +84,9 @@
     return WriteState();
 }
 
-void SnapshotMergeStats::set_state(android::snapshot::UpdateState state) {
+void SnapshotMergeStats::set_state(android::snapshot::UpdateState state, bool using_compression) {
     report_.set_state(state);
+    report_.set_compression_enabled(using_compression);
 }
 
 void SnapshotMergeStats::set_cow_file_size(uint64_t cow_file_size) {
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 26b9129..8a254c9 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -116,9 +116,14 @@
     return nullptr;
 }
 
+bool SnapshotManagerStub::UpdateUsesCompression() {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return false;
+}
+
 class SnapshotMergeStatsStub : public ISnapshotMergeStats {
     bool Start() override { return false; }
-    void set_state(android::snapshot::UpdateState) override {}
+    void set_state(android::snapshot::UpdateState, bool) override {}
     void set_cow_file_size(uint64_t) override {}
     uint64_t cow_file_size() override { return 0; }
     std::unique_ptr<Result> Finish() override { return nullptr; }
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 95e7d89..d57aa6c 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1160,6 +1160,11 @@
 // Test that shrinking and growing partitions at the same time is handled
 // correctly in VABC.
 TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
+    if (!IsCompressionEnabled()) {
+        // b/179111359
+        GTEST_SKIP() << "Skipping Virtual A/B Compression test";
+    }
+
     // OTA client blindly unmaps all partitions that are possibly mapped.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
         ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
diff --git a/fs_mgr/libsnapshot/snapuserd.rc b/fs_mgr/libsnapshot/snapuserd.rc
index f2d21ac..4bf34a2 100644
--- a/fs_mgr/libsnapshot/snapuserd.rc
+++ b/fs_mgr/libsnapshot/snapuserd.rc
@@ -4,3 +4,4 @@
     disabled
     user root
     group root system
+    seclabel u:r:snapuserd:s0
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 4aa439a..1cadc9f 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -35,6 +35,8 @@
 #ifndef __ANDROID_VNDK__
 
 static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
+// Path to test against for freezer support
+static constexpr const char* CGROUP_FREEZE_PATH = "/sys/fs/cgroup/freezer/cgroup.freeze";
 
 bool UsePerAppMemcg();
 
diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json
index 792af6f..5b7a28a 100644
--- a/libprocessgroup/profiles/cgroups.json
+++ b/libprocessgroup/profiles/cgroups.json
@@ -42,7 +42,7 @@
     "Controllers": [
       {
         "Controller": "freezer",
-        "Path": ".",
+        "Path": "freezer",
         "Mode": "0755",
         "UID": "system",
         "GID": "system"
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 628098b..5b57bdd 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -46,7 +46,7 @@
       "File": "cpu.uclamp.latency_sensitive"
     },
     {
-      "Name": "Freezer",
+      "Name": "FreezerState",
       "Controller": "freezer",
       "File": "cgroup.freeze"
     }
@@ -70,11 +70,11 @@
       "Name": "Frozen",
       "Actions": [
         {
-          "Name": "SetAttribute",
+          "Name": "JoinCgroup",
           "Params":
           {
-            "Name": "Freezer",
-            "Value": "1"
+            "Controller": "freezer",
+            "Path": ""
           }
         }
       ]
@@ -83,11 +83,11 @@
       "Name": "Unfrozen",
       "Actions": [
         {
-          "Name": "SetAttribute",
+          "Name": "JoinCgroup",
           "Params":
           {
-            "Name": "Freezer",
-            "Value": "0"
+            "Controller": "freezer",
+            "Path": "../"
           }
         }
       ]