Add support for v2 of dm-default-key

Version 2 of dm-default-key has an extra parameter and always sets the
DUN.

Bug: 147814592
Test: Cuttlefish boots with keydirectory flag
Test: Crosshatch formatted before this change boots after it
Change-Id: I309bcc3f907a6df745f5c073b0017a7dd5b5354b
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index ea54029..d7b689e 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -243,15 +243,43 @@
     return android::base::Join(argv, " ");
 }
 
+const std::string DmTargetDefaultKey::name_ = "default-key";
+
+bool DmTargetDefaultKey::IsLegacy(bool* result) {
+    DeviceMapper& dm = DeviceMapper::Instance();
+    DmTargetTypeInfo info;
+    if (!dm.GetTargetByName(name_, &info)) return false;
+    // dm-default-key was modified to be like dm-crypt with version 2
+    *result = !info.IsAtLeast(2, 0, 0);
+    return true;
+}
+
+bool DmTargetDefaultKey::Valid() const {
+    bool real_is_legacy;
+    if (!DmTargetDefaultKey::IsLegacy(&real_is_legacy)) return false;
+    if (real_is_legacy != is_legacy_) return false;
+    if (!is_legacy_ && !set_dun_) return false;
+    return true;
+}
+
 std::string DmTargetDefaultKey::GetParameterString() const {
     std::vector<std::string> argv;
     argv.emplace_back(cipher_);
     argv.emplace_back(key_);
+    if (!is_legacy_) {
+        argv.emplace_back("0");  // iv_offset
+    }
     argv.emplace_back(blockdev_);
     argv.push_back(std::to_string(start_sector_));
     std::vector<std::string> extra_argv;
-    if (set_dun_) {
-        extra_argv.emplace_back("set_dun");
+    if (is_legacy_) {
+        if (set_dun_) {  // v2 always sets the DUN.
+            extra_argv.emplace_back("set_dun");
+        }
+    } else {
+        extra_argv.emplace_back("allow_discards");
+        extra_argv.emplace_back("sector_size:4096");
+        extra_argv.emplace_back("iv_large_sectors");
     }
     if (!extra_argv.empty()) {
         argv.emplace_back(std::to_string(extra_argv.size()));
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index b7f31bc..b296801 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -516,10 +516,25 @@
 }
 
 TEST(libdm, DefaultKeyArgs) {
-    DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0);
+    DmTargetTypeInfo info;
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+    if (!dm.GetTargetByName("default-key", &info)) {
+        cout << "default-key module not enabled; skipping test" << std::endl;
+        return;
+    }
+    bool is_legacy;
+    ASSERT_TRUE(DmTargetDefaultKey::IsLegacy(&is_legacy));
+    // set_dun only in the non-is_legacy case
+    DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0,
+                              is_legacy, !is_legacy);
     ASSERT_EQ(target.name(), "default-key");
     ASSERT_TRUE(target.Valid());
-    ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
+    if (is_legacy) {
+        ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
+    } else {
+        ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 0 /dev/loop0 0");
+    }
 }
 
 TEST(libdm, DeleteDeviceWithTimeout) {
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index a78bc71..e3dd92b 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -281,23 +281,27 @@
   public:
     DmTargetDefaultKey(uint64_t start, uint64_t length, const std::string& cipher,
                        const std::string& key, const std::string& blockdev, uint64_t start_sector,
-                       bool set_dun = false)
+                       bool is_legacy, bool set_dun)
         : DmTarget(start, length),
           cipher_(cipher),
           key_(key),
           blockdev_(blockdev),
           start_sector_(start_sector),
+          is_legacy_(is_legacy),
           set_dun_(set_dun) {}
 
-    std::string name() const override { return "default-key"; }
-    bool Valid() const override { return true; }
+    std::string name() const override { return name_; }
+    bool Valid() const override;
     std::string GetParameterString() const override;
+    static bool IsLegacy(bool* result);
 
   private:
+    static const std::string name_;
     std::string cipher_;
     std::string key_;
     std::string blockdev_;
     uint64_t start_sector_;
+    bool is_legacy_;
     bool set_dun_;
 };