Merge "authfs: Fix broken test"
diff --git a/compositediskconfig/src/lib.rs b/compositediskconfig/src/lib.rs
deleted file mode 100644
index dc199e4..0000000
--- a/compositediskconfig/src/lib.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-//! JSON configuration for composite disks, as used for running `mk_cdisk` and by the `vm` tool.
-
-use serde::{Deserialize, Serialize};
-use std::path::PathBuf;
-
-/// Configuration for running `mk_cdisk`.
-#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
-pub struct Config {
- /// The set of partitions to be assembled into a composite image.
- pub partitions: Vec<Partition>,
-}
-
-/// A partition to be assembled into a composite image.
-#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
-pub struct Partition {
- /// A label for the partition.
- pub label: String,
- /// The filename of the partition image.
- pub path: PathBuf,
- /// Whether the partition should be writable.
- #[serde(default)]
- pub writable: bool,
-}
diff --git a/microdroid/README.md b/microdroid/README.md
index 802e847..b9d2086 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -181,7 +181,7 @@
TEST_ROOT=/data/local/tmp/virt
adb push out/dist/MyApp.apk.idsig $TEST_ROOT/MyApp.apk.idsig
adb push path_to_payload.json $TEST_ROOT/payload.json
-adb shell /apex/com.android.virt/bin/my_payload $TEST_ROOT/payload.json $TEST_ROOT/payload.img
+adb shell /apex/com.android.virt/bin/mk_payload $TEST_ROOT/payload.json $TEST_ROOT/payload.img
adb shell chmod go+r $TEST_ROOT/payload*
```
@@ -193,14 +193,14 @@
```sh
TEST_ROOT=/data/local/tmp/virt
-adb push packages/modules/Virtualization/microdroid/microdroid.json $TEST_ROOT/microdroid.json
adb root
adb shell setenforce 0
adb shell start virtualizationservice
-adb shell /apex/com.android.virt/bin/vm run $TEST_ROOT/microdroid.json
+adb shell /apex/com.android.virt/bin/vm run --daemonize --log $TEST_ROOT/log.txt /apex/com.android.virt/etc/microdroid.json
```
-The last command lets you know the CID assigned to the VM.
+The last command lets you know the CID assigned to the VM. The console output
+from the VM is stored to `$TEST_ROOT/log.txt` file for debugging purpose.
Note: the disabling of SELinux is a temporary step. The restriction will
eventually be removed.
@@ -211,7 +211,8 @@
adb shell /apex/com.android.virt/bin/vm stop CID
```
-, where `CID` is the reported CID value.
+, where `CID` is the reported CID value. This works only when the `vm` was
+invoked with the `--daemonize` flag.
## ADB
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index 2457797..87c8aee 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -46,6 +46,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -132,7 +134,7 @@
return result.getStdout().trim();
}
- // Run a shell command on Android
+ // Run a shell command on Android. the default timeout is 2 min by tradefed
private String runOnAndroid(String... cmd) throws Exception {
CommandResult result = getDevice().executeShellV2Command(join(cmd));
if (result.getStatus() != CommandStatus.SUCCESS) {
@@ -141,12 +143,25 @@
return result.getStdout().trim();
}
- // Same as runOnAndroid, but failutre is not an error
+ // Same as runOnAndroid, but failure is not an error
private String tryRunOnAndroid(String... cmd) throws Exception {
CommandResult result = getDevice().executeShellV2Command(join(cmd));
return result.getStdout().trim();
}
+ private String runOnAndroidWithTimeout(long timeoutMillis, String... cmd) throws Exception {
+ CommandResult result =
+ getDevice()
+ .executeShellV2Command(
+ join(cmd),
+ timeoutMillis,
+ java.util.concurrent.TimeUnit.MILLISECONDS);
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ fail(join(cmd) + " has failed: " + result);
+ }
+ return result.getStdout().trim();
+ }
+
// Run a shell command on Microdroid
private String runOnMicrodroid(String... cmd) {
final long timeout = 30000; // 30 sec. Microdroid is extremely slow on GCE-on-CF.
@@ -234,6 +249,8 @@
// Create payload.img
createPayloadImage(apkName, packageName, configPath);
+ final String logPath = TEST_ROOT + "log.txt";
+
// Run the VM
runOnAndroid("start", "virtualizationservice");
String ret =
@@ -241,8 +258,27 @@
VIRT_APEX + "bin/vm",
"run",
"--daemonize",
+ "--log " + logPath,
VIRT_APEX + "etc/microdroid.json");
+ // Redirect log.txt to logd using logwrapper
+ ExecutorService executor = Executors.newFixedThreadPool(1);
+ executor.execute(
+ () -> {
+ try {
+ // Keep redirecting sufficiently long enough
+ runOnAndroidWithTimeout(
+ MICRODROID_BOOT_TIMEOUT_MINUTES * 60 * 1000,
+ "logwrapper",
+ "tail",
+ "-f",
+ "-n +0",
+ logPath);
+ } catch (Exception e) {
+ // Consume
+ }
+ });
+
// Retrieve the CID from the vm tool output
Pattern pattern = Pattern.compile("with CID (\\d+)");
Matcher matcher = pattern.matcher(ret);
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
index 825c3da..9b8658b 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
@@ -20,8 +20,8 @@
/** A label for the partition. */
@utf8InCpp String label;
- /** The backing file descriptor of the partition image. */
- ParcelFileDescriptor image;
+ /** The backing file descriptors of the partition images. */
+ ParcelFileDescriptor[] images;
/** Whether the partition should be writable by the VM. */
boolean writable;
diff --git a/virtualizationservice/src/composite.rs b/virtualizationservice/src/composite.rs
index 5f792fd..7b5a258 100644
--- a/virtualizationservice/src/composite.rs
+++ b/virtualizationservice/src/composite.rs
@@ -336,9 +336,9 @@
Ok((composite_image, files))
}
-/// Given the AIDL config containing a list of partitions, with a [`ParcelFileDescriptor`] for each
-/// partition, return the list of file descriptors which must be passed to the mk_cdisk child
-/// process and the composite disk image partition configuration for it.
+/// Given the AIDL config containing a list of partitions, with [`ParcelFileDescriptor`]s for each
+/// partition, return the list of file descriptors which must be passed to the composite disk image
+/// partition configuration for it.
fn convert_partitions(partitions: &[Partition]) -> Result<(Vec<PartitionInfo>, Vec<File>), Error> {
// File descriptors to pass to child process.
let mut files = vec![];
@@ -346,24 +346,27 @@
let partitions = partitions
.iter()
.map(|partition| {
- // TODO(b/187187765): This shouldn't be an Option.
- let file = partition
- .image
- .as_ref()
- .context("Invalid partition image file descriptor")?
- .as_ref()
- .try_clone()
- .context("Failed to clone partition image file descriptor")?;
- let size = get_partition_size(&file)?;
- let fd = file.as_raw_fd();
- files.push(file);
+ let image_files = partition
+ .images
+ .iter()
+ .map(|image| {
+ let file = image
+ .as_ref()
+ .try_clone()
+ .context("Failed to clone partition image file descriptor")?;
+
+ let size = get_partition_size(&file)?;
+ let fd = file.as_raw_fd();
+ let partition_info_file =
+ PartitionFileInfo { path: format!("/proc/self/fd/{}", fd).into(), size };
+ files.push(file);
+ Ok(partition_info_file)
+ })
+ .collect::<Result<Vec<_>, Error>>()?;
Ok(PartitionInfo {
label: partition.label.to_owned(),
- files: vec![PartitionFileInfo {
- path: format!("/proc/self/fd/{}", fd).into(),
- size,
- }],
+ files: image_files,
partition_type: ImagePartitionType::LinuxFilesystem,
writable: partition.writable,
})
diff --git a/vm/Android.bp b/vm/Android.bp
index c07beb2..734f2d3 100644
--- a/vm/Android.bp
+++ b/vm/Android.bp
@@ -10,13 +10,13 @@
rustlibs: [
"android.system.virtualizationservice-rust",
"libanyhow",
- "libcompositediskconfig",
"libenv_logger",
"liblibc",
"liblog_rust",
"libserde_json",
"libserde",
"libstructopt",
+ "libvmconfig",
],
apex_available: [
"com.android.virt",
diff --git a/vm/src/main.rs b/vm/src/main.rs
index b79f42a..8f16eb5 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -14,7 +14,6 @@
//! Android VM control tool.
-mod config;
mod run;
mod sync;
diff --git a/vm/src/run.rs b/vm/src/run.rs
index ec95646..fbf849b 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -14,7 +14,6 @@
//! Command to run a VM.
-use crate::config::VmConfig;
use crate::sync::AtomicFlag;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::IVirtualizationService;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualMachine::IVirtualMachine;
@@ -30,6 +29,7 @@
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::path::Path;
+use vmconfig::VmConfig;
/// Run a VM from the given configuration file.
pub fn command_run(
diff --git a/compositediskconfig/Android.bp b/vmconfig/Android.bp
similarity index 66%
rename from compositediskconfig/Android.bp
rename to vmconfig/Android.bp
index 4608323..321eba0 100644
--- a/compositediskconfig/Android.bp
+++ b/vmconfig/Android.bp
@@ -3,12 +3,13 @@
}
rust_library {
- name: "libcompositediskconfig",
- host_supported: true,
- crate_name: "compositediskconfig",
+ name: "libvmconfig",
+ crate_name: "vmconfig",
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
+ "android.system.virtualizationservice-rust",
+ "libanyhow",
"libserde_json",
"libserde",
],
diff --git a/vm/src/config.rs b/vmconfig/src/lib.rs
similarity index 74%
rename from vm/src/config.rs
rename to vmconfig/src/lib.rs
index 8ea0d8f..c9385f3 100644
--- a/vm/src/config.rs
+++ b/vmconfig/src/lib.rs
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//! Struct for VM configuration.
+//! Struct for VM configuration with JSON (de)serialization and AIDL parcelables
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::DiskImage::DiskImage as AidlDiskImage,
@@ -20,8 +20,8 @@
aidl::android::system::virtualizationservice::VirtualMachineConfig::VirtualMachineConfig,
binder::ParcelFileDescriptor,
};
-use anyhow::{bail, Context, Error};
-use compositediskconfig::Partition;
+
+use anyhow::{bail, Context, Error, Result};
use serde::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
use std::io::BufReader;
@@ -105,7 +105,7 @@
impl DiskImage {
fn to_parcelable(&self) -> Result<AidlDiskImage, Error> {
let partitions =
- self.partitions.iter().map(partition_to_parcelable).collect::<Result<_, Error>>()?;
+ self.partitions.iter().map(Partition::to_parcelable).collect::<Result<_>>()?;
Ok(AidlDiskImage {
image: maybe_open_parcel_file(&self.image, self.writable)?,
writable: self.writable,
@@ -114,16 +114,49 @@
}
}
-fn partition_to_parcelable(partition: &Partition) -> Result<AidlPartition, Error> {
- Ok(AidlPartition {
- image: Some(open_parcel_file(&partition.path, partition.writable)?),
- writable: partition.writable,
- label: partition.label.to_owned(),
- })
+/// A partition to be assembled into a composite image.
+#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
+pub struct Partition {
+ /// A label for the partition.
+ pub label: String,
+ /// The filename of the partition image.
+ #[serde(default)]
+ pub path: Option<PathBuf>,
+ /// The filename of the partition image.
+ #[serde(default)]
+ pub paths: Vec<PathBuf>,
+ /// Whether the partition should be writable.
+ #[serde(default)]
+ pub writable: bool,
+}
+
+impl Partition {
+ fn to_parcelable(&self) -> Result<AidlPartition> {
+ if !self.paths.is_empty() {
+ if self.path.is_some() {
+ bail!("Partition {} contains both path/paths", &self.label);
+ }
+ let images = self
+ .paths
+ .iter()
+ .map(|path| open_parcel_file(&path, self.writable))
+ .collect::<Result<Vec<_>, _>>()?;
+ Ok(AidlPartition { images, writable: self.writable, label: self.label.to_owned() })
+ } else {
+ let path = self.path.as_ref().ok_or_else(|| {
+ Error::msg(format!("Partition {} doesn't set path/paths", &self.label))
+ })?;
+ Ok(AidlPartition {
+ images: vec![open_parcel_file(&path, self.writable)?],
+ writable: self.writable,
+ label: self.label.to_owned(),
+ })
+ }
+ }
}
/// Try to open the given file and wrap it in a [`ParcelFileDescriptor`].
-fn open_parcel_file(filename: &Path, writable: bool) -> Result<ParcelFileDescriptor, Error> {
+fn open_parcel_file(filename: &Path, writable: bool) -> Result<ParcelFileDescriptor> {
Ok(ParcelFileDescriptor::new(
OpenOptions::new()
.read(true)
@@ -137,6 +170,6 @@
fn maybe_open_parcel_file(
filename: &Option<PathBuf>,
writable: bool,
-) -> Result<Option<ParcelFileDescriptor>, Error> {
+) -> Result<Option<ParcelFileDescriptor>> {
filename.as_deref().map(|filename| open_parcel_file(filename, writable)).transpose()
}