Add libdts for comparing DTs
dtdiff script compares DTs of various formats, but it can't be used
because it expects bash extension.
libdts decompiles DTs with statically built dtc with sort option, so can
be used in Android instead of dtdiff.
Bug: 277993056
Test: atest libfsfdt_test
Change-Id: I69187beeb544afeb5206fed22dc824165b0dc410
diff --git a/tests/libs/libdts/Android.bp b/tests/libs/libdts/Android.bp
new file mode 100644
index 0000000..512c50b
--- /dev/null
+++ b/tests/libs/libdts/Android.bp
@@ -0,0 +1,17 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library_rlib {
+ name: "libdts",
+ crate_name: "dts",
+ defaults: ["avf_build_flags_rust"],
+ srcs: ["src/lib.rs"],
+ edition: "2021",
+ prefer_rlib: true,
+ rustlibs: [
+ "libanyhow",
+ "liblibfdt",
+ ],
+ apex_available: ["com.android.virt"],
+}
diff --git a/tests/libs/libdts/README.md b/tests/libs/libdts/README.md
new file mode 100644
index 0000000..ed63bd0
--- /dev/null
+++ b/tests/libs/libdts/README.md
@@ -0,0 +1,16 @@
+Device tree source (DTS) decompiler on Android device.
+
+This is alternative to dtdiff, which only support bash.
+
+How to use for rust_test
+========================
+
+Following dependencies are needed in addition to libdts.
+
+```
+rust_test {
+ ...
+ data_bins: ["dtc_static"],
+ compile_multilib: "first",
+}
+```
diff --git a/tests/libs/libdts/src/lib.rs b/tests/libs/libdts/src/lib.rs
new file mode 100644
index 0000000..0ee9b66
--- /dev/null
+++ b/tests/libs/libdts/src/lib.rs
@@ -0,0 +1,75 @@
+// Copyright 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Device tree source (dts) for comparing device tree contents
+//! i.e. sorted dts decompiled by `dtc -s -O dts`.
+
+use anyhow::{anyhow, Result};
+use libfdt::Fdt;
+use std::io::Write;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+/// Device tree source (dts)
+#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub struct Dts {
+ dts: String,
+}
+
+impl Dts {
+ /// Creates a device tree source from /proc/device-tree style directory
+ pub fn from_fs(path: &Path) -> Result<Self> {
+ let path = path.to_str().unwrap();
+ let res = Command::new("./dtc_static")
+ .args(["-f", "-s", "-I", "fs", "-O", "dts", path])
+ .output()?;
+ if !res.status.success() {
+ return Err(anyhow!("Failed to run dtc_static, res={res:?}"));
+ }
+ Ok(Self { dts: String::from_utf8(res.stdout)? })
+ }
+
+ /// Creates a device tree source from dtb
+ pub fn from_dtb(path: &Path) -> Result<Self> {
+ let path = path.to_str().unwrap();
+ let res = Command::new("./dtc_static")
+ .args(["-f", "-s", "-I", "dtb", "-O", "dts", path])
+ .output()?;
+ if !res.status.success() {
+ return Err(anyhow!("Failed to run dtc_static, res={res:?}"));
+ }
+ Ok(Self { dts: String::from_utf8(res.stdout)? })
+ }
+
+ /// Creates a device tree source from Fdt
+ pub fn from_fdt(fdt: &Fdt) -> Result<Self> {
+ let mut dtc = Command::new("./dtc_static")
+ .args(["-f", "-s", "-I", "dtb", "-O", "dts"])
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()?;
+
+ {
+ let mut stdin = dtc.stdin.take().unwrap();
+ stdin.write_all(fdt.as_slice())?;
+ // Explicitly drop stdin to avoid indefinite blocking
+ }
+
+ let res = dtc.wait_with_output()?;
+ if !res.status.success() {
+ return Err(anyhow!("Failed to run dtc_static, res={res:?}"));
+ }
+ Ok(Self { dts: String::from_utf8(res.stdout)? })
+ }
+}
diff --git a/virtualizationmanager/fsfdt/Android.bp b/virtualizationmanager/fsfdt/Android.bp
index 7a1e5ed..1d03522 100644
--- a/virtualizationmanager/fsfdt/Android.bp
+++ b/virtualizationmanager/fsfdt/Android.bp
@@ -41,6 +41,7 @@
defaults: ["libfsfdt_default"],
data: ["testdata/**/*"],
data_bins: ["dtc_static"],
- rustlibs: ["libtempfile"],
+ prefer_rlib: true,
+ rustlibs: ["libdts"],
compile_multilib: "first",
}
diff --git a/virtualizationmanager/fsfdt/src/lib.rs b/virtualizationmanager/fsfdt/src/lib.rs
index 84e50c1..e176b7b 100644
--- a/virtualizationmanager/fsfdt/src/lib.rs
+++ b/virtualizationmanager/fsfdt/src/lib.rs
@@ -114,51 +114,20 @@
#[cfg(test)]
mod test {
use super::*;
- use std::io::Write;
- use std::process::Command;
- use tempfile::NamedTempFile;
+ use dts::Dts;
const TEST_FS_FDT_ROOT_PATH: &str = "testdata/fs";
const BUF_SIZE_MAX: usize = 1024;
- fn dts_from_fs(path: &Path) -> String {
- let path = path.to_str().unwrap();
- let res = Command::new("./dtc_static")
- .args(["-f", "-s", "-I", "fs", "-O", "dts", path])
- .output()
- .unwrap();
- assert!(res.status.success(), "{res:?}");
- String::from_utf8(res.stdout).unwrap()
- }
-
- fn dts_from_dtb(path: &Path) -> String {
- let path = path.to_str().unwrap();
- let res = Command::new("./dtc_static")
- .args(["-f", "-s", "-I", "dtb", "-O", "dts", path])
- .output()
- .unwrap();
- assert!(res.status.success(), "{res:?}");
- String::from_utf8(res.stdout).unwrap()
- }
-
- fn to_temp_file(fdt: &Fdt) -> Result<NamedTempFile> {
- let mut file = NamedTempFile::new()?;
- file.as_file_mut().write_all(fdt.as_slice())?;
- file.as_file_mut().sync_all()?;
-
- Ok(file)
- }
-
#[test]
fn test_from_fs() {
let fs_path = Path::new(TEST_FS_FDT_ROOT_PATH);
let mut data = vec![0_u8; BUF_SIZE_MAX];
let fdt = Fdt::from_fs(fs_path, &mut data).unwrap();
- let file = to_temp_file(fdt).unwrap();
- let expected = dts_from_fs(fs_path);
- let actual = dts_from_dtb(file.path());
+ let expected = Dts::from_fs(fs_path).unwrap();
+ let actual = Dts::from_fdt(fdt).unwrap();
assert_eq!(&expected, &actual);
// Again append fdt from TEST_FS_FDT_ROOT_PATH at root & ensure it succeeds when some