Revert^2 "Remove minor version from sepolicy version"

85d84f01c78748c9f9ceafa0ce03695d699ce0df

Change-Id: I67ad9363bdd2cbe3527eab930ca55544cf17af16
diff --git a/AssembleVintf.cpp b/AssembleVintf.cpp
index 7bca24c..9a35ca7 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -757,14 +757,14 @@
             }
 
             // Add PLATFORM_SEPOLICY_* to sepolicy.sepolicy-version. Remove dupes.
-            std::set<Version> sepolicyVersions;
+            std::set<SepolicyVersion> sepolicyVersions;
             auto sepolicyVersionStrings = getEnvList("PLATFORM_SEPOLICY_COMPAT_VERSIONS");
             auto currentSepolicyVersionString = getEnv("PLATFORM_SEPOLICY_VERSION");
             if (!currentSepolicyVersionString.empty()) {
                 sepolicyVersionStrings.push_back(currentSepolicyVersionString);
             }
             for (auto&& s : sepolicyVersionStrings) {
-                Version v;
+                SepolicyVersion v;
                 if (!parse(s, &v)) {
                     err() << "Error: unknown sepolicy version '" << s << "' specified by "
                           << (s == currentSepolicyVersionString
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index eebb2e2..b6c8e45 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -462,7 +462,7 @@
     return found;
 }
 
-std::vector<VersionRange> CompatibilityMatrix::getSepolicyVersions() const {
+std::vector<SepolicyVersionRange> CompatibilityMatrix::getSepolicyVersions() const {
     if (type() == SchemaType::FRAMEWORK) return framework.mSepolicy.sepolicyVersions();
     return {};
 }
diff --git a/HalManifest.cpp b/HalManifest.cpp
index 0d4b829..61d2c32 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -581,7 +581,7 @@
     return mLevel;
 }
 
-const Version &HalManifest::sepolicyVersion() const {
+const SepolicyVersion& HalManifest::sepolicyVersion() const {
     CHECK(mType == SchemaType::DEVICE);
     return device.mSepolicyVersion;
 }
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index ee72d18..bb776ec 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -68,7 +68,7 @@
 
     std::string getVendorNdkVersion() const;
 
-    std::vector<VersionRange> getSepolicyVersions() const;
+    std::vector<SepolicyVersionRange> getSepolicyVersions() const;
 
     bool add(MatrixHal&&, std::string* error = nullptr);
     // Move all hals from another CompatibilityMatrix to this.
diff --git a/include/vintf/HalManifest.h b/include/vintf/HalManifest.h
index 0230834..3413359 100644
--- a/include/vintf/HalManifest.h
+++ b/include/vintf/HalManifest.h
@@ -111,7 +111,7 @@
 
     // device.mSepolicyVersion. Assume type == device.
     // Abort if type != device.
-    const Version &sepolicyVersion() const;
+    const SepolicyVersion& sepolicyVersion() const;
 
     // framework.mVendorNdks. Assume type == framework.
     // Abort if type != framework.
@@ -249,7 +249,7 @@
 
     // entries for device hal manifest only
     struct {
-        Version mSepolicyVersion;
+        SepolicyVersion mSepolicyVersion;
         std::optional<KernelInfo> mKernel;
     } device;
 
diff --git a/include/vintf/Sepolicy.h b/include/vintf/Sepolicy.h
index 09b9c97..fbfca8c 100644
--- a/include/vintf/Sepolicy.h
+++ b/include/vintf/Sepolicy.h
@@ -35,12 +35,12 @@
 
     Sepolicy() : Sepolicy(0u, {}) {}
     Sepolicy(KernelSepolicyVersion kernelSepolicyVersion,
-            std::vector<VersionRange> &&sepolicyVersions) :
-            mKernelSepolicyVersion(kernelSepolicyVersion),
-            mSepolicyVersionRanges(std::move(sepolicyVersions)) {}
+             std::vector<SepolicyVersionRange>&& sepolicyVersions)
+        : mKernelSepolicyVersion(kernelSepolicyVersion),
+          mSepolicyVersionRanges(std::move(sepolicyVersions)) {}
 
     inline size_t kernelSepolicyVersion() const { return mKernelSepolicyVersion.value; }
-    inline const std::vector<VersionRange> &sepolicyVersions() const {
+    inline const std::vector<SepolicyVersionRange>& sepolicyVersions() const {
         return mSepolicyVersionRanges;
     }
 
@@ -48,7 +48,7 @@
     friend class AssembleVintfImpl;
     friend struct SepolicyConverter;
     KernelSepolicyVersion mKernelSepolicyVersion;
-    std::vector<VersionRange> mSepolicyVersionRanges;
+    std::vector<SepolicyVersionRange> mSepolicyVersionRanges;
 };
 
 inline bool operator==(const Sepolicy &lft, const Sepolicy &rgt) {
diff --git a/include/vintf/Version.h b/include/vintf/Version.h
index 15c1089..456546b 100644
--- a/include/vintf/Version.h
+++ b/include/vintf/Version.h
@@ -19,6 +19,7 @@
 #define ANDROID_VINTF_VERSION_H
 
 #include <stdint.h>
+#include <optional>
 #include <string>
 #include <utility>
 
@@ -68,6 +69,23 @@
     inline Version withMinor(size_t mi) { return Version(majorVer, mi); }
 };
 
+struct SepolicyVersion {
+    constexpr SepolicyVersion() : SepolicyVersion(0u, std::nullopt) {}
+    constexpr SepolicyVersion(size_t mj, std::optional<size_t> mi) : majorVer(mj), minorVer(mi) {}
+
+    size_t majorVer;
+    std::optional<size_t> minorVer;
+
+    bool operator==(const SepolicyVersion& other) const = default;
+    bool operator!=(const SepolicyVersion& other) const = default;
+    inline bool operator<(const SepolicyVersion& other) const {
+        return std::pair(majorVer, minorVer) < std::pair(other.majorVer, other.minorVer);
+    }
+    inline bool operator>(const SepolicyVersion& other) const { return other < *this; }
+    inline bool operator<=(const SepolicyVersion& other) const { return !((*this) > other); }
+    inline bool operator>=(const SepolicyVersion& other) const { return !((*this) < other); }
+};
+
 struct KernelVersion {
 
     constexpr KernelVersion() : KernelVersion(0u, 0u, 0u) {}
diff --git a/include/vintf/VersionRange.h b/include/vintf/VersionRange.h
index a17eaf6..d5c7c56 100644
--- a/include/vintf/VersionRange.h
+++ b/include/vintf/VersionRange.h
@@ -19,6 +19,7 @@
 #define ANDROID_VINTF_VERSION_RANGE_H
 
 #include <stdint.h>
+#include <optional>
 #include <string>
 #include <tuple>
 #include <utility>
@@ -73,6 +74,33 @@
     size_t maxMinor;
 };
 
+struct SepolicyVersionRange {
+    size_t majorVer;
+    std::optional<size_t> minMinor;
+    std::optional<size_t> maxMinor;
+
+    constexpr SepolicyVersionRange() : SepolicyVersionRange(0u, std::nullopt, std::nullopt) {}
+    constexpr SepolicyVersionRange(size_t mjV, std::optional<size_t> miV)
+        : SepolicyVersionRange(mjV, miV, miV) {}
+    constexpr SepolicyVersionRange(size_t mjV, std::optional<size_t> miM, std::optional<size_t> mxM)
+        : majorVer(mjV), minMinor(miM), maxMinor(mxM) {}
+    constexpr inline SepolicyVersion minVer() const { return SepolicyVersion(majorVer, minMinor); }
+    constexpr inline SepolicyVersion maxVer() const { return SepolicyVersion(majorVer, maxMinor); }
+    inline bool isSingleVersion() const { return minMinor == maxMinor; }
+
+    bool operator==(const SepolicyVersionRange& other) const = default;
+    bool operator!=(const SepolicyVersionRange& other) const = default;
+
+    // If this == 2.3-7,
+    //     ver == 2.2: false
+    //     ver == 2.3: true
+    //     ver == 2.7: true
+    //     ver == 2.8: true
+    inline bool supportedBy(const SepolicyVersion& ver) const {
+        return majorVer == ver.majorVer && minMinor <= ver.minorVer;
+    }
+};
+
 } // namespace vintf
 } // namespace android
 
