Snap for 12361654 from a43fc7260000cce0578263adc08626d0e77bb089 to 24Q4-release
Change-Id: I347a3943d4aebd757d6762882ec66767612f4320
diff --git a/libs/libinherited_fd/Android.bp b/libs/libinherited_fd/Android.bp
deleted file mode 100644
index 28ec2e5..0000000
--- a/libs/libinherited_fd/Android.bp
+++ /dev/null
@@ -1,44 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-rust_defaults {
- name: "libinherited_fd.defaults",
- crate_name: "inherited_fd",
- srcs: ["src/lib.rs"],
- edition: "2021",
- rustlibs: [
- "libnix",
- "libonce_cell",
- "libthiserror",
- ],
-}
-
-rust_library {
- name: "libinherited_fd",
- defaults: ["libinherited_fd.defaults"],
- apex_available: [
- "com.android.compos",
- "com.android.virt",
- ],
-}
-
-rust_test {
- name: "libinherited_fd.test",
- defaults: ["libinherited_fd.defaults"],
- rustlibs: [
- "libanyhow",
- "libtempfile",
- ],
- host_supported: true,
- test_suites: ["general-tests"],
- test_options: {
- unit_test: true,
- },
- // this is to run each test function in a separate process.
- // note that they still run in parallel.
- flags: [
- "-C panic=abort",
- "-Z panic_abort_tests",
- ],
-}
diff --git a/libs/libinherited_fd/src/lib.rs b/libs/libinherited_fd/src/lib.rs
deleted file mode 100644
index f5e2d6b..0000000
--- a/libs/libinherited_fd/src/lib.rs
+++ /dev/null
@@ -1,270 +0,0 @@
-// 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.
-
-//! Library for safely obtaining `OwnedFd` for inherited file descriptors.
-
-use nix::fcntl::{fcntl, FdFlag, F_SETFD};
-use nix::libc;
-use std::collections::HashMap;
-use std::fs::canonicalize;
-use std::fs::read_dir;
-use std::os::fd::FromRawFd;
-use std::os::fd::OwnedFd;
-use std::os::fd::RawFd;
-use std::sync::Mutex;
-use std::sync::OnceLock;
-use thiserror::Error;
-
-/// Errors that can occur while taking an ownership of `RawFd`
-#[derive(Debug, PartialEq, Error)]
-pub enum Error {
- /// init_once() not called
- #[error("init_once() not called")]
- NotInitialized,
-
- /// Ownership already taken
- #[error("Ownership of FD {0} is already taken")]
- OwnershipTaken(RawFd),
-
- /// Not an inherited file descriptor
- #[error("FD {0} is either invalid file descriptor or not an inherited one")]
- FileDescriptorNotInherited(RawFd),
-
- /// Failed to set CLOEXEC
- #[error("Failed to set CLOEXEC on FD {0}")]
- FailCloseOnExec(RawFd),
-}
-
-static INHERITED_FDS: OnceLock<Mutex<HashMap<RawFd, Option<OwnedFd>>>> = OnceLock::new();
-
-/// Take ownership of all open file descriptors in this process, which later can be obtained by
-/// calling `take_fd_ownership`.
-///
-/// # Safety
-/// This function has to be called very early in the program before the ownership of any file
-/// descriptors (except stdin/out/err) is taken.
-pub unsafe fn init_once() -> Result<(), std::io::Error> {
- let mut fds = HashMap::new();
-
- let fd_path = canonicalize("/proc/self/fd")?;
-
- for entry in read_dir(&fd_path)? {
- let entry = entry?;
-
- // Files in /prod/self/fd are guaranteed to be numbers. So parsing is always successful.
- let file_name = entry.file_name();
- let raw_fd = file_name.to_str().unwrap().parse::<RawFd>().unwrap();
-
- // We don't take ownership of the stdio FDs as the Rust runtime owns them.
- if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
- continue;
- }
-
- // Exceptional case: /proc/self/fd/* may be a dir fd created by read_dir just above. Since
- // the file descriptor is owned by read_dir (and thus closed by it), we shouldn't take
- // ownership to it.
- if entry.path().read_link()? == fd_path {
- continue;
- }
-
- // SAFETY: /proc/self/fd/* are file descriptors that are open. If `init_once()` was called
- // at the very beginning of the program execution (as requested by the safety requirement
- // of this function), this is the first time to claim the ownership of these file
- // descriptors.
- let owned_fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
- fds.insert(raw_fd, Some(owned_fd));
- }
-
- INHERITED_FDS
- .set(Mutex::new(fds))
- .or(Err(std::io::Error::other("Inherited fds were already initialized")))
-}
-
-/// Take the ownership of the given `RawFd` and returns `OwnedFd` for it. The returned FD is set
-/// CLOEXEC. `Error` is returned when the ownership was already taken (by a prior call to this
-/// function with the same `RawFd`) or `RawFd` is not an inherited file descriptor.
-pub fn take_fd_ownership(raw_fd: RawFd) -> Result<OwnedFd, Error> {
- let mut fds = INHERITED_FDS.get().ok_or(Error::NotInitialized)?.lock().unwrap();
-
- if let Some(value) = fds.get_mut(&raw_fd) {
- if let Some(owned_fd) = value.take() {
- fcntl(raw_fd, F_SETFD(FdFlag::FD_CLOEXEC)).or(Err(Error::FailCloseOnExec(raw_fd)))?;
- Ok(owned_fd)
- } else {
- Err(Error::OwnershipTaken(raw_fd))
- }
- } else {
- Err(Error::FileDescriptorNotInherited(raw_fd))
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use anyhow::Result;
- use nix::fcntl::{fcntl, FdFlag, F_GETFD, F_SETFD};
- use nix::unistd::close;
- use std::os::fd::{AsRawFd, IntoRawFd};
- use tempfile::tempfile;
-
- struct Fixture {
- fds: Vec<RawFd>,
- }
-
- impl Fixture {
- fn setup(num_fds: usize) -> Result<Self> {
- let mut fds = Vec::new();
- for _ in 0..num_fds {
- fds.push(tempfile()?.into_raw_fd());
- }
- Ok(Fixture { fds })
- }
-
- fn open_new_file(&mut self) -> Result<RawFd> {
- let raw_fd = tempfile()?.into_raw_fd();
- self.fds.push(raw_fd);
- Ok(raw_fd)
- }
- }
-
- impl Drop for Fixture {
- fn drop(&mut self) {
- self.fds.iter().for_each(|fd| {
- let _ = close(*fd);
- });
- }
- }
-
- fn is_fd_opened(raw_fd: RawFd) -> bool {
- fcntl(raw_fd, F_GETFD).is_ok()
- }
-
- #[test]
- fn happy_case() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f0 = fixture.fds[0];
- let f1 = fixture.fds[1];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f0_owned = take_fd_ownership(f0)?;
- let f1_owned = take_fd_ownership(f1)?;
- assert_eq!(f0, f0_owned.as_raw_fd());
- assert_eq!(f1, f1_owned.as_raw_fd());
-
- drop(f0_owned);
- drop(f1_owned);
- assert!(!is_fd_opened(f0));
- assert!(!is_fd_opened(f1));
- Ok(())
- }
-
- #[test]
- fn access_non_inherited_fd() -> Result<()> {
- let mut fixture = Fixture::setup(2)?;
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f = fixture.open_new_file()?;
- assert_eq!(Some(Error::FileDescriptorNotInherited(f)), take_fd_ownership(f).err());
- Ok(())
- }
-
- #[test]
- fn call_init_once_multiple_times() -> Result<()> {
- let _ = Fixture::setup(2)?;
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- // SAFETY: for testing
- let res = unsafe { init_once() };
- assert!(res.is_err());
- Ok(())
- }
-
- #[test]
- fn access_without_init_once() -> Result<()> {
- let fixture = Fixture::setup(2)?;
-
- let f = fixture.fds[0];
- assert_eq!(Some(Error::NotInitialized), take_fd_ownership(f).err());
- Ok(())
- }
-
- #[test]
- fn double_ownership() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f = fixture.fds[0];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f_owned = take_fd_ownership(f)?;
- let f_double_owned = take_fd_ownership(f);
- assert_eq!(Some(Error::OwnershipTaken(f)), f_double_owned.err());
-
- // just to highlight that f_owned is kept alive when the second call to take_fd_ownership
- // is made.
- drop(f_owned);
- Ok(())
- }
-
- #[test]
- fn take_drop_retake() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f = fixture.fds[0];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- let f_owned = take_fd_ownership(f)?;
- drop(f_owned);
-
- let f_double_owned = take_fd_ownership(f);
- assert_eq!(Some(Error::OwnershipTaken(f)), f_double_owned.err());
- Ok(())
- }
-
- #[test]
- fn cloexec() -> Result<()> {
- let fixture = Fixture::setup(2)?;
- let f = fixture.fds[0];
-
- // SAFETY: assume files opened by Fixture are inherited ones
- unsafe {
- init_once()?;
- }
-
- // Intentionally cleaar cloexec to see if it is set by take_fd_ownership
- fcntl(f, F_SETFD(FdFlag::empty()))?;
-
- let f_owned = take_fd_ownership(f)?;
- let flags = fcntl(f_owned.as_raw_fd(), F_GETFD)?;
- assert_eq!(flags, FdFlag::FD_CLOEXEC.bits());
- Ok(())
- }
-}
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java b/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
index 3814cdd..8604553 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
@@ -78,9 +78,9 @@
/** This class provides utilities to interact with the hyp tracing subsystem */
public final class KvmHypTracer {
- private static final String HYP_TRACING_ROOT = "/sys/kernel/tracing/hyp/";
private static final int DEFAULT_BUF_SIZE_KB = 4 * 1024;
+ private final String mHypTracingRoot;
private final CommandRunner mRunner;
private final ITestDevice mDevice;
private final int mNrCpus;
@@ -88,17 +88,41 @@
private final ArrayList<File> mTraces;
- private void setNode(String node, int val) throws Exception {
- mRunner.run("echo " + val + " > " + HYP_TRACING_ROOT + node);
+ private static String getHypTracingRoot(ITestDevice device) throws Exception {
+ String legacy = "/sys/kernel/tracing/hyp/";
+ String path = "/sys/kernel/tracing/hypervisor/";
+
+ if (device.doesFileExist(path)) {
+ return path;
+ }
+
+ if (device.doesFileExist(legacy)) {
+ return legacy;
+ }
+
+ throw new Exception("Hypervisor tracing not found");
}
- private static String eventDir(String event) {
- return "events/hyp/" + event + "/";
+ private static String getHypEventsDir(String root) {
+ if (root.endsWith("/hypervisor/"))
+ return "events/hypervisor/";
+
+ return "events/hyp/";
}
public static boolean isSupported(ITestDevice device, String[] events) throws Exception {
- for (String event : events) {
- if (!device.doesFileExist(HYP_TRACING_ROOT + eventDir(event) + "/enable")) return false;
+ String dir;
+
+ try {
+ dir = getHypTracingRoot(device);
+ dir += getHypEventsDir(dir);
+ } catch (Exception e) {
+ return false;
+ }
+
+ for (String event: events) {
+ if (!device.doesFileExist(dir + event + "/enable"))
+ return false;
}
return true;
}
@@ -108,6 +132,7 @@
.that(isSupported(device, events))
.isTrue();
+ mHypTracingRoot = getHypTracingRoot(device);
mDevice = device;
mRunner = new CommandRunner(mDevice);
mTraces = new ArrayList<File>();
@@ -115,17 +140,25 @@
mHypEvents = events;
}
+ private void setNode(String node, int val) throws Exception {
+ mRunner.run("echo " + val + " > " + mHypTracingRoot + node);
+ }
+
public String run(String payload_cmd) throws Exception {
mTraces.clear();
setNode("tracing_on", 0);
- mRunner.run("echo 0 | tee " + HYP_TRACING_ROOT + "events/*/*/enable");
+ mRunner.run("echo 0 | tee " + mHypTracingRoot + "events/*/*/enable");
setNode("buffer_size_kb", DEFAULT_BUF_SIZE_KB);
- for (String event : mHypEvents) setNode(eventDir(event) + "/enable", 1);
+
+ for (String event: mHypEvents) {
+ setNode(getHypEventsDir(mHypTracingRoot) + event + "/enable", 1);
+ }
+
setNode("trace", 0);
/* Cat each per-cpu trace_pipe in its own tmp file in the background */
- String cmd = "cd " + HYP_TRACING_ROOT + ";";
+ String cmd = "cd " + mHypTracingRoot + ";";
String trace_pipes[] = new String[mNrCpus];
for (int i = 0; i < mNrCpus; i++) {
trace_pipes[i] = mRunner.run("mktemp -t trace_pipe.cpu" + i + ".XXXXXXXXXX");