Fix S and T mixed build OTA

When a device has vendor partitions in S and system partitions in T, ota
package will enable VABC XOR. But device's snapuserd actually doesn't
support XOR, because snapuserd is in vendor partition. Therefore, at
runtime, check if XOR is supported.

Test: th
Bug: 227614163

Change-Id: I4cb84aa9b69ff872f5de7a5e9c5ca1e3405d2d8b
diff --git a/aosp/dynamic_partition_control_android.cc b/aosp/dynamic_partition_control_android.cc
index e39e7bc..27d1d54 100644
--- a/aosp/dynamic_partition_control_android.cc
+++ b/aosp/dynamic_partition_control_android.cc
@@ -82,6 +82,8 @@
 constexpr char kVirtualAbRetrofit[] = "ro.virtual_ab.retrofit";
 constexpr char kVirtualAbCompressionEnabled[] =
     "ro.virtual_ab.compression.enabled";
+constexpr auto&& kVirtualAbCompressionXorEnabled =
+    "ro.virtual_ab.compression.xor.enabled";
 
 // Currently, android doesn't have a retrofit prop for VAB Compression. However,
 // struct FeatureFlag forces us to determine if a feature is 'retrofit'. So this
@@ -126,6 +128,8 @@
       virtual_ab_(GetFeatureFlag(kVirtualAbEnabled, kVirtualAbRetrofit)),
       virtual_ab_compression_(GetFeatureFlag(kVirtualAbCompressionEnabled,
                                              kVirtualAbCompressionRetrofit)),