diff --git a/include/vintf/parse_string.h b/include/vintf/parse_string.h
index 677759e..52defff 100644
--- a/include/vintf/parse_string.h
+++ b/include/vintf/parse_string.h
@@ -40,6 +40,8 @@
 std::ostream& operator<<(std::ostream& os, KernelSepolicyVersion v);
 std::ostream &operator<<(std::ostream &os, const Version &ver);
 std::ostream &operator<<(std::ostream &os, const VersionRange &vr);
+std::ostream& operator<<(std::ostream& os, const SepolicyVersion& ver);
+std::ostream& operator<<(std::ostream& os, const SepolicyVersionRange& vr);
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -71,6 +73,8 @@
 bool parse(const std::string &s, KernelSepolicyVersion *ksv);
 bool parse(const std::string &s, Version *ver);
 bool parse(const std::string &s, VersionRange *vr);
+bool parse(const std::string& s, SepolicyVersion* ver);
+bool parse(const std::string& s, SepolicyVersionRange* ver);
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
diff --git a/parse_string.cpp b/parse_string.cpp
index 1e79284..caf58d9 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -236,10 +236,30 @@
     return true;
 }
 
+bool parse(const std::string& s, SepolicyVersion* sepolicyVer) {
+    size_t major;
+    // vFRC versioning
+    if (ParseUint(s, &major)) {
+        *sepolicyVer = SepolicyVersion(major, std::nullopt);
+        return true;
+    }
+    // fall back to normal Version
+    Version ver;
+    if (!parse(s, &ver)) return false;
+    *sepolicyVer = SepolicyVersion(ver.majorVer, ver.minorVer);
+    return true;
+}
+
 std::ostream &operator<<(std::ostream &os, const Version &ver) {
     return os << ver.majorVer << "." << ver.minorVer;
 }
 
