Merge "microdroid_manager: waits for a config file"
diff --git a/microdroid/microdroid_payload.json b/microdroid/microdroid_payload.json
index 287aabd..ec4ff17 100644
--- a/microdroid/microdroid_payload.json
+++ b/microdroid/microdroid_payload.json
@@ -6,5 +6,6 @@
"apk": {
"name": "com.android.microdroid.test",
"path": "/apex/com.android.virt/app/MicrodroidTestApp/MicrodroidTestApp.apk"
- }
+ },
+ "payload_config_path": "/mnt/apk/assets/vm_config.json"
}
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index 2c79196..38d500c 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -2,8 +2,8 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-rust_binary {
- name: "microdroid_manager",
+rust_defaults {
+ name: "microdroid_manager_defaults",
crate_name: "microdroid_manager",
srcs: ["src/main.rs"],
edition: "2018",
@@ -19,3 +19,22 @@
],
init_rc: ["microdroid_manager.rc"],
}
+
+rust_binary {
+ name: "microdroid_manager",
+ defaults: ["microdroid_manager_defaults"],
+}
+
+rust_test {
+ name: "microdroid_manager_test",
+ defaults: ["microdroid_manager_defaults"],
+ test_suites: ["device-tests"],
+ rustlibs: [
+ "libtempfile",
+ ],
+ multilib: {
+ lib32: {
+ enabled: false,
+ },
+ },
+}
diff --git a/microdroid_manager/src/ioutil.rs b/microdroid_manager/src/ioutil.rs
new file mode 100644
index 0000000..e8732ad
--- /dev/null
+++ b/microdroid_manager/src/ioutil.rs
@@ -0,0 +1,74 @@
+// Copyright 2021, 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.
+
+//! IO utilities
+
+use std::fs::File;
+use std::io;
+use std::path::Path;
+use std::thread;
+use std::time::{Duration, Instant};
+
+const SLEEP_DURATION: Duration = Duration::from_millis(5);
+
+/// waits for a file with a timeout and returns it
+pub fn wait_for_file<P: AsRef<Path>>(path: P, timeout: Duration) -> io::Result<File> {
+ let begin = Instant::now();
+ loop {
+ match File::open(&path) {
+ Ok(file) => return Ok(file),
+ Err(error) => {
+ if error.kind() != io::ErrorKind::NotFound {
+ return Err(error);
+ }
+ if begin.elapsed() > timeout {
+ return Err(io::Error::from(io::ErrorKind::NotFound));
+ }
+ thread::sleep(SLEEP_DURATION);
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::io::{Read, Write};
+
+ #[test]
+ fn test_wait_for_file() -> io::Result<()> {
+ let test_dir = tempfile::TempDir::new().unwrap();
+ let test_file = test_dir.path().join("test.txt");
+ thread::spawn(move || -> io::Result<()> {
+ thread::sleep(Duration::from_secs(1));
+ File::create(test_file)?.write_all(b"test")
+ });
+
+ let test_file = test_dir.path().join("test.txt");
+ let mut file = wait_for_file(&test_file, Duration::from_secs(5))?;
+ let mut buffer = String::new();
+ file.read_to_string(&mut buffer)?;
+ assert_eq!("test", buffer);
+ Ok(())
+ }
+
+ #[test]
+ fn test_wait_for_file_fails() {
+ let test_dir = tempfile::TempDir::new().unwrap();
+ let test_file = test_dir.path().join("test.txt");
+ let file = wait_for_file(&test_file, Duration::from_secs(1));
+ assert!(file.is_err());
+ assert_eq!(io::ErrorKind::NotFound, file.unwrap_err().kind());
+ }
+}
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 4f87a40..fbbe8f3 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -14,6 +14,7 @@
//! Microdroid Manager
+mod ioutil;
mod payload_config;
mod signature;
@@ -21,7 +22,8 @@
use log::{info, Level};
use payload_config::{Task, VmPayloadConfig};
use std::io;
-use std::process::Command;
+use std::path::Path;
+use std::process::{Command, Stdio};
const LOG_TAG: &str = "MicrodroidManager";
@@ -32,7 +34,7 @@
let signature = signature::load()?;
if !signature.payload_config_path.is_empty() {
- let config = VmPayloadConfig::load_from(&signature.payload_config_path)?;
+ let config = VmPayloadConfig::load_from(Path::new(&signature.payload_config_path))?;
if let Some(main_task) = &config.task {
exec(main_task)?;
}
@@ -45,7 +47,8 @@
/// TODO(jooyung): fork a child process
fn exec(task: &Task) -> io::Result<()> {
info!("executing main task {} {:?}...", task.command, task.args);
- let exit_status = Command::new(&task.command).args(&task.args).status()?;
+ let exit_status =
+ Command::new(&task.command).args(&task.args).stdout(Stdio::inherit()).status()?;
info!("exit with {}", &exit_status);
Ok(())
}
diff --git a/microdroid_manager/src/payload_config.rs b/microdroid_manager/src/payload_config.rs
index 1dd6d92..bac841a 100644
--- a/microdroid_manager/src/payload_config.rs
+++ b/microdroid_manager/src/payload_config.rs
@@ -16,8 +16,13 @@
use log::info;
use serde::{Deserialize, Serialize};
-use std::fs::File;
use std::io;
+use std::path::Path;
+use std::time::Duration;
+
+use crate::ioutil;
+
+const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct VmPayloadConfig {
@@ -33,9 +38,9 @@
}
impl VmPayloadConfig {
- pub fn load_from(path: &str) -> io::Result<VmPayloadConfig> {
- info!("loading config from {}...", path);
- let file = File::open(path)?;
+ pub fn load_from(path: &Path) -> io::Result<VmPayloadConfig> {
+ info!("loading config from {:?}...", path);
+ let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)?;
Ok(serde_json::from_reader(file)?)
}
}
diff --git a/tests/testapk/assets/vm_config.json b/tests/testapk/assets/vm_config.json
new file mode 100644
index 0000000..e619c3b
--- /dev/null
+++ b/tests/testapk/assets/vm_config.json
@@ -0,0 +1,6 @@
+{
+ "task": {
+ "command": "echo",
+ "args": ["hello", "microdroid"]
+ }
+}
\ No newline at end of file