+      virtual_ab_compression_xor_(
+          GetFeatureFlag(kVirtualAbCompressionXorEnabled, "")),
       source_slot_(source_slot) {
   if (GetVirtualAbFeatureFlag().IsEnabled()) {
     snapshot_ = SnapshotManager::New();
@@ -152,6 +156,11 @@
   return virtual_ab_compression_;
 }
 
+FeatureFlag
+DynamicPartitionControlAndroid::GetVirtualAbCompressionXorFeatureFlag() {
+  return virtual_ab_compression_xor_;
+}
+
 bool DynamicPartitionControlAndroid::OptimizeOperation(
     const std::string& partition_name,
     const InstallOperation& operation,
diff --git a/aosp/dynamic_partition_control_android.h b/aosp/dynamic_partition_control_android.h
index 457ef18..92761d2 100644
--- a/aosp/dynamic_partition_control_android.h
+++ b/aosp/dynamic_partition_control_android.h
@@ -44,6 +44,7 @@
   FeatureFlag GetDynamicPartitionsFeatureFlag() override;
   FeatureFlag GetVirtualAbFeatureFlag() override;
   FeatureFlag GetVirtualAbCompressionFeatureFlag() override;
+  FeatureFlag GetVirtualAbCompressionXorFeatureFlag() override;
   bool OptimizeOperation(const std::string& partition_name,
                          const InstallOperation& operation,
                          InstallOperation* optimized) override;
@@ -339,6 +340,7 @@
   const FeatureFlag dynamic_partitions_;
   const FeatureFlag virtual_ab_;
   const FeatureFlag virtual_ab_compression_;
+  const FeatureFlag virtual_ab_compression_xor_;
   std::unique_ptr<android::snapshot::ISnapshotManager> snapshot_;
   std::unique_ptr<android::snapshot::AutoDevice> metadata_device_;
   bool target_supports_snapshot_ = false;
diff --git a/aosp/mock_dynamic_partition_control_android.h b/aosp/mock_dynamic_partition_control_android.h
index 33ef39c..f55cdf7 100644
--- a/aosp/mock_dynamic_partition_control_android.h
+++ b/aosp/mock_dynamic_partition_control_android.h
@@ -73,6 +73,10 @@
   MOCK_METHOD(std::string, GetSuperPartitionName, (uint32_t), (override));
   MOCK_METHOD(FeatureFlag, GetVirtualAbFeatureFlag, (), (override));
   MOCK_METHOD(FeatureFlag, GetVirtualAbCompressionFeatureFlag, (), (override));
+  MOCK_METHOD(FeatureFlag,
+              GetVirtualAbCompressionXorFeatureFlag,
+              (),
+              (override));
   MOCK_METHOD(bool, FinishUpdate, (bool), (override));
   MOCK_METHOD(bool,
               GetSystemOtherPath,
diff --git a/common/dynamic_partition_control_interface.h b/common/dynamic_partition_control_interface.h
index e6ebe6a..2c01b1a 100644
--- a/common/dynamic_partition_control_interface.h
+++ b/common/dynamic_partition_control_interface.h
@@ -73,6 +73,8 @@
   // DOES NOT tell you if VABC is used for current OTA update. For that, use
   // UpdateUsesSnapshotCompression.
   virtual FeatureFlag GetVirtualAbCompressionFeatureFlag() = 0;
+  // Return the feature flag for Virtual AB Compression XOR
+  virtual FeatureFlag GetVirtualAbCompressionXorFeatureFlag() = 0;
 
   // Attempt to optimize |operation|.
   // If successful, |optimized| contains an operation with extents that
diff --git a/common/dynamic_partition_control_stub.cc b/common/dynamic_partition_control_stub.cc
index dd30a8b..6283b1d 100644
--- a/common/dynamic_partition_control_stub.cc
+++ b/common/dynamic_partition_control_stub.cc
@@ -38,6 +38,10 @@
   return FeatureFlag(FeatureFlag::Value::NONE);
 }
 
+FeatureFlag DynamicPartitionControlStub::GetVirtualAbCompressionXorFeatureFlag() {
+  return FeatureFlag(FeatureFlag::Value::NONE);
+}
+
 bool DynamicPartitionControlStub::OptimizeOperation(
     const std::string& partition_name,
     const InstallOperation& operation,
diff --git a/common/dynamic_partition_control_stub.h b/common/dynamic_partition_control_stub.h
index 5aa4336..15137d2 100644
--- a/common/dynamic_partition_control_stub.h
+++ b/common/dynamic_partition_control_stub.h
@@ -27,11 +27,12 @@
 
 namespace chromeos_update_engine {
 
-class DynamicPartitionControlStub : public DynamicPartitionControlInterface {
+class DynamicPartitionControlStub final : public DynamicPartitionControlInterface {
  public:
   FeatureFlag GetDynamicPartitionsFeatureFlag() override;
   FeatureFlag GetVirtualAbFeatureFlag() override;
   FeatureFlag GetVirtualAbCompressionFeatureFlag() override;
+  FeatureFlag GetVirtualAbCompressionXorFeatureFlag() override;
   bool OptimizeOperation(const std::string& partition_name,
                          const InstallOperation& operation,
                          InstallOperation* optimized) override;
diff --git a/common/mock_dynamic_partition_control.h b/common/mock_dynamic_partition_control.h
index f3a446a..fd0a5a9 100644
--- a/common/mock_dynamic_partition_control.h
+++ b/common/mock_dynamic_partition_control.h
@@ -34,6 +34,10 @@
   MOCK_METHOD(bool, GetDeviceDir, (std::string*), (override));
   MOCK_METHOD(FeatureFlag, GetDynamicPartitionsFeatureFlag, (), (override));
   MOCK_METHOD(FeatureFlag, GetVirtualAbCompressionFeatureFlag, (), (override));
+  MOCK_METHOD(FeatureFlag,
+              GetVirtualAbCompressionXorFeatureFlag,
+              (),
+              (override));
   MOCK_METHOD(FeatureFlag, GetVirtualAbFeatureFlag, (), (override));
   MOCK_METHOD(bool, FinishUpdate, (bool), (override));
   MOCK_METHOD(std::unique_ptr<FileDescriptor>,
diff --git a/payload_consumer/vabc_partition_writer.cc b/payload_consumer/vabc_partition_writer.cc
index 54aea86..8ae0b51 100644
--- a/payload_consumer/vabc_partition_writer.cc
+++ b/payload_consumer/vabc_partition_writer.cc
@@ -97,7 +97,17 @@
 bool VABCPartitionWriter::Init(const InstallPlan* install_plan,
                                bool source_may_exist,
                                size_t next_op_index) {
-  xor_map_ = ComputeXorMap(partition_update_.merge_operations());
+  if (dynamic_control_->GetVirtualAbCompressionXorFeatureFlag().IsEnabled()) {
+    xor_map_ = ComputeXorMap(partition_update_.merge_operations());
+    if (xor_map_.size() > 0) {
+      LOG(INFO) << "Virtual AB Compression with XOR is enabled";
+    } else {
+      LOG(INFO) << "Device supports Virtual AB compression with XOR, but OTA "
+                   "package does not.";
+    }
+  } else {
+    LOG(INFO) << "Virtual AB Compression with XOR is disabled.";
+  }
   TEST_AND_RETURN_FALSE(install_plan != nullptr);
   if (source_may_exist && install_part_.source_size > 0) {
     TEST_AND_RETURN_FALSE(!install_part_.source_path.empty());
diff --git a/payload_consumer/vabc_partition_writer_unittest.cc b/payload_consumer/vabc_partition_writer_unittest.cc
index f331091..20aa75f 100644
--- a/payload_consumer/vabc_partition_writer_unittest.cc
+++ b/payload_consumer/vabc_partition_writer_unittest.cc
@@ -48,7 +48,11 @@
 static constexpr size_t FAKE_PART_SIZE = 4096 * 50;
 class VABCPartitionWriterTest : public ::testing::Test {
  public:
-  void SetUp() override { ftruncate(source_part_.fd, FAKE_PART_SIZE); }
+  void SetUp() override {
+    ftruncate(source_part_.fd, FAKE_PART_SIZE);
+    ON_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+        .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
+  }
 
  protected:
   CowMergeOperation* AddMergeOp(PartitionUpdate* partition,
@@ -102,6 +106,8 @@
         ON_CALL(*cow_writer, EmitLabel(_)).WillByDefault(Return(true));
         return cow_writer;
       }));
+  EXPECT_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+      .WillRepeatedly(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
   ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
 }
 
@@ -125,6 +131,8 @@
             ON_CALL(*cow_writer, EmitLabel(_)).WillByDefault(Return(true));
             return cow_writer;
           }));
+  EXPECT_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+      .WillRepeatedly(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
   ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
 }
 
@@ -224,10 +232,12 @@
             .WillOnce(Return(true));
         return cow_writer;
       }));
+  EXPECT_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+      .WillRepeatedly(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
   VABCPartitionWriter writer_{
       partition_update_, install_part_, &dynamic_control_, kBlockSize};
   ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
-  auto patch_data = GetNoopBSDIFF(kBlockSize * 5);
+  const auto patch_data = GetNoopBSDIFF(kBlockSize * 5);
   ASSERT_GT(patch_data.size(), 0UL);
   ASSERT_TRUE(writer_.PerformDiffOperation(
       *install_op, nullptr, patch_data.data(), patch_data.size()));