[REFACTOR] DynamicPartitionControl: combine DAP feature flag APIs

Combine IsDynamicPartitionsEnabled/Retrofit into one API that
returns a FeatureFlag struct instead.

This allows us to add new feature flags more easily.

Test: unittest
Change-Id: I32f0f0c4d5c636d2eac3bf99d6f92fcc6b71c7a9
diff --git a/boot_control_android.cc b/boot_control_android.cc
index b820ded..44fc0fa 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -193,7 +193,7 @@
   // current payload doesn't encode them as dynamic partitions. This may happen
   // when applying a retrofit update on top of a dynamic-partitions-enabled
   // build.
-  if (dynamic_control_->IsDynamicPartitionsEnabled() &&
+  if (dynamic_control_->GetDynamicPartitionsFeatureFlag().IsEnabled() &&
       (slot == GetCurrentSlot() || is_target_dynamic_)) {
     switch (GetDynamicPartitionDevice(
         device_dir, partition_name_suffix, slot, device)) {
@@ -288,7 +288,7 @@
            "resources.\n"
         << "run adb enable-verity to deactivate if required and try again.";
   }
-  if (!dynamic_control_->IsDynamicPartitionsEnabled()) {
+  if (!dynamic_control_->GetDynamicPartitionsFeatureFlag().IsEnabled()) {
     return true;
   }
 
diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc
index dfcb6fb..3e0320d 100644
--- a/boot_control_android_unittest.cc
+++ b/boot_control_android_unittest.cc
@@ -274,10 +274,8 @@
           return Void();
         }));
 
-    ON_CALL(dynamicControl(), IsDynamicPartitionsEnabled())
-        .WillByDefault(Return(true));
-    ON_CALL(dynamicControl(), IsDynamicPartitionsRetrofit())
-        .WillByDefault(Return(false));
+    ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
+        .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
     ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true));
     ON_CALL(dynamicControl(), GetDeviceDir(_))
         .WillByDefault(Invoke([](auto path) {
diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc
index 5a172b0..329ddd3 100644
--- a/dynamic_partition_control_android.cc
+++ b/dynamic_partition_control_android.cc
@@ -58,12 +58,26 @@
   CleanupInternal(false /* wait */);
 }
 
-bool DynamicPartitionControlAndroid::IsDynamicPartitionsEnabled() {
-  return GetBoolProperty(kUseDynamicPartitions, false);
+static FeatureFlag GetFeatureFlag(const char* enable_prop,
+                                  const char* retrofit_prop) {
+  bool retrofit = GetBoolProperty(retrofit_prop, false);
+  bool enabled = GetBoolProperty(enable_prop, false);
+  if (retrofit && !enabled) {
+    LOG(ERROR) << retrofit_prop << " is true but " << enable_prop
+               << " is not. These sysprops are inconsistent. Assume that "
+               << enable_prop << " is true from now on.";
+  }
+  if (retrofit) {
+    return FeatureFlag(FeatureFlag::Value::RETROFIT);
+  }
+  if (enabled) {
+    return FeatureFlag(FeatureFlag::Value::LAUNCH);
+  }
+  return FeatureFlag(FeatureFlag::Value::NONE);
 }
 
-bool DynamicPartitionControlAndroid::IsDynamicPartitionsRetrofit() {
-  return GetBoolProperty(kRetrfoitDynamicPartitions, false);
+FeatureFlag DynamicPartitionControlAndroid::GetDynamicPartitionsFeatureFlag() {
+  return GetFeatureFlag(kUseDynamicPartitions, kRetrfoitDynamicPartitions);
 }
 
 bool DynamicPartitionControlAndroid::MapPartitionInternal(
@@ -217,7 +231,7 @@
     return false;
   }
 
-  if (IsDynamicPartitionsRetrofit()) {
+  if (GetDynamicPartitionsFeatureFlag().IsRetrofit()) {
     if (!FlashPartitionTable(super_device, *metadata)) {
       LOG(ERROR) << "Cannot write metadata to " << super_device;
       return false;
@@ -328,7 +342,7 @@
 
   std::string expr;
   uint64_t allocatable_space = builder->AllocatableSpace();
-  if (!IsDynamicPartitionsRetrofit()) {
+  if (!GetDynamicPartitionsFeatureFlag().IsRetrofit()) {
     allocatable_space /= 2;
     expr = "half of ";
   }
diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h
index e0859ed..73d7539 100644
--- a/dynamic_partition_control_android.h
+++ b/dynamic_partition_control_android.h
@@ -29,8 +29,7 @@
  public:
   DynamicPartitionControlAndroid() = default;
   ~DynamicPartitionControlAndroid();
-  bool IsDynamicPartitionsEnabled() override;
-  bool IsDynamicPartitionsRetrofit() override;
+  FeatureFlag GetDynamicPartitionsFeatureFlag() override;
   bool MapPartitionOnDeviceMapper(const std::string& super_device,
                                   const std::string& target_partition_name,
                                   uint32_t slot,
diff --git a/dynamic_partition_control_interface.h b/dynamic_partition_control_interface.h
index 12e62e0..32fbbe4 100644
--- a/dynamic_partition_control_interface.h
+++ b/dynamic_partition_control_interface.h
@@ -30,15 +30,25 @@
 
 namespace chromeos_update_engine {
 
+struct FeatureFlag {
+  enum class Value { NONE = 0, RETROFIT, LAUNCH };
+  constexpr explicit FeatureFlag(Value value) : value_(value) {}
+  constexpr bool IsEnabled() const { return value_ != Value::NONE; }
+  constexpr bool IsRetrofit() const { return value_ == Value::RETROFIT; }
+
+ private:
+  Value value_;
+};
+
 class DynamicPartitionControlInterface {
  public:
   virtual ~DynamicPartitionControlInterface() = default;
 
-  // Return true iff dynamic partitions is enabled on this device.
-  virtual bool IsDynamicPartitionsEnabled() = 0;
-
-  // Return true iff dynamic partitions is retrofitted on this device.
-  virtual bool IsDynamicPartitionsRetrofit() = 0;
+  // Return the feature flags of dynamic partitions on this device.
+  // Return RETROFIT iff dynamic partitions is retrofitted on this device,
+  //        LAUNCH iff this device is launched with dynamic partitions,
+  //        NONE iff dynamic partitions is disabled on this device.
+  virtual FeatureFlag GetDynamicPartitionsFeatureFlag() = 0;
 
   // Map logical partition on device-mapper.
   // |super_device| is the device path of the physical partition ("super").
diff --git a/mock_dynamic_partition_control.h b/mock_dynamic_partition_control.h
index 310e528..a0701e7 100644
--- a/mock_dynamic_partition_control.h
+++ b/mock_dynamic_partition_control.h
@@ -49,8 +49,7 @@
                     android::fs_mgr::MetadataBuilder*,
                     uint32_t));
   MOCK_METHOD1(GetDeviceDir, bool(std::string*));
-  MOCK_METHOD0(IsDynamicPartitionsEnabled, bool());
-  MOCK_METHOD0(IsDynamicPartitionsRetrofit, bool());
+  MOCK_METHOD0(GetDynamicPartitionsFeatureFlag, FeatureFlag());
 };
 
 }  // namespace chromeos_update_engine