Check API version levels for backcompat tests

Check that vendor API level is set and that the board API level >=
202504 when running backcompat tests to check for Secretkeeper nodes.
If those 2 conditions are not met, Secretkeeper is assumed not supported
and we skip over the nodes related to Secretkeeper.

Bug: 394770084
Test: TH
Change-Id: I4846e1f3252615b4829f754c256696bb13903389
diff --git a/tests/backcompat_test/Android.bp b/tests/backcompat_test/Android.bp
index aa1e089..d47487a 100644
--- a/tests/backcompat_test/Android.bp
+++ b/tests/backcompat_test/Android.bp
@@ -14,6 +14,7 @@
         "libanyhow",
         "liblibc",
         "libnix",
+        "librustutils",
         "libvmclient",
         "liblog_rust",
     ],
diff --git a/tests/backcompat_test/src/main.rs b/tests/backcompat_test/src/main.rs
index b92049d..eaf3365 100644
--- a/tests/backcompat_test/src/main.rs
+++ b/tests/backcompat_test/src/main.rs
@@ -25,6 +25,7 @@
 use anyhow::anyhow;
 use anyhow::Context;
 use anyhow::Error;
+use anyhow::Result;
 use log::info;
 use std::fs::read_to_string;
 use std::fs::File;
@@ -46,11 +47,11 @@
 
 /// Runs a protected VM and validates it against a golden device tree.
 #[test]
-fn test_device_tree_protected_compat() -> Result<(), Error> {
+fn test_device_tree_protected_compat() -> Result<()> {
     run_test(true, GOLDEN_DEVICE_TREE_PROTECTED)
 }
 
-fn run_test(protected: bool, golden_dt: &str) -> Result<(), Error> {
+fn run_test(protected: bool, golden_dt: &str) -> Result<()> {
     let kernel = Some(open_payload(VMBASE_EXAMPLE_KERNEL_PATH)?);
     android_logger::init_once(
         android_logger::Config::default()
@@ -142,7 +143,8 @@
     {
         return Err(anyhow!("failed to execute dtc"));
     }
-    let dtcompare_res = Command::new("./dtcompare")
+    let mut dtcompare_cmd = Command::new("./dtcompare");
+    dtcompare_cmd
         .arg("--dt1")
         .arg("dump_dt_golden.dtb")
         .arg("--dt2")
@@ -162,12 +164,23 @@
         .arg("/chosen/linux,initrd-start")
         .arg("--ignore-path-value")
         .arg("/chosen/linux,initrd-end")
-        .arg("--ignore-path-value")
-        .arg("/avf/secretkeeper_public_key")
         .arg("--ignore-path")
-        .arg("/avf/name")
-        .output()
-        .context("failed to execute dtcompare")?;
+        .arg("/avf/name");
+    // Check if Secretkeeper is advertised. If not, check the vendor API level. Secretkeeper is
+    // required as of 202504, and if missing, the test should fail.
+    // Otherwise, ignore the fields, as they are not required.
+    if service.isUpdatableVmSupported()? {
+        dtcompare_cmd.arg("--ignore-path-value").arg("/avf/secretkeeper_public_key");
+    } else if vsr_api_level()? >= 202504 {
+        return Err(anyhow!("Secretkeeper support missing on vendor API >= 202504. Secretkeeper needs to be implemented."));
+    } else {
+        dtcompare_cmd
+            .arg("--ignore-path")
+            .arg("/avf/secretkeeper_public_key")
+            .arg("--ignore-path")
+            .arg("/avf/untrusted/defer-rollback-protection");
+    }
+    let dtcompare_res = dtcompare_cmd.output().context("failed to execute dtcompare")?;
     if !dtcompare_res.status.success() {
         if !Command::new("./dtc_static")
             .arg("-I")
@@ -202,7 +215,17 @@
     Ok(())
 }
 
-fn open_payload(path: &str) -> Result<ParcelFileDescriptor, Error> {
+fn open_payload(path: &str) -> Result<ParcelFileDescriptor> {
     let file = File::open(path).with_context(|| format!("Failed to open VM image {path}"))?;
     Ok(ParcelFileDescriptor::new(file))
 }
+
+fn vsr_api_level() -> Result<i32> {
+    get_sysprop_i32("ro.vendor.api_level")
+}
+
+fn get_sysprop_i32(prop: &str) -> Result<i32> {
+    let res = rustutils::system_properties::read(prop)?;
+    res.map(|val| val.parse::<i32>().with_context(|| format!("Failed to read {prop}")))
+        .unwrap_or(Ok(-1))
+}