+std::ostream& operator<<(std::ostream& os, const SepolicyVersion& ver) {
+    os << ver.majorVer;
+    if (ver.minorVer.has_value()) os << "." << ver.minorVer.value();
+    return os;
+}
+
 // Helper for parsing a VersionRange object. versionParser defines how the first half
 // (before the '-' character) of the string is parsed.
 static bool parseVersionRange(
@@ -270,6 +290,22 @@
     return parseVersionRange(s, vr, versionParser);
 }
 
+// TODO(b/314010177): Add unit tests for this function.
+bool parse(const std::string& s, SepolicyVersionRange* svr) {
+    SepolicyVersion sepolicyVersion;
+    if (parse(s, &sepolicyVersion)) {
+        *svr = SepolicyVersionRange(sepolicyVersion.majorVer, sepolicyVersion.minorVer);
+        return true;
+    }
+    // fall back to normal VersionRange
+    VersionRange vr;
+    if (parse(s, &vr)) {
+        *svr = SepolicyVersionRange(vr.majorVer, vr.minMinor, vr.maxMinor);
+        return true;
+    }
+    return false;
+}
+
 std::ostream &operator<<(std::ostream &os, const VersionRange &vr) {
     if (vr.isSingleVersion()) {
         return os << vr.minVer();
@@ -277,6 +313,14 @@
     return os << vr.minVer() << "-" << vr.maxMinor;
 }
 
+std::ostream& operator<<(std::ostream& os, const SepolicyVersionRange& svr) {
+    if (svr.maxMinor.has_value()) {
+        return os << VersionRange(svr.majorVer, svr.minMinor.value_or(0), svr.maxMinor.value());
+    }
+
+    return os << SepolicyVersion(svr.majorVer, svr.minMinor);
+}
+
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 bool parse(const std::string &s, VndkVersionRange *vr) {
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 12d8569..f5410e7 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -483,10 +483,18 @@
     std::string elementName() const override { return "version"; }
 };
 
+struct SepolicyVersionConverter : public XmlTextConverter<SepolicyVersion> {
+    std::string elementName() const override { return "version"; }
+};
+
 struct VersionRangeConverter : public XmlTextConverter<VersionRange> {
     std::string elementName() const override { return "version"; }
 };
 
+struct SepolicyVersionRangeConverter : public XmlTextConverter<SepolicyVersionRange> {
+    std::string elementName() const override { return "sepolicy-version"; }
+};
+
 // <version>100</version> <=> Version{kFakeAidlMajorVersion, 100}
 struct AidlVersionConverter : public XmlNodeConverter<Version> {
     std::string elementName() const override { return "version"; }
@@ -1077,22 +1085,18 @@
     std::string elementName() const override { return "kernel-sepolicy-version"; }
 };
 
-struct SepolicyVersionConverter : public XmlTextConverter<VersionRange> {
-    std::string elementName() const override { return "sepolicy-version"; }
-};
-
 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
     std::string elementName() const override { return "sepolicy"; }
     void mutateNode(const Sepolicy& object, NodeType* root,
                     const MutateNodeParam& param) const override {
         appendChild(root, KernelSepolicyVersionConverter{}(object.kernelSepolicyVersion(), param));
-        appendChildren(root, SepolicyVersionConverter{}, object.sepolicyVersions(), param);
+        appendChildren(root, SepolicyVersionRangeConverter{}, object.sepolicyVersions(), param);
     }
     bool buildObject(Sepolicy* object, NodeType* root,
                      const BuildObjectParam& param) const override {
         if (!parseChild(root, KernelSepolicyVersionConverter{}, &object->mKernelSepolicyVersion,
                         param) ||
-            !parseChildren(root, SepolicyVersionConverter{}, &object->mSepolicyVersionRanges,
+            !parseChildren(root, SepolicyVersionRangeConverter{}, &object->mSepolicyVersionRanges,
                            param)) {
             return false;
         }
@@ -1161,15 +1165,15 @@
     }
 };
 
-struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
+struct HalManifestSepolicyConverter : public XmlNodeConverter<SepolicyVersion> {
     std::string elementName() const override { return "sepolicy"; }
-    void mutateNode(const Version& object, NodeType* root,
+    void mutateNode(const SepolicyVersion& object, NodeType* root,
                     const MutateNodeParam& param) const override {
-        appendChild(root, VersionConverter{}(object, param));
+        appendChild(root, SepolicyVersionConverter{}(object, param));
     }
-    bool buildObject(Version* object, NodeType* root,
+    bool buildObject(SepolicyVersion* object, NodeType* root,
                      const BuildObjectParam& param) const override {
-        return parseChild(root, VersionConverter{}, object, param);
+        return parseChild(root, SepolicyVersionConverter{}, object, param);
     }
 };
 
@@ -1249,7 +1253,7 @@
         }
         if (object.mType == SchemaType::DEVICE) {
             if (param.flags.isSepolicyEnabled()) {
-                if (object.device.mSepolicyVersion != Version{}) {
+                if (object.device.mSepolicyVersion != SepolicyVersion{}) {
                     appendChild(root, HalManifestSepolicyConverter{}(object.device.mSepolicyVersion,
                                                                      param));
                 }
@@ -1591,6 +1595,7 @@
 
 // Create convert functions for testing.
 CREATE_CONVERT_FN(Version)
+CREATE_CONVERT_FN(SepolicyVersion)
 CREATE_CONVERT_FN(KernelConfigTypedValue)
 CREATE_CONVERT_FN(MatrixHal)
 CREATE_CONVERT_FN(ManifestHal)
diff --git a/parse_xml_for_test.h b/parse_xml_for_test.h
index f22c0c4..64f39e2 100644
--- a/parse_xml_for_test.h
+++ b/parse_xml_for_test.h
@@ -21,12 +21,16 @@
 namespace android::vintf {
 
 std::string toXml(const Version& o, SerializeFlags::Type flags = SerializeFlags::EVERYTHING);
+std::string toXml(const SepolicyVersion& o,
+                  SerializeFlags::Type flags = SerializeFlags::EVERYTHING);
 std::string toXml(const KernelConfigTypedValue& o,
                   SerializeFlags::Type flags = SerializeFlags::EVERYTHING);
 std::string toXml(const ManifestHal& o, SerializeFlags::Type flags = SerializeFlags::EVERYTHING);
 std::string toXml(const MatrixHal& o, SerializeFlags::Type flags = SerializeFlags::EVERYTHING);
 
 [[nodiscard]] bool fromXml(Version* o, const std::string& xml, std::string* error = nullptr);
+[[nodiscard]] bool fromXml(SepolicyVersion* o, const std::string& xml,
+                           std::string* error = nullptr);
 [[nodiscard]] bool fromXml(KernelConfigTypedValue* o, const std::string& xml,
                            std::string* error = nullptr);
 [[nodiscard]] bool fromXml(MatrixHal* o, const std::string& xml, std::string* error = nullptr);
diff --git a/test/AssembleVintfTest.cpp b/test/AssembleVintfTest.cpp
index 4759f34..f243cf9 100644
--- a/test/AssembleVintfTest.cpp
+++ b/test/AssembleVintfTest.cpp
@@ -96,7 +96,7 @@
     addInput("compatibility_matrix.empty.xml", xmlEmpty);
     setFakeEnvs({
         {"POLICYVERS", "30"},
-        {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
+        {"PLATFORM_SEPOLICY_VERSION", "202404"},
         {"FRAMEWORK_VBMETA_VERSION", "1.0"},
     });
     getInstance()->addKernelConfigInputStream({3, 18, 0}, "android-base.config",
@@ -149,7 +149,7 @@
         "    </kernel>\n"
         "    <sepolicy>\n"
         "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
-        "        <sepolicy-version>10000.0</sepolicy-version>\n"
+        "        <sepolicy-version>202404</sepolicy-version>\n"
         "    </sepolicy>\n"
         "    <avb>\n"
         "        <vbmeta-version>1.0</vbmeta-version>\n"
@@ -167,7 +167,7 @@
         "    </kernel>\n"
         "    <sepolicy>\n"
         "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
-        "        <sepolicy-version>10000.0</sepolicy-version>\n"
+        "        <sepolicy-version>202404</sepolicy-version>\n"
         "    </sepolicy>\n"
         "    <avb>\n"
         "        <vbmeta-version>1.0</vbmeta-version>\n"
@@ -239,7 +239,7 @@
                "        </interface>\n"
                "    </hal>\n"
                "    <sepolicy>\n"
-               "        <version>10000.0</version>\n"
+               "        <version>202404</version>\n"
                "    </sepolicy>\n"
                "</manifest>\n";
     };
@@ -406,13 +406,13 @@
 const std::string gEmptyOutManifest =
     "<manifest " + kMetaVersionStr + " type=\"device\">\n"
     "    <sepolicy>\n"
-    "        <version>10000.0</version>\n"
+    "        <version>202404</version>\n"
     "    </sepolicy>\n"
     "</manifest>\n";
 
 TEST_F(AssembleVintfTest, EmptyManifest) {
     const std::string emptyManifest = "<manifest " + kMetaVersionStr + " type=\"device\" />";
-    setFakeEnvs({{"BOARD_SEPOLICY_VERS", "10000.0"}, {"IGNORE_TARGET_FCM_VERSION", "true"}});
+    setFakeEnvs({{"BOARD_SEPOLICY_VERS", "202404"}, {"IGNORE_TARGET_FCM_VERSION", "true"}});
     addInput("manifest.empty.xml", emptyManifest);
     EXPECT_TRUE(getInstance()->assemble());
     EXPECT_IN(gEmptyOutManifest, getOutput());
@@ -420,7 +420,7 @@
 
 TEST_F(AssembleVintfTest, DeviceFrameworkMatrixOptional) {
     setFakeEnvs({{"POLICYVERS", "30"},
-                 {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
+                 {"PLATFORM_SEPOLICY_VERSION", "202404"},
                  {"PLATFORM_SEPOLICY_COMPAT_VERSIONS", "26.0 27.0"},
                  {"FRAMEWORK_VBMETA_VERSION", "1.0"},
                  {"PRODUCT_ENFORCE_VINTF_MANIFEST", "true"}});
@@ -453,7 +453,7 @@
         "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
         "        <sepolicy-version>26.0</sepolicy-version>\n"
         "        <sepolicy-version>27.0</sepolicy-version>\n"
-        "        <sepolicy-version>10000.0</sepolicy-version>\n"
+        "        <sepolicy-version>202404</sepolicy-version>\n"
         "    </sepolicy>\n"
         "    <avb>\n"
         "        <vbmeta-version>1.0</vbmeta-version>\n"
@@ -464,7 +464,7 @@
 
 TEST_F(AssembleVintfTest, DeviceFrameworkMatrixRequired) {
     setFakeEnvs({{"POLICYVERS", "30"},
-                 {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
+                 {"PLATFORM_SEPOLICY_VERSION", "202404"},
                  {"PLATFORM_SEPOLICY_COMPAT_VERSIONS", "26.0 27.0"},
                  {"FRAMEWORK_VBMETA_VERSION", "1.0"},
                  {"PRODUCT_ENFORCE_VINTF_MANIFEST", "true"}});
@@ -487,7 +487,7 @@
 
 TEST_F(AssembleVintfTest, DeviceFrameworkMatrixMultiple) {
     setFakeEnvs({{"POLICYVERS", "30"},
-                 {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
+                 {"PLATFORM_SEPOLICY_VERSION", "202404"},
                  {"PLATFORM_SEPOLICY_COMPAT_VERSIONS", "26.0 27.0"},
                  {"FRAMEWORK_VBMETA_VERSION", "1.0"},
                  {"PRODUCT_ENFORCE_VINTF_MANIFEST", "true"}});
@@ -540,7 +540,7 @@
         "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
         "        <sepolicy-version>26.0</sepolicy-version>\n"
         "        <sepolicy-version>27.0</sepolicy-version>\n"
-        "        <sepolicy-version>10000.0</sepolicy-version>\n"
+        "        <sepolicy-version>202404</sepolicy-version>\n"
         "    </sepolicy>\n"
         "    <avb>\n"
         "        <vbmeta-version>1.0</vbmeta-version>\n"
@@ -656,7 +656,7 @@
 
 TEST_F(AssembleVintfTest, WithKernelRequirements) {
     setFakeEnvs({{"POLICYVERS", "30"},
-                 {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
+                 {"PLATFORM_SEPOLICY_VERSION", "202404"},
                  {"PRODUCT_ENFORCE_VINTF_MANIFEST", "true"}});
     addInput("compatibility_matrix.xml",
         "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"1\">\n"
@@ -671,7 +671,7 @@
         "<manifest " + kMetaVersionStr + " type=\"device\" target-level=\"1\">\n"
         "    <kernel target-level=\"1\" version=\"3.18.0\"/>\n"
         "    <sepolicy>\n"
-        "        <version>10000.0</version>\n"
+        "        <version>202404</version>\n"
         "    </sepolicy>\n"
         "</manifest>\n"));
 
@@ -680,7 +680,7 @@
 
 TEST_F(AssembleVintfTest, NoKernelRequirements) {
     setFakeEnvs({{"POLICYVERS", "30"},
-                 {"PLATFORM_SEPOLICY_VERSION", "10000.0"},
+                 {"PLATFORM_SEPOLICY_VERSION", "202404"},
                  {"PRODUCT_ENFORCE_VINTF_MANIFEST", "true"}});
     addInput("compatibility_matrix.xml",
         "<compatibility-matrix " + kMetaVersionStr + " type=\"framework\" level=\"1\">\n"
@@ -690,7 +690,7 @@
         "<manifest " + kMetaVersionStr + " type=\"device\" target-level=\"1\">\n"
         "    <kernel target-level=\"1\"/>\n"
         "    <sepolicy>\n"
-        "        <version>10000.0</version>\n"
+        "        <version>202404</version>\n"
         "    </sepolicy>\n"
         "</manifest>\n"));
 
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index cea7bfb..7576dbc 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -155,10 +155,10 @@
         return ret;
     }
 
-    HalManifest testDeviceManifest() {
+    HalManifest testDeviceManifestWithSepolicy(SepolicyVersion sepolicyVersion) {
         HalManifest vm;
         vm.mType = SchemaType::DEVICE;
-        vm.device.mSepolicyVersion = {25, 0};
+        vm.device.mSepolicyVersion = sepolicyVersion;
         vm.add(createManifestHal(HalFormat::HIDL, "android.hardware.camera",
                                  {Transport::HWBINDER, Arch::ARCH_EMPTY},
                                  {
@@ -172,6 +172,7 @@
 
         return vm;
     }
+    HalManifest testDeviceManifest() { return testDeviceManifestWithSepolicy({25, 0}); }
     HalManifest testDeviceManifestWithXmlFile() {
         HalManifest vm = testDeviceManifest();
         ManifestXmlFile xmlFile;
@@ -252,6 +253,16 @@
     VersionRange v2;
     EXPECT_TRUE(parse("1.2-3", &v2));
     EXPECT_EQ(v, v2);
+    SepolicyVersionRange v3(4, std::nullopt);
+    EXPECT_EQ(to_string(v3), "4");
+    SepolicyVersionRange v4;
+    EXPECT_TRUE(parse("4", &v4));
+    EXPECT_EQ(v3, v4);
+    SepolicyVersion v5(5, std::nullopt);
+    EXPECT_EQ(to_string(v5), "5");
+    SepolicyVersion v6;
+    EXPECT_TRUE(parse("5", &v6));
+    EXPECT_EQ(v5, v6);
 }
 
 TEST_F(LibVintfTest, GetTransport) {
@@ -311,6 +322,33 @@
     EXPECT_EQ(vm, vm2);
 }
 
+TEST_F(LibVintfTest, HalManifestConverterWithVfrcSepolicy) {
+    HalManifest vm = testDeviceManifestWithSepolicy({202404, std::nullopt});
+    std::string xml =
+        toXml(vm, SerializeFlags::HALS_ONLY.enableSepolicy());
+    EXPECT_EQ(xml,
+        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>android.hardware.camera</name>\n"
+        "        <transport>hwbinder</transport>\n"
+        "        <fqname>@2.0::IBetterCamera/camera</fqname>\n"
+        "        <fqname>@2.0::ICamera/default</fqname>\n"
+        "        <fqname>@2.0::ICamera/legacy/0</fqname>\n"
+        "    </hal>\n"
+        "    <hal format=\"hidl\">\n"
+        "        <name>android.hardware.nfc</name>\n"
+        "        <transport arch=\"32+64\">passthrough</transport>\n"
+        "        <fqname>@1.0::INfc/default</fqname>\n"
+        "    </hal>\n"
+        "    <sepolicy>\n"
+        "        <version>202404</version>\n"
+        "    </sepolicy>\n"
+        "</manifest>\n");
+    HalManifest vm2;
+    EXPECT_TRUE(fromXml(&vm2, xml));
+    EXPECT_EQ(vm, vm2);
+}
+
 TEST_F(LibVintfTest, HalManifestConverterWithInterface) {
     HalManifest vm = testDeviceManifest();
     std::string xml =
@@ -669,6 +707,13 @@
     Version v2;
     EXPECT_TRUE(fromXml(&v2, xml));
     EXPECT_EQ(v, v2);
+
+    SepolicyVersion v3(202404, std::nullopt);
+    std::string xml2 = toXml(v3);
+    EXPECT_EQ(xml2, "<version>202404</version>\n");
+    SepolicyVersion v4;
+    EXPECT_TRUE(fromXml(&v4, xml2));
+    EXPECT_EQ(v3, v4);
 }
 
 static bool insert(std::map<std::string, HalInterface>* map, HalInterface&& intf) {
@@ -799,7 +844,7 @@
             {KernelConfig{"CONFIG_FOO", Tristate::YES}, KernelConfig{"CONFIG_BAR", "stringvalue"}}}));
     EXPECT_TRUE(add(cm, MatrixKernel{KernelVersion(4, 4, 1),
             {KernelConfig{"CONFIG_BAZ", 20}, KernelConfig{"CONFIG_BAR", KernelConfigRangeValue{3, 5} }}}));
-    set(cm, Sepolicy(30, {{25, 0}, {26, 0, 3}}));
+    set(cm, Sepolicy(30, {{25, 0}, {26, 0, 3}, {202404, std::nullopt}}));
     setAvb(cm, Version{2, 1});
     std::string xml = toXml(cm);
     EXPECT_EQ(xml,
@@ -846,6 +891,7 @@
             "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
             "        <sepolicy-version>25.0</sepolicy-version>\n"
             "        <sepolicy-version>26.0-3</sepolicy-version>\n"
+            "        <sepolicy-version>202404</sepolicy-version>\n"
             "    </sepolicy>\n"
             "    <avb>\n"
             "        <vbmeta-version>2.1</vbmeta-version>\n"
@@ -1468,6 +1514,7 @@
         "        <kernel-sepolicy-version>30</kernel-sepolicy-version>\n"
         "        <sepolicy-version>25.5</sepolicy-version>\n"
         "        <sepolicy-version>26.0-3</sepolicy-version>\n"
+        "        <sepolicy-version>202404</sepolicy-version>\n"
         "    </sepolicy>\n"
         "    <avb>\n"
         "        <vbmeta-version>2.1</vbmeta-version>\n"
@@ -1513,6 +1560,23 @@
     EXPECT_FALSE(manifest.checkCompatibility(matrix));
     set(matrix, Sepolicy{30, {{25, 4}}});
     EXPECT_TRUE(manifest.checkCompatibility(matrix, &error)) << error;
+    set(matrix, Sepolicy{30, {{202404, std::nullopt}}});
+    EXPECT_FALSE(manifest.checkCompatibility(matrix));
+
+    // vFRC sepolicy test cases
+    manifestXml =
+        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
+        "    <sepolicy>\n"
+        "        <version>202404</version>\n"
+        "    </sepolicy>\n"
+        "</manifest>\n";
+    EXPECT_TRUE(fromXml(&manifest, manifestXml));
+    set(matrix, Sepolicy{30, {{202404, std::nullopt}}});
+    EXPECT_TRUE(manifest.checkCompatibility(matrix)) << error;
+    set(matrix, Sepolicy{30, {{202404, 0}}});
+    EXPECT_FALSE(manifest.checkCompatibility(matrix)) << error;
+    set(matrix, Sepolicy{30, {{202504, std::nullopt}}});
+    EXPECT_FALSE(manifest.checkCompatibility(matrix));
 }
 
 // clang-format on
@@ -4179,7 +4243,7 @@
         "    </hal>\n"
         "    <sepolicy>\n"
         "        <kernel-sepolicy-version>0</kernel-sepolicy-version>\n"
-        "        <sepolicy-version>0.0</sepolicy-version>\n"
+        "        <sepolicy-version>0</sepolicy-version>\n"
         "    </sepolicy>\n"
         "</compatibility-matrix>\n";
     EXPECT_TRUE(fromXml(&matrix, matrixXml, &error)) << error;
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 8793634..6f81081 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -1974,7 +1974,7 @@
         FAKE_KERNEL("2.0.0", "B1", 1)
         "    <sepolicy>\n"
         "        <kernel-sepolicy-version>0</kernel-sepolicy-version>\n"
-        "        <sepolicy-version>0.0</sepolicy-version>\n"
+        "        <sepolicy-version>0</sepolicy-version>\n"
         "    </sepolicy>\n"
         "</compatibility-matrix>\n"});
     expectKernelFcmVersion(1, Level{1});