Merge changes from topic "instance_id_as_salt" into main
* changes:
Backup instance_id & reuse it for rerunning VM
pvmfw: Defer rbp checks & instance.img is obsolete
diff --git a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
index 9c0fd72..7c85797 100644
--- a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
+++ b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
@@ -52,7 +52,7 @@
public static final String FUSE_SUPER_MAGIC_HEX = "65735546";
/** VM config entry path in the test APK */
- private static final String VM_CONFIG_PATH_IN_APK = "assets/microdroid/vm_config.json";
+ private static final String VM_CONFIG_PATH_IN_APK = "assets/vm_config.json";
/** Test directory on Android where data are located */
public static final String TEST_DIR = "/data/local/tmp/authfs";
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index ffdd0ea..d0ca026 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -24,10 +24,7 @@
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
CpuTopology::CpuTopology,
IVirtualizationService::IVirtualizationService,
- VirtualMachineAppConfig::{
- CustomConfig::CustomConfig, DebugLevel::DebugLevel, Payload::Payload,
- VirtualMachineAppConfig,
- },
+ VirtualMachineAppConfig::{DebugLevel::DebugLevel, Payload::Payload, VirtualMachineAppConfig},
VirtualMachineConfig::VirtualMachineConfig,
};
use anyhow::{anyhow, bail, Context, Result};
@@ -125,14 +122,13 @@
idsig: Some(idsig_fd),
instanceId: instance_id,
instanceImage: Some(instance_fd),
- encryptedStorageImage: None,
payload: Payload::ConfigPath(config_path),
debugLevel: debug_level,
extraIdsigs: extra_idsigs,
protectedVm: protected_vm,
memoryMib: parameters.memory_mib.unwrap_or(0), // 0 means use the default
cpuTopology: cpu_topology,
- customConfig: Some(CustomConfig { ..Default::default() }),
+ ..Default::default()
});
// Let logs go to logcat.
diff --git a/java/framework/api/test-current.txt b/java/framework/api/test-current.txt
index 3cd8e42..25eab18 100644
--- a/java/framework/api/test-current.txt
+++ b/java/framework/api/test-current.txt
@@ -9,9 +9,10 @@
public final class VirtualMachineConfig {
method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull public java.util.List<java.lang.String> getExtraApks();
- method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @Nullable public String getOs();
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull public String getOs();
method @Nullable public String getPayloadConfigPath();
method public boolean isVmConsoleInputSupported();
+ field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String MICRODROID = "microdroid";
}
public static final class VirtualMachineConfig.Builder {
@@ -25,6 +26,7 @@
public class VirtualMachineManager {
method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @NonNull public java.util.List<java.lang.String> getSupportedOSList() throws android.system.virtualmachine.VirtualMachineException;
method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @RequiresPermission(android.system.virtualmachine.VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION) public boolean isFeatureEnabled(String) throws android.system.virtualmachine.VirtualMachineException;
+ method @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") @RequiresPermission(android.system.virtualmachine.VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION) public boolean isRemoteAttestationSupported() throws android.system.virtualmachine.VirtualMachineException;
field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String FEATURE_DICE_CHANGES = "com.android.kvm.DICE_CHANGES";
field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String FEATURE_LLPVM_CHANGES = "com.android.kvm.LLPVM_CHANGES";
field @FlaggedApi("com.android.system.virtualmachine.flags.avf_v_test_apis") public static final String FEATURE_MULTI_TENANT = "com.android.kvm.MULTI_TENANT";
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java b/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
index 12aeac8..054d73c 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -27,6 +27,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
@@ -183,8 +184,25 @@
@Nullable private final File mVendorDiskImage;
- /** OS name of the VM using payload binaries. null if the VM uses a payload config file. */
- @Nullable private final String mOs;
+ /** OS name of the VM using payload binaries. */
+ @NonNull @OsName private final String mOs;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(
+ prefix = "MICRODROID",
+ value = {MICRODROID})
+ private @interface OsName {}
+
+ /**
+ * OS name of microdroid using microdroid kernel.
+ *
+ * @see Builder#setOs
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
+ @OsName
+ public static final String MICRODROID = "microdroid";
private VirtualMachineConfig(
@Nullable String packageName,
@@ -200,7 +218,7 @@
boolean vmOutputCaptured,
boolean vmConsoleInputSupported,
@Nullable File vendorDiskImage,
- @Nullable String os) {
+ @NonNull @OsName String os) {
// This is only called from Builder.build(); the builder handles parameter validation.
mPackageName = packageName;
mApkPath = apkPath;
@@ -301,10 +319,7 @@
builder.setVendorDiskImage(new File(vendorDiskImagePath));
}
- String os = b.getString(KEY_OS);
- if (os != null) {
- builder.setOs(os);
- }
+ builder.setOs(b.getString(KEY_OS));
String[] extraApks = b.getStringArray(KEY_EXTRA_APKS);
if (extraApks != null) {
@@ -498,14 +513,15 @@
}
/**
- * Returns the OS of the VM using a payload binary. Returns null if the VM uses payload config.
+ * Returns the OS of the VM.
*
* @see Builder#setOs
* @hide
*/
@TestApi
@FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
- @Nullable
+ @NonNull
+ @OsName
public String getOs() {
return mOs;
}
@@ -559,7 +575,6 @@
if (mPayloadBinaryName != null) {
VirtualMachinePayloadConfig payloadConfig = new VirtualMachinePayloadConfig();
payloadConfig.payloadBinaryName = mPayloadBinaryName;
- payloadConfig.osName = mOs;
payloadConfig.extraApks = Collections.emptyList();
vsConfig.payload =
VirtualMachineAppConfig.Payload.payloadConfig(payloadConfig);
@@ -567,6 +582,7 @@
vsConfig.payload =
VirtualMachineAppConfig.Payload.configPath(mPayloadConfigPath);
}
+ vsConfig.osName = mOs;
switch (mDebugLevel) {
case DEBUG_LEVEL_FULL:
vsConfig.debugLevel = VirtualMachineAppConfig.DebugLevel.FULL;
@@ -658,7 +674,7 @@
*/
@SystemApi
public static final class Builder {
- private final String DEFAULT_OS = "microdroid";
+ @OsName private final String DEFAULT_OS = MICRODROID;
@Nullable private final String mPackageName;
@Nullable private String mApkPath;
@@ -674,7 +690,7 @@
private boolean mVmOutputCaptured = false;
private boolean mVmConsoleInputSupported = false;
@Nullable private File mVendorDiskImage;
- @Nullable private String mOs;
+ @NonNull @OsName private String mOs = DEFAULT_OS;
/**
* Creates a builder for the given context.
@@ -714,15 +730,10 @@
throw new IllegalStateException("apkPath or packageName must be specified");
}
- String os = null;
if (mPayloadBinaryName == null) {
if (mPayloadConfigPath == null) {
throw new IllegalStateException("setPayloadBinaryName must be called");
}
- if (mOs != null) {
- throw new IllegalStateException(
- "setPayloadConfigPath and setOs may not both be called");
- }
if (!mExtraApks.isEmpty()) {
throw new IllegalStateException(
"setPayloadConfigPath and addExtraApk may not both be called");
@@ -732,11 +743,6 @@
throw new IllegalStateException(
"setPayloadBinaryName and setPayloadConfigPath may not both be called");
}
- if (mOs != null) {
- os = mOs;
- } else {
- os = DEFAULT_OS;
- }
}
if (!mProtectedVmSet) {
@@ -765,7 +771,7 @@
mVmOutputCaptured,
mVmConsoleInputSupported,
mVendorDiskImage,
- os);
+ mOs);
}
/**
@@ -1025,7 +1031,7 @@
@FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
@RequiresPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION)
@NonNull
- public Builder setOs(@NonNull String os) {
+ public Builder setOs(@NonNull @OsName String os) {
mOs = requireNonNull(os, "os must not be null");
return this;
}
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachineManager.java b/java/framework/src/android/system/virtualmachine/VirtualMachineManager.java
index 5020ff0..9c965ec 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachineManager.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachineManager.java
@@ -393,4 +393,24 @@
}
}
}
+
+ /**
+ * Returns {@code true} if the pVM remote attestation feature is supported. Remote attestation
+ * allows a protected VM to attest its authenticity to a remote server.
+ *
+ * @hide
+ */
+ @TestApi
+ @FlaggedApi(Flags.FLAG_AVF_V_TEST_APIS)
+ @RequiresPermission(VirtualMachine.MANAGE_VIRTUAL_MACHINE_PERMISSION)
+ public boolean isRemoteAttestationSupported() throws VirtualMachineException {
+ synchronized (sCreateLock) {
+ VirtualizationService service = VirtualizationService.getInstance();
+ try {
+ return service.getBinder().isRemoteAttestationSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+ }
}
diff --git a/libs/bssl/src/aead.rs b/libs/bssl/src/aead.rs
index 9aa1885..311d370 100644
--- a/libs/bssl/src/aead.rs
+++ b/libs/bssl/src/aead.rs
@@ -98,7 +98,8 @@
// SAFETY: This function only reads the given data and the returned pointer is
// checked below.
let ctx = unsafe { EVP_AEAD_CTX_new(aead.0, key.as_ptr(), key.len(), tag_len) };
- let ctx = NonNull::new(ctx).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_new))?;
+ let ctx =
+ NonNull::new(ctx).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_new))?;
Ok(Self { ctx, aead })
}
@@ -132,7 +133,7 @@
)
};
check_int_result(ret, ApiName::EVP_AEAD_CTX_seal)?;
- out.get(0..out_len).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_seal))
+ out.get(0..out_len).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_seal))
}
/// Authenticates `data` and decrypts it to `out`.
@@ -166,7 +167,7 @@
)
};
check_int_result(ret, ApiName::EVP_AEAD_CTX_open)?;
- out.get(0..out_len).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_open))
+ out.get(0..out_len).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_open))
}
/// Returns the `Aead` represented by this `AeadContext`.
diff --git a/libs/bssl/src/digest.rs b/libs/bssl/src/digest.rs
index 8a51b11..42d23d9 100644
--- a/libs/bssl/src/digest.rs
+++ b/libs/bssl/src/digest.rs
@@ -121,7 +121,7 @@
pub fn new() -> Result<Self> {
// SAFETY: The returned pointer is checked below.
let ctx = unsafe { EVP_MD_CTX_new() };
- NonNull::new(ctx).map(Self).ok_or(to_call_failed_error(ApiName::EVP_MD_CTX_new))
+ NonNull::new(ctx).map(Self).ok_or_else(|| to_call_failed_error(ApiName::EVP_MD_CTX_new))
}
pub(crate) fn as_mut_ptr(&mut self) -> *mut EVP_MD_CTX {
diff --git a/libs/bssl/src/ec_key.rs b/libs/bssl/src/ec_key.rs
index 6c9910c..897f8a1 100644
--- a/libs/bssl/src/ec_key.rs
+++ b/libs/bssl/src/ec_key.rs
@@ -65,7 +65,7 @@
};
NonNull::new(ec_key)
.map(Self)
- .ok_or(to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
+ .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
}
/// Creates a new EC P-384 key pair.
@@ -76,7 +76,7 @@
};
NonNull::new(ec_key)
.map(Self)
- .ok_or(to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
+ .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
}
/// Constructs an `EcKey` instance from the provided COSE_Key encoded public key slice.
@@ -295,7 +295,7 @@
let ec_key = NonNull::new(ec_key)
.map(Self)
- .ok_or(to_call_failed_error(ApiName::EC_KEY_parse_private_key))?;
+ .ok_or_else(|| to_call_failed_error(ApiName::EC_KEY_parse_private_key))?;
ec_key.check_key()?;
Ok(ec_key)
}
@@ -320,7 +320,7 @@
// SAFETY: This is safe because the CBB pointer is initialized with `CBB_init_fixed()`,
// and it has been flushed, thus it has no active children.
let len = unsafe { CBB_len(cbb.as_ref()) };
- Ok(buf.get(0..len).ok_or(to_call_failed_error(ApiName::CBB_len))?.to_vec().into())
+ Ok(buf.get(0..len).ok_or_else(|| to_call_failed_error(ApiName::CBB_len))?.to_vec().into())
}
}
@@ -411,13 +411,13 @@
// SAFETY: The function reads `x` within its bounds, and the returned
// pointer is checked below.
let bn = unsafe { BN_bin2bn(x.as_ptr(), x.len(), ptr::null_mut()) };
- NonNull::new(bn).map(Self).ok_or(to_call_failed_error(ApiName::BN_bin2bn))
+ NonNull::new(bn).map(Self).ok_or_else(|| to_call_failed_error(ApiName::BN_bin2bn))
}
fn new() -> Result<Self> {
// SAFETY: The returned pointer is checked below.
let bn = unsafe { BN_new() };
- NonNull::new(bn).map(Self).ok_or(to_call_failed_error(ApiName::BN_new))
+ NonNull::new(bn).map(Self).ok_or_else(|| to_call_failed_error(ApiName::BN_new))
}
/// Converts the `BigNum` to a big-endian integer. The integer is padded with leading zeros up
diff --git a/libs/bssl/src/evp.rs b/libs/bssl/src/evp.rs
index fca189c..719bb1d 100644
--- a/libs/bssl/src/evp.rs
+++ b/libs/bssl/src/evp.rs
@@ -54,7 +54,7 @@
fn new_pkey() -> Result<NonNull<EVP_PKEY>> {
// SAFETY: The returned pointer is checked below.
let key = unsafe { EVP_PKEY_new() };
- NonNull::new(key).ok_or(to_call_failed_error(ApiName::EVP_PKEY_new))
+ NonNull::new(key).ok_or_else(|| to_call_failed_error(ApiName::EVP_PKEY_new))
}
impl TryFrom<EcKey> for PKey {
@@ -94,7 +94,7 @@
// SAFETY: This is safe because the CBB pointer is initialized with `CBB_init_fixed()`,
// and it has been flushed, thus it has no active children.
let len = unsafe { CBB_len(cbb.as_ref()) };
- Ok(buf.get(0..len).ok_or(to_call_failed_error(ApiName::CBB_len))?.to_vec())
+ Ok(buf.get(0..len).ok_or_else(|| to_call_failed_error(ApiName::CBB_len))?.to_vec())
}
/// This function takes a raw public key data slice and creates a `PKey` instance wrapping
@@ -118,8 +118,8 @@
raw_public_key.len(),
)
};
- let pkey =
- NonNull::new(pkey).ok_or(to_call_failed_error(ApiName::EVP_PKEY_new_raw_public_key))?;
+ let pkey = NonNull::new(pkey)
+ .ok_or_else(|| to_call_failed_error(ApiName::EVP_PKEY_new_raw_public_key))?;
Ok(Self { pkey, _inner_ec_key: None })
}
diff --git a/libs/vmconfig/src/lib.rs b/libs/vmconfig/src/lib.rs
index 50f3c8e..907e0d3 100644
--- a/libs/vmconfig/src/lib.rs
+++ b/libs/vmconfig/src/lib.rs
@@ -15,6 +15,7 @@
//! Struct for VM configuration with JSON (de)serialization and AIDL parcelables
use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::CpuTopology::CpuTopology,
aidl::android::system::virtualizationservice::DiskImage::DiskImage as AidlDiskImage,
aidl::android::system::virtualizationservice::Partition::Partition as AidlPartition,
aidl::android::system::virtualizationservice::VirtualMachineRawConfig::VirtualMachineRawConfig,
@@ -54,6 +55,8 @@
/// The amount of RAM to give the VM, in MiB.
#[serde(default)]
pub memory_mib: Option<NonZeroU32>,
+ /// The CPU topology: either "one_cpu"(default) or "match_host"
+ pub cpu_topology: Option<String>,
/// Version or range of versions of the virtual platform that this config is compatible with.
/// The format follows SemVer (https://semver.org).
pub platform_version: VersionReq,
@@ -96,7 +99,12 @@
} else {
0
};
-
+ let cpu_topology = match self.cpu_topology.as_deref() {
+ None => CpuTopology::ONE_CPU,
+ Some("one_cpu") => CpuTopology::ONE_CPU,
+ Some("match_host") => CpuTopology::MATCH_HOST,
+ Some(cpu_topology) => bail!("Invalid cpu topology {}", cpu_topology),
+ };
Ok(VirtualMachineRawConfig {
kernel: maybe_open_parcel_file(&self.kernel, false)?,
initrd: maybe_open_parcel_file(&self.initrd, false)?,
@@ -105,6 +113,7 @@
disks: self.disks.iter().map(DiskImage::to_parcelable).collect::<Result<_, Error>>()?,
protectedVm: self.protected,
memoryMib: memory_mib,
+ cpuTopology: cpu_topology,
platformVersion: self.platform_version.to_string(),
devices: self
.devices
diff --git a/microdroid/payload/config/src/lib.rs b/microdroid/payload/config/src/lib.rs
index cdef3e4..d6f65bd 100644
--- a/microdroid/payload/config/src/lib.rs
+++ b/microdroid/payload/config/src/lib.rs
@@ -17,10 +17,12 @@
use serde::{Deserialize, Serialize};
/// VM payload config
-#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
+#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct VmPayloadConfig {
- /// OS config. Default: "microdroid"
+ /// OS config.
+ /// Deprecated: don't use. Error if not "" or "microdroid".
#[serde(default)]
+ #[deprecated]
pub os: OsConfig,
/// Task to run in a VM
@@ -58,7 +60,7 @@
impl Default for OsConfig {
fn default() -> Self {
- Self { name: "microdroid".to_owned() }
+ Self { name: "".to_owned() }
}
}
diff --git a/service_vm/manager/src/lib.rs b/service_vm/manager/src/lib.rs
index 8dedec5..3f2550c 100644
--- a/service_vm/manager/src/lib.rs
+++ b/service_vm/manager/src/lib.rs
@@ -32,7 +32,7 @@
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::os::unix::io::FromRawFd;
use std::path::{Path, PathBuf};
-use std::sync::{Condvar, Mutex, MutexGuard};
+use std::sync::{Condvar, Mutex};
use std::thread;
use std::time::Duration;
use vmclient::{DeathReason, VmInstance};
@@ -48,40 +48,78 @@
const WRITE_TIMEOUT: Duration = Duration::from_secs(10);
lazy_static! {
- static ref SERVICE_VM_STATE: State = State::default();
+ static ref PENDING_REQUESTS: AtomicCounter = AtomicCounter::default();
+ static ref SERVICE_VM: Mutex<Option<ServiceVm>> = Mutex::new(None);
+ static ref SERVICE_VM_SHUTDOWN: Condvar = Condvar::new();
}
-/// The running state of the Service VM.
+/// Atomic counter with a condition variable that is used to wait for the counter
+/// to become positive within a timeout.
#[derive(Debug, Default)]
-struct State {
- is_running: Mutex<bool>,
- stopped: Condvar,
+struct AtomicCounter {
+ num: Mutex<usize>,
+ num_increased: Condvar,
}
-impl State {
- fn wait_until_no_service_vm_running(&self) -> Result<MutexGuard<'_, bool>> {
- // The real timeout can be longer than 10 seconds since the time to acquire
- // is_running mutex is not counted in the 10 seconds.
- let (guard, wait_result) = self
- .stopped
- .wait_timeout_while(
- self.is_running.lock().unwrap(),
- Duration::from_secs(10),
- |&mut is_running| is_running,
- )
+impl AtomicCounter {
+ /// Checks if the counter becomes positive within the given timeout.
+ fn is_positive_within_timeout(&self, timeout: Duration) -> bool {
+ let (guard, _wait_result) = self
+ .num_increased
+ .wait_timeout_while(self.num.lock().unwrap(), timeout, |&mut x| x == 0)
.unwrap();
- ensure!(
- !wait_result.timed_out(),
- "Timed out while waiting for the running service VM to stop."
- );
- Ok(guard)
+ *guard > 0
}
- fn notify_service_vm_shutdown(&self) {
- let mut is_running_guard = self.is_running.lock().unwrap();
- *is_running_guard = false;
- self.stopped.notify_one();
+ fn increment(&self) {
+ let mut num = self.num.lock().unwrap();
+ *num = num.checked_add(1).unwrap();
+ self.num_increased.notify_all();
}
+
+ fn decrement(&self) {
+ let mut num = self.num.lock().unwrap();
+ *num = num.checked_sub(1).unwrap();
+ }
+}
+
+/// Processes the request in the service VM.
+pub fn process_request(request: Request) -> Result<Response> {
+ PENDING_REQUESTS.increment();
+ let result = process_request_in_service_vm(request);
+ PENDING_REQUESTS.decrement();
+ thread::spawn(stop_service_vm_if_idle);
+ result
+}
+
+fn process_request_in_service_vm(request: Request) -> Result<Response> {
+ let mut service_vm = SERVICE_VM.lock().unwrap();
+ if service_vm.is_none() {
+ *service_vm = Some(ServiceVm::start()?);
+ }
+ service_vm.as_mut().unwrap().process_request(request)
+}
+
+fn stop_service_vm_if_idle() {
+ if PENDING_REQUESTS.is_positive_within_timeout(Duration::from_secs(1)) {
+ info!("Service VM has pending requests, keeping it running.");
+ } else {
+ info!("Service VM is idle, shutting it down.");
+ *SERVICE_VM.lock().unwrap() = None;
+ SERVICE_VM_SHUTDOWN.notify_all();
+ }
+}
+
+/// Waits until the service VM shuts down.
+/// This function is only used in tests.
+pub fn wait_until_service_vm_shuts_down() -> Result<()> {
+ const WAIT_FOR_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
+
+ let (_guard, wait_result) = SERVICE_VM_SHUTDOWN
+ .wait_timeout_while(SERVICE_VM.lock().unwrap(), WAIT_FOR_SHUTDOWN_TIMEOUT, |x| x.is_some())
+ .unwrap();
+ ensure!(!wait_result.timed_out(), "Service VM didn't shut down within the timeout");
+ Ok(())
}
/// Service VM.
@@ -94,17 +132,12 @@
impl ServiceVm {
/// Starts the service VM and returns its instance.
/// The same instance image is used for different VMs.
- /// At any given time, only one service should be running. If a service VM is
- /// already running, this function will start the service VM once the running one
- /// shuts down.
+ /// TODO(b/27593612): Remove instance image usage for Service VM.
pub fn start() -> Result<Self> {
- let mut is_running_guard = SERVICE_VM_STATE.wait_until_no_service_vm_running()?;
-
let instance_img_path = Path::new(VIRT_DATA_DIR).join(INSTANCE_IMG_NAME);
let vm = protected_vm_instance(instance_img_path)?;
let vm = Self::start_vm(vm, VmType::ProtectedVm)?;
- *is_running_guard = true;
Ok(vm)
}
@@ -174,7 +207,6 @@
Ok(reason) => info!("Exit the service VM successfully: {reason:?}"),
Err(e) => warn!("Service VM shutdown request failed '{e:?}', killing it."),
}
- SERVICE_VM_STATE.notify_service_vm_shutdown();
}
}
diff --git a/service_vm/test_apk/Android.bp b/service_vm/test_apk/Android.bp
index cd992db..e69b348 100644
--- a/service_vm/test_apk/Android.bp
+++ b/service_vm/test_apk/Android.bp
@@ -45,7 +45,10 @@
rust_ffi {
name: "libvm_attestation_test_payload",
defaults: ["vm_attestation_test_payload_defaults"],
- visibility: [":__subpackages__"],
+ visibility: [
+ ":__subpackages__",
+ "//packages/modules/Virtualization/tests/testapk",
+ ],
}
android_test {
diff --git a/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl b/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl
index 34c8549..18df572 100644
--- a/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl
+++ b/service_vm/test_apk/aidl/com/android/virt/vm_attestation/testservice/IAttestationService.aidl
@@ -21,6 +21,27 @@
const int PORT = 5679;
/**
+ * The status of the attestation.
+ *
+ * The status here maps to the status defined in
+ * vm_payload/include/vm_payload.h
+ */
+ @Backing(type="int")
+ enum AttestationStatus {
+ /** The remote attestation completes successfully. */
+ ATTESTATION_OK = 0,
+
+ /** The challenge size is not between 0 and 64. */
+ ATTESTATION_ERROR_INVALID_CHALLENGE = 1,
+
+ /** Failed to attest the VM. Please retry at a later time. */
+ ATTESTATION_ERROR_ATTESTATION_FAILED = 2,
+
+ /** Remote attestation is not supported in the current environment. */
+ ATTESTATION_ERROR_UNSUPPORTED = 3,
+ }
+
+ /**
* The result of signing a message with the attested key.
*/
parcelable SigningResult {
@@ -29,6 +50,9 @@
/** The DER-encoded attestation X509 certificate chain. */
byte[] certificateChain;
+
+ /** The status of the attestation. */
+ AttestationStatus status;
}
/**
diff --git a/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java b/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
index 2a771f3..a48fc81 100644
--- a/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
+++ b/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
@@ -41,7 +41,6 @@
import com.android.rkpdapp.testutil.SystemInterfaceSelector;
import com.android.rkpdapp.utils.Settings;
import com.android.rkpdapp.utils.X509Utils;
-import com.android.virt.vm_attestation.testservice.IAttestationService;
import com.android.virt.vm_attestation.testservice.IAttestationService.SigningResult;
import org.bouncycastle.asn1.ASN1Boolean;
@@ -62,7 +61,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
/**
@@ -171,35 +169,10 @@
Arrays.fill(challenge, (byte) 0xab);
// Act.
- CompletableFuture<Exception> exception = new CompletableFuture<>();
- CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
- CompletableFuture<SigningResult> signingResultFuture = new CompletableFuture<>();
- VmEventListener listener =
- new VmEventListener() {
- @Override
- public void onPayloadReady(VirtualMachine vm) {
- payloadReady.complete(true);
- try {
- IAttestationService service =
- IAttestationService.Stub.asInterface(
- vm.connectToVsockServer(IAttestationService.PORT));
- signingResultFuture.complete(
- service.signWithAttestationKey(challenge, MESSAGE.getBytes()));
- } catch (Exception e) {
- exception.complete(e);
- } finally {
- forceStop(vm);
- }
- }
- };
- listener.runToFinish(TAG, vm);
+ SigningResult signingResult =
+ runVmAttestationService(TAG, vm, challenge, MESSAGE.getBytes());
// Assert.
- assertThat(payloadReady.getNow(false)).isTrue();
- assertThat(exception.getNow(null)).isNull();
- SigningResult signingResult = signingResultFuture.getNow(null);
- assertThat(signingResult).isNotNull();
-
// Parsing the certificate chain successfully indicates that the certificate
// chain is valid, that each certificate is signed by the next one and the last
// one is self-signed.
diff --git a/service_vm/test_apk/src/native/main.rs b/service_vm/test_apk/src/native/main.rs
index a04fb1f..ff21bd8 100644
--- a/service_vm/test_apk/src/native/main.rs
+++ b/service_vm/test_apk/src/native/main.rs
@@ -18,7 +18,8 @@
use avflog::LogResult;
use com_android_virt_vm_attestation_testservice::{
aidl::com::android::virt::vm_attestation::testservice::IAttestationService::{
- BnAttestationService, IAttestationService, SigningResult::SigningResult, PORT,
+ AttestationStatus::AttestationStatus, BnAttestationService, IAttestationService,
+ SigningResult::SigningResult, PORT,
},
binder::{self, unstable_api::AsNative, BinderFeatures, Interface, IntoBinderResult, Strong},
};
@@ -103,14 +104,18 @@
challenge: &[u8],
message: &[u8],
) -> binder::Result<SigningResult> {
- let res = AttestationResult::request_attestation(challenge)
- .map_err(|e| anyhow!("Unexpected status: {:?}", status_to_cstr(e)))
- .with_log()
- .or_service_specific_exception(-1)?;
+ let res = match AttestationResult::request_attestation(challenge) {
+ Ok(res) => res,
+ Err(status) => {
+ let status = to_attestation_status(status);
+ return Ok(SigningResult { certificateChain: vec![], signature: vec![], status });
+ }
+ };
let certificate_chain =
res.certificate_chain().with_log().or_service_specific_exception(-1)?;
+ let status = AttestationStatus::ATTESTATION_OK;
let signature = res.sign(message).with_log().or_service_specific_exception(-1)?;
- Ok(SigningResult { certificateChain: certificate_chain, signature })
+ Ok(SigningResult { certificateChain: certificate_chain, signature, status })
}
fn validateAttestationResult(&self) -> binder::Result<()> {
@@ -119,6 +124,21 @@
}
}
+fn to_attestation_status(status: AVmAttestationStatus) -> AttestationStatus {
+ match status {
+ AVmAttestationStatus::ATTESTATION_OK => AttestationStatus::ATTESTATION_OK,
+ AVmAttestationStatus::ATTESTATION_ERROR_INVALID_CHALLENGE => {
+ AttestationStatus::ATTESTATION_ERROR_INVALID_CHALLENGE
+ }
+ AVmAttestationStatus::ATTESTATION_ERROR_ATTESTATION_FAILED => {
+ AttestationStatus::ATTESTATION_ERROR_ATTESTATION_FAILED
+ }
+ AVmAttestationStatus::ATTESTATION_ERROR_UNSUPPORTED => {
+ AttestationStatus::ATTESTATION_ERROR_UNSUPPORTED
+ }
+ }
+}
+
#[derive(Debug)]
struct AttestationResult(NonNull<AVmAttestationResult>);
diff --git a/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config.json b/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config.json
deleted file mode 100644
index c4fdc6e..0000000
--- a/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "task": {
- "type": "microdroid_launcher",
- "command": "MicrodroidIdleNativeLib.so"
- },
- "export_tombstones": true
-}
diff --git a/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config_io.json b/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config_io.json
deleted file mode 100644
index 34c204e..0000000
--- a/tests/benchmark/assets/microdroid_gki-android14-6.1/vm_config_io.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "task": {
- "type": "microdroid_launcher",
- "command": "MicrodroidBenchmarkNativeLib.so"
- },
- "apexes": [
- {
- "name": "com.android.virt"
- }
- ],
- "export_tombstones": true
-}
diff --git a/tests/benchmark/assets/microdroid/vm_config.json b/tests/benchmark/assets/vm_config.json
similarity index 76%
rename from tests/benchmark/assets/microdroid/vm_config.json
rename to tests/benchmark/assets/vm_config.json
index 5a604a9..d4c66d7 100644
--- a/tests/benchmark/assets/microdroid/vm_config.json
+++ b/tests/benchmark/assets/vm_config.json
@@ -1,7 +1,4 @@
{
- "os": {
- "name": "microdroid"
- },
"task": {
"type": "microdroid_launcher",
"command": "MicrodroidIdleNativeLib.so"
diff --git a/tests/benchmark/assets/microdroid/vm_config_io.json b/tests/benchmark/assets/vm_config_io.json
similarity index 82%
rename from tests/benchmark/assets/microdroid/vm_config_io.json
rename to tests/benchmark/assets/vm_config_io.json
index 66046ba..f982d41 100644
--- a/tests/benchmark/assets/microdroid/vm_config_io.json
+++ b/tests/benchmark/assets/vm_config_io.json
@@ -1,7 +1,4 @@
{
- "os": {
- "name": "microdroid"
- },
"task": {
"type": "microdroid_launcher",
"command": "MicrodroidBenchmarkNativeLib.so"
diff --git a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index acd6f2c..9cc1b7b 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -222,7 +222,6 @@
private void runBootTimeTest(
String name,
- String payloadConfig,
boolean fullDebug,
Function<VirtualMachineConfig.Builder, VirtualMachineConfig.Builder> fnConfig)
throws VirtualMachineException, InterruptedException, IOException {
@@ -261,7 +260,6 @@
throws VirtualMachineException, InterruptedException, IOException {
runBootTimeTest(
"test_vm_boot_time",
- "assets/" + os() + "/vm_config.json",
/* fullDebug */ false,
(builder) -> builder.setCpuTopology(CPU_TOPOLOGY_ONE_CPU));
}
@@ -270,7 +268,6 @@
throws VirtualMachineException, InterruptedException, IOException {
runBootTimeTest(
"test_vm_boot_time_host_topology",
- "assets/" + os() + "/vm_config.json",
/* fullDebug */ false,
(builder) -> builder.setCpuTopology(CPU_TOPOLOGY_MATCH_HOST));
}
@@ -280,7 +277,6 @@
throws VirtualMachineException, InterruptedException, IOException {
runBootTimeTest(
"test_vm_boot_time_debug",
- "assets/" + os() + "/vm_config.json",
/* fullDebug */ true,
(builder) -> builder);
}
@@ -298,7 +294,6 @@
assumeFeatureEnabled(VirtualMachineManager.FEATURE_VENDOR_MODULES);
runBootTimeTest(
"test_vm_boot_time_debug_with_vendor_partition",
- "assets/" + os() + "/vm_config.json",
/* fullDebug */ true,
(builder) -> builder.setVendorDiskImage(vendorDiskImage));
}
@@ -348,7 +343,7 @@
@Test
public void testVsockTransferFromHostToVM() throws Exception {
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
.setDebugLevel(DEBUG_LEVEL_NONE)
.build();
List<Double> transferRates = new ArrayList<>(IO_TEST_TRIAL_COUNT);
@@ -374,7 +369,7 @@
private void testVirtioBlkReadRate(boolean isRand) throws Exception {
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
.setDebugLevel(DEBUG_LEVEL_NONE)
.build();
List<Double> readRates = new ArrayList<>(IO_TEST_TRIAL_COUNT);
@@ -525,7 +520,7 @@
public void testMemoryUsage() throws Exception {
final String vmName = "test_vm_mem_usage";
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
.setDebugLevel(DEBUG_LEVEL_NONE)
.setMemoryBytes(256 * ONE_MEBI)
.build();
@@ -611,7 +606,7 @@
public void testMemoryReclaim() throws Exception {
final String vmName = "test_vm_mem_reclaim";
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
.setDebugLevel(DEBUG_LEVEL_NONE)
.setMemoryBytes(256 * ONE_MEBI)
.build();
@@ -836,7 +831,7 @@
@Test
public void testVmKillTime() throws Exception {
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_io.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config_io.json")
.setDebugLevel(DEBUG_LEVEL_NONE)
.build();
List<Double> vmKillTime = new ArrayList<>(TEST_TRIAL_COUNT);
diff --git a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
index f01a76b..b176cfc 100644
--- a/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
+++ b/tests/benchmark_hostside/java/android/avf/test/AVFHostTestCase.java
@@ -231,7 +231,7 @@
android.tryRun("rm", "-rf", MicrodroidHostTestCaseBase.TEST_ROOT);
// Donate 80% of the available device memory to the VM
- final String configPath = "assets/microdroid/vm_config.json";
+ final String configPath = "assets/vm_config.json";
final int vm_mem_mb = getFreeMemoryInfoMb(android) * 80 / 100;
ITestDevice microdroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
diff --git a/tests/helper/Android.bp b/tests/helper/Android.bp
index 614c70c..41d1ba2 100644
--- a/tests/helper/Android.bp
+++ b/tests/helper/Android.bp
@@ -16,6 +16,7 @@
"androidx.test.runner",
"androidx.test.ext.junit",
"com.android.microdroid.testservice-java",
+ "com.android.virt.vm_attestation.testservice-java",
"MicrodroidTestHelper",
"truth",
],
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index 2c92f04..b7e2b8f 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -43,6 +43,8 @@
import com.android.microdroid.test.common.DeviceProperties;
import com.android.microdroid.test.common.MetricsProcessor;
import com.android.microdroid.testservice.ITestService;
+import com.android.virt.vm_attestation.testservice.IAttestationService;
+import com.android.virt.vm_attestation.testservice.IAttestationService.SigningResult;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
@@ -127,6 +129,7 @@
public VirtualMachineConfig.Builder newVmConfigBuilderWithPayloadConfig(String configPath) {
return new VirtualMachineConfig.Builder(mCtx)
.setProtectedVm(mProtectedVm)
+ .setOs(os())
.setPayloadConfigPath(configPath);
}
@@ -523,6 +526,40 @@
}
}
+ protected SigningResult runVmAttestationService(
+ String logTag, VirtualMachine vm, byte[] challenge, byte[] messageToSign)
+ throws Exception {
+
+ CompletableFuture<Exception> exception = new CompletableFuture<>();
+ CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
+ CompletableFuture<SigningResult> signingResultFuture = new CompletableFuture<>();
+ VmEventListener listener =
+ new VmEventListener() {
+ @Override
+ public void onPayloadReady(VirtualMachine vm) {
+ payloadReady.complete(true);
+ try {
+ IAttestationService service =
+ IAttestationService.Stub.asInterface(
+ vm.connectToVsockServer(IAttestationService.PORT));
+ signingResultFuture.complete(
+ service.signWithAttestationKey(challenge, messageToSign));
+ } catch (Exception e) {
+ exception.complete(e);
+ } finally {
+ forceStop(vm);
+ }
+ }
+ };
+ listener.runToFinish(TAG, vm);
+
+ assertThat(payloadReady.getNow(false)).isTrue();
+ assertThat(exception.getNow(null)).isNull();
+ SigningResult signingResult = signingResultFuture.getNow(null);
+ assertThat(signingResult).isNotNull();
+ return signingResult;
+ }
+
protected TestResults runVmTestService(
String logTag, VirtualMachine vm, RunTestsAgainstTestService testsToRun)
throws Exception {
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 6dd3afe..a51bebe 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -153,7 +153,7 @@
throws Exception {
PayloadMetadata.write(
PayloadMetadata.metadata(
- "/mnt/apk/assets/" + mOs + "/vm_config.json",
+ "/mnt/apk/assets/vm_config.json",
PayloadMetadata.apk("microdroid-apk"),
apexes.stream()
.map(apex -> PayloadMetadata.apex(apex.name))
@@ -412,7 +412,7 @@
public void protectedVmRunsPvmfw() throws Exception {
// Arrange
assumeProtectedVm();
- final String configPath = "assets/" + mOs + "/vm_config_apex.json";
+ final String configPath = "assets/vm_config_apex.json";
// Act
mMicrodroidDevice =
@@ -421,6 +421,7 @@
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(true)
+ .gki(mGki)
.build(getAndroidDevice());
// Assert
@@ -548,6 +549,7 @@
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
+ .gki(mGki)
.build(getAndroidDevice());
mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT);
mMicrodroidDevice.enableAdbRoot();
@@ -569,7 +571,7 @@
assertThat(
isTombstoneGeneratedWithCmd(
mProtectedVm,
- "assets/" + mOs + "/vm_config.json",
+ "assets/vm_config.json",
"kill",
"-SIGSEGV",
"$(pidof microdroid_launcher)"))
@@ -583,7 +585,7 @@
assertThat(
isTombstoneGeneratedWithCmd(
mProtectedVm,
- "assets/" + mOs + "/vm_config_no_tombstone.json",
+ "assets/vm_config_no_tombstone.json",
"kill",
"-SIGSEGV",
"$(pidof microdroid_launcher)"))
@@ -597,7 +599,7 @@
assertThat(
isTombstoneGeneratedWithCmd(
mProtectedVm,
- "assets/" + mOs + "/vm_config.json",
+ "assets/vm_config.json",
"echo",
"c",
">",
@@ -636,6 +638,10 @@
if (protectedVm) {
cmd.add("--protected");
}
+ if (mGki != null) {
+ cmd.add("--gki");
+ cmd.add(mGki);
+ }
Collections.addAll(cmd, additionalArgs);
android.run(cmd.toArray(new String[0]));
@@ -667,10 +673,7 @@
private boolean isTombstoneGeneratedWithCrashConfig(boolean protectedVm, boolean debuggable)
throws Exception {
return isTombstoneGeneratedWithVmRunApp(
- protectedVm,
- debuggable,
- "--config-path",
- "assets/" + mOs + "/vm_config_crash.json");
+ protectedVm, debuggable, "--config-path", "assets/vm_config_crash.json");
}
@Test
@@ -705,13 +708,14 @@
// Create VM with microdroid
TestDevice device = getAndroidDevice();
- final String configPath = "assets/" + mOs + "/vm_config_apex.json"; // path inside the APK
+ final String configPath = "assets/vm_config_apex.json"; // path inside the APK
ITestDevice microdroid =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
.debugLevel("full")
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(mProtectedVm)
+ .gki(mGki)
.build(device);
microdroid.waitForBootComplete(BOOT_COMPLETE_TIMEOUT);
device.shutdownMicrodroid(microdroid);
@@ -797,7 +801,7 @@
getDevice().pullFileContents(CONSOLE_PATH) + getDevice().pullFileContents(LOG_PATH);
assertWithMessage("Unexpected denials during VM boot")
.that(logText)
- .doesNotContainMatch("avc:\s+denied");
+ .doesNotContainMatch("avc:\\s+denied");
assertThat(getDeviceNumCpus(microdroid)).isEqualTo(getDeviceNumCpus(android));
@@ -833,24 +837,26 @@
@Test
@CddTest(requirements = {"9.17/C-1-1", "9.17/C-1-2", "9.17/C/1-3"})
public void testMicrodroidBoots() throws Exception {
- final String configPath = "assets/" + mOs + "/vm_config.json"; // path inside the APK
+ final String configPath = "assets/vm_config.json"; // path inside the APK
testMicrodroidBootsWithBuilder(
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
.debugLevel("full")
.memoryMib(minMemorySize())
.cpuTopology("match_host")
- .protectedVm(mProtectedVm));
+ .protectedVm(mProtectedVm)
+ .gki(mGki));
}
@Test
public void testMicrodroidRamUsage() throws Exception {
- final String configPath = "assets/" + mOs + "/vm_config.json";
+ final String configPath = "assets/vm_config.json";
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
.debugLevel("full")
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(mProtectedVm)
+ .gki(mGki)
.build(getAndroidDevice());
mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT);
mMicrodroidDevice.enableAdbRoot();
@@ -1082,14 +1088,15 @@
}
private void launchWithDeviceAssignment(String device) throws Exception {
- final String configPath = "assets/" + mOs + "/vm_config.json";
+ final String configPath = "assets/vm_config.json";
MicrodroidBuilder builder =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
.debugLevel("full")
.memoryMib(minMemorySize())
.cpuTopology("match_host")
- .protectedVm(mProtectedVm);
+ .protectedVm(mProtectedVm)
+ .gki(mGki);
if (device != null) {
builder.addAssignableDevice(device);
}
diff --git a/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java b/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java
index a3216c2..541f5ec 100644
--- a/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java
+++ b/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java
@@ -50,8 +50,7 @@
@NonNull public static final String MICRODROID_DEBUG_FULL = "full";
@NonNull public static final String MICRODROID_DEBUG_NONE = "none";
- @NonNull
- public static final String MICRODROID_CONFIG_PATH = "assets/microdroid/vm_config_apex.json";
+ @NonNull public static final String MICRODROID_CONFIG_PATH = "assets/vm_config_apex.json";
@NonNull
public static final String VM_REFERENCE_DT_PATH = "/data/local/tmp/pvmfw/reference_dt.dtb";
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 732be94..1ed48d0 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -23,6 +23,7 @@
static_libs: [
"com.android.microdroid.testservice-java",
"com.android.microdroid.test.vmshare_service-java",
+ "com.android.virt.vm_attestation.testservice-java",
],
certificate: ":MicrodroidTestAppCert",
sdk_version: "test_current",
@@ -53,6 +54,7 @@
"MicrodroidExitNativeLib",
"MicrodroidPrivateLinkingNativeLib",
"MicrodroidCrashNativeLib",
+ "libvm_attestation_test_payload",
],
min_sdk_version: "33",
// Defined in ../vmshareapp/Android.bp
diff --git a/tests/testapk/assets/microdroid/vm_config_no_task.json b/tests/testapk/assets/microdroid/vm_config_no_task.json
deleted file mode 100644
index 3162bd0..0000000
--- a/tests/testapk/assets/microdroid/vm_config_no_task.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "os": {
- "name": "microdroid"
- },
- "export_tombstones": true
-}
diff --git a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config.json b/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config.json
deleted file mode 100644
index 2022127..0000000
--- a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "task": {
- "type": "microdroid_launcher",
- "command": "MicrodroidTestNativeLib.so"
- },
- "export_tombstones": true
-}
diff --git a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_apex.json b/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_apex.json
deleted file mode 100644
index bd3998d..0000000
--- a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_apex.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "task": {
- "type": "microdroid_launcher",
- "command": "MicrodroidTestNativeLib.so"
- },
- "apexes": [
- {
- "name": "com.android.art"
- },
- {
- "name": "com.android.compos"
- },
- {
- "name": "com.android.sdkext"
- }
- ],
- "export_tombstones": true
-}
diff --git a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_crash.json b/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_crash.json
deleted file mode 100644
index 4692258..0000000
--- a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_crash.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "task": {
- "type": "microdroid_launcher",
- "command": "MicrodroidCrashNativeLib.so"
- }
-}
diff --git a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_extra_apk.json b/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_extra_apk.json
deleted file mode 100644
index 1602294..0000000
--- a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_extra_apk.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "task": {
- "type": "microdroid_launcher",
- "command": "MicrodroidTestNativeLib.so"
- },
- "extra_apks": [
- {
- "path": "/system/etc/security/fsverity/BuildManifest.apk"
- }
- ],
- "export_tombstones": true
-}
diff --git a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_no_task.json b/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_no_task.json
deleted file mode 100644
index 8282f99..0000000
--- a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_no_task.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "export_tombstones": true
-}
diff --git a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_no_tombstone.json b/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_no_tombstone.json
deleted file mode 100644
index 6e8a136..0000000
--- a/tests/testapk/assets/microdroid_gki-android14-6.1/vm_config_no_tombstone.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "os": {
- "name": "microdroid_gki-android14-6.1"
- },
- "task": {
- "type": "microdroid_launcher",
- "command": "MicrodroidTestNativeLib.so"
- },
- "export_tombstones": false
-}
diff --git a/tests/testapk/assets/microdroid/vm_config.json b/tests/testapk/assets/vm_config.json
similarity index 76%
rename from tests/testapk/assets/microdroid/vm_config.json
rename to tests/testapk/assets/vm_config.json
index d12eb5c..90945a5 100644
--- a/tests/testapk/assets/microdroid/vm_config.json
+++ b/tests/testapk/assets/vm_config.json
@@ -1,7 +1,4 @@
{
- "os": {
- "name": "microdroid"
- },
"task": {
"type": "microdroid_launcher",
"command": "MicrodroidTestNativeLib.so"
diff --git a/tests/testapk/assets/microdroid/vm_config_apex.json b/tests/testapk/assets/vm_config_apex.json
similarity index 87%
rename from tests/testapk/assets/microdroid/vm_config_apex.json
rename to tests/testapk/assets/vm_config_apex.json
index c00787f..591bfea 100644
--- a/tests/testapk/assets/microdroid/vm_config_apex.json
+++ b/tests/testapk/assets/vm_config_apex.json
@@ -1,7 +1,4 @@
{
- "os": {
- "name": "microdroid"
- },
"task": {
"type": "microdroid_launcher",
"command": "MicrodroidTestNativeLib.so"
diff --git a/tests/testapk/assets/microdroid/vm_config_crash.json b/tests/testapk/assets/vm_config_crash.json
similarity index 71%
rename from tests/testapk/assets/microdroid/vm_config_crash.json
rename to tests/testapk/assets/vm_config_crash.json
index ce6af80..ef2a383 100644
--- a/tests/testapk/assets/microdroid/vm_config_crash.json
+++ b/tests/testapk/assets/vm_config_crash.json
@@ -1,7 +1,4 @@
{
- "os": {
- "name": "microdroid"
- },
"task": {
"type": "microdroid_launcher",
"command": "MicrodroidCrashNativeLib.so"
diff --git a/tests/testapk/assets/microdroid/vm_config_extra_apk.json b/tests/testapk/assets/vm_config_extra_apk.json
similarity index 84%
rename from tests/testapk/assets/microdroid/vm_config_extra_apk.json
rename to tests/testapk/assets/vm_config_extra_apk.json
index b45e57d..3e4bf2d 100644
--- a/tests/testapk/assets/microdroid/vm_config_extra_apk.json
+++ b/tests/testapk/assets/vm_config_extra_apk.json
@@ -1,7 +1,4 @@
{
- "os": {
- "name": "microdroid"
- },
"task": {
"type": "microdroid_launcher",
"command": "MicrodroidTestNativeLib.so"
diff --git a/tests/testapk/assets/vm_config_no_task.json b/tests/testapk/assets/vm_config_no_task.json
new file mode 100644
index 0000000..b71140e
--- /dev/null
+++ b/tests/testapk/assets/vm_config_no_task.json
@@ -0,0 +1,3 @@
+{
+ "export_tombstones": true
+}
diff --git a/tests/testapk/assets/microdroid/vm_config_no_tombstone.json b/tests/testapk/assets/vm_config_no_tombstone.json
similarity index 76%
rename from tests/testapk/assets/microdroid/vm_config_no_tombstone.json
rename to tests/testapk/assets/vm_config_no_tombstone.json
index 97e764d..a07ec89 100644
--- a/tests/testapk/assets/microdroid/vm_config_no_tombstone.json
+++ b/tests/testapk/assets/vm_config_no_tombstone.json
@@ -1,7 +1,4 @@
{
- "os": {
- "name": "microdroid"
- },
"task": {
"type": "microdroid_launcher",
"command": "MicrodroidTestNativeLib.so"
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 1337cb2..4714132 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -28,6 +28,8 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.TruthJUnit.assume;
+import com.android.virt.vm_attestation.testservice.IAttestationService.AttestationStatus;
+import com.android.virt.vm_attestation.testservice.IAttestationService.SigningResult;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -115,6 +117,8 @@
@RunWith(Parameterized.class)
public class MicrodroidTests extends MicrodroidDeviceTestBase {
private static final String TAG = "MicrodroidTests";
+ private static final String VM_ATTESTATION_PAYLOAD_PATH = "libvm_attestation_test_payload.so";
+ private static final String VM_ATTESTATION_MESSAGE = "Hello RKP from AVF!";
@Rule public Timeout globalTimeout = Timeout.seconds(300);
@@ -210,6 +214,47 @@
@Test
@CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ public void vmAttestationWhenRemoteAttestationIsSupported() throws Exception {
+ // pVM remote attestation is only supported on protected VMs.
+ assumeProtectedVM();
+ assumeFeatureEnabled(VirtualMachineManager.FEATURE_REMOTE_ATTESTATION);
+ assume().withMessage("Test needs Remote Attestation support")
+ .that(getVirtualMachineManager().isRemoteAttestationSupported())
+ .isTrue();
+ VirtualMachineConfig config =
+ newVmConfigBuilderWithPayloadBinary(VM_ATTESTATION_PAYLOAD_PATH)
+ .setProtectedVm(mProtectedVm)
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+ VirtualMachine vm =
+ forceCreateNewVirtualMachine("cts_attestation_with_rkpd_supported", config);
+
+ // Check with an invalid challenge.
+ byte[] invalidChallenge = new byte[65];
+ Arrays.fill(invalidChallenge, (byte) 0xbb);
+ SigningResult signingResultInvalidChallenge =
+ runVmAttestationService(
+ TAG, vm, invalidChallenge, VM_ATTESTATION_MESSAGE.getBytes());
+ assertThat(signingResultInvalidChallenge.status)
+ .isEqualTo(AttestationStatus.ATTESTATION_ERROR_INVALID_CHALLENGE);
+
+ // Check with a valid challenge.
+ byte[] challenge = new byte[32];
+ Arrays.fill(challenge, (byte) 0xac);
+ SigningResult signingResult =
+ runVmAttestationService(TAG, vm, challenge, VM_ATTESTATION_MESSAGE.getBytes());
+ assertWithMessage(
+ "VM attestation should either succeed or fail when the network is unstable")
+ .that(signingResult.status)
+ .isAnyOf(
+ AttestationStatus.ATTESTATION_OK,
+ AttestationStatus.ATTESTATION_ERROR_ATTESTATION_FAILED);
+ // TODO(b/330662600): Check the certificate chain and the signature after refactoring the
+ // x509 util method in RkpdVmAttestationTest.
+ }
+
+ @Test
+ @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
public void createAndRunNoDebugVm() throws Exception {
assumeSupportedDevice();
@@ -469,7 +514,7 @@
assertThat(minimal.isEncryptedStorageEnabled()).isFalse();
assertThat(minimal.getEncryptedStorageBytes()).isEqualTo(0);
assertThat(minimal.isVmOutputCaptured()).isEqualTo(false);
- assertThat(minimal.getOs()).isNull();
+ assertThat(minimal.getOs()).isEqualTo("microdroid");
// Maximal has everything that can be set to some non-default value. (And has different
// values than minimal for the required fields.)
@@ -484,7 +529,8 @@
.setMemoryBytes(42)
.setCpuTopology(CPU_TOPOLOGY_MATCH_HOST)
.setEncryptedStorageBytes(1_000_000)
- .setVmOutputCaptured(true);
+ .setVmOutputCaptured(true)
+ .setOs("microdroid_gki-android14-6.1");
VirtualMachineConfig maximal = maximalBuilder.build();
assertThat(maximal.getApkPath()).isEqualTo("/apk/path");
@@ -500,16 +546,11 @@
assertThat(maximal.isEncryptedStorageEnabled()).isTrue();
assertThat(maximal.getEncryptedStorageBytes()).isEqualTo(1_000_000);
assertThat(maximal.isVmOutputCaptured()).isEqualTo(true);
- assertThat(maximal.getOs()).isEqualTo("microdroid");
+ assertThat(maximal.getOs()).isEqualTo("microdroid_gki-android14-6.1");
assertThat(minimal.isCompatibleWith(maximal)).isFalse();
assertThat(minimal.isCompatibleWith(minimal)).isTrue();
assertThat(maximal.isCompatibleWith(maximal)).isTrue();
-
- VirtualMachineConfig os = maximalBuilder.setOs("microdroid_gki-android14-6.1").build();
- assertThat(os.getPayloadBinaryName()).isEqualTo("binary.so");
- assertThat(os.getOs()).isEqualTo("microdroid_gki-android14-6.1");
- assertThat(os.isCompatibleWith(maximal)).isFalse();
}
@Test
@@ -560,16 +601,6 @@
.setVmConsoleInputSupported(true);
e = assertThrows(IllegalStateException.class, () -> captureInputOnNonDebuggable.build());
assertThat(e).hasMessageThat().contains("debug level must be FULL to use console input");
-
- VirtualMachineConfig.Builder specifyBothOsAndConfig =
- new VirtualMachineConfig.Builder(getContext())
- .setPayloadConfigPath("config/path")
- .setProtectedVm(mProtectedVm)
- .setOs("microdroid");
- e = assertThrows(IllegalStateException.class, () -> specifyBothOsAndConfig.build());
- assertThat(e)
- .hasMessageThat()
- .contains("setPayloadConfigPath and setOs may not both be called");
}
@Test
@@ -787,7 +818,7 @@
revokePermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config.json")
.setMemoryBytes(minMemoryRequired())
.build();
@@ -905,7 +936,7 @@
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_extra_apk.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config_extra_apk.json")
.setMemoryBytes(minMemoryRequired())
.setDebugLevel(DEBUG_LEVEL_FULL)
.build();
@@ -1097,7 +1128,7 @@
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig normalConfig =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
.build();
forceCreateNewVirtualMachine("test_vm_a", normalConfig);
@@ -1123,7 +1154,7 @@
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig normalConfig =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
.build();
forceCreateNewVirtualMachine("test_vm", normalConfig);
@@ -1143,7 +1174,7 @@
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig normalConfig =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
.build();
VirtualMachine vm = forceCreateNewVirtualMachine("bcc_vm", normalConfig);
@@ -1286,7 +1317,7 @@
public void bootFailsWhenConfigIsInvalid() throws Exception {
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config_no_task.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config_no_task.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
.build();
@@ -1411,7 +1442,7 @@
// Arrange
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig config =
- newVmConfigBuilderWithPayloadConfig("assets/" + os() + "/vm_config.json")
+ newVmConfigBuilderWithPayloadConfig("assets/vm_config.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
.build();
String vmNameOrig = "test_vm_orig";
@@ -1700,9 +1731,7 @@
assumeSupportedDevice();
final VirtualMachineConfig vmConfig =
- new VirtualMachineConfig.Builder(getContext())
- .setProtectedVm(mProtectedVm)
- .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
.setDebugLevel(DEBUG_LEVEL_FULL)
.setVmConsoleInputSupported(true) // even if console input is supported
.build();
@@ -1724,9 +1753,7 @@
assumeSupportedDevice();
final VirtualMachineConfig vmConfig =
- new VirtualMachineConfig.Builder(getContext())
- .setProtectedVm(mProtectedVm)
- .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
.setDebugLevel(DEBUG_LEVEL_FULL)
.setVmOutputCaptured(true) // even if output is captured
.build();
@@ -1750,6 +1777,7 @@
.setPayloadBinaryName("MicrodroidTestNativeLib.so")
.setDebugLevel(debuggable ? DEBUG_LEVEL_FULL : DEBUG_LEVEL_NONE)
.setVmOutputCaptured(false)
+ .setOs(os())
.build();
final VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_logcat", vmConfig);
@@ -1844,6 +1872,7 @@
.setDebugLevel(DEBUG_LEVEL_FULL)
.setProtectedVm(isProtectedVm())
.setPayloadBinaryName("MicrodroidPayloadInOtherAppNativeLib.so")
+ .setOs(os())
.build();
try (VirtualMachine vm = forceCreateNewVirtualMachine("vm_from_another_app", config)) {
@@ -1958,6 +1987,7 @@
.setDebugLevel(DEBUG_LEVEL_FULL)
.setProtectedVm(isProtectedVm())
.setPayloadBinaryName("MicrodroidPayloadInOtherAppNativeLib.so")
+ .setOs(os())
.build();
VirtualMachine vm = forceCreateNewVirtualMachine("vm_to_share", config);
@@ -2007,6 +2037,7 @@
.setProtectedVm(isProtectedVm())
.setEncryptedStorageBytes(3_000_000)
.setPayloadBinaryName("MicrodroidPayloadInOtherAppNativeLib.so")
+ .setOs(os())
.build();
VirtualMachine vm = forceCreateNewVirtualMachine("vm_to_share", config);
diff --git a/tests/vmshareapp/AndroidManifest.xml b/tests/vmshareapp/AndroidManifest.xml
index b623f7f..9626599 100644
--- a/tests/vmshareapp/AndroidManifest.xml
+++ b/tests/vmshareapp/AndroidManifest.xml
@@ -16,6 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.microdroid.vmshare_app">
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
<uses-feature android:name="android.software.virtualization_framework"
android:required="false" />
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 6be219e..d0d3878 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -70,7 +70,7 @@
use glob::glob;
use lazy_static::lazy_static;
use log::{debug, error, info, warn};
-use microdroid_payload_config::{ApkConfig, OsConfig, Task, TaskType, VmPayloadConfig};
+use microdroid_payload_config::{ApkConfig, Task, TaskType, VmPayloadConfig};
use nix::unistd::pipe;
use rpcbinder::RpcServer;
use rustutils::system_properties;
@@ -313,6 +313,11 @@
fn enableTestAttestation(&self) -> binder::Result<()> {
GLOBAL_SERVICE.enableTestAttestation()
}
+
+ fn isRemoteAttestationSupported(&self) -> binder::Result<bool> {
+ check_manage_access()?;
+ GLOBAL_SERVICE.isRemoteAttestationSupported()
+ }
}
impl VirtualizationService {
@@ -622,13 +627,10 @@
// - specifying a config file;
// - specifying extra APKs;
// - specifying an OS other than Microdroid.
- match &config.payload {
+ (match &config.payload {
Payload::ConfigPath(_) => true,
- Payload::PayloadConfig(payload_config) => {
- !payload_config.extraApks.is_empty()
- || payload_config.osName != MICRODROID_OS_NAME
- }
- }
+ Payload::PayloadConfig(payload_config) => !payload_config.extraApks.is_empty(),
+ }) || config.osName != MICRODROID_OS_NAME
}
}
}
@@ -813,8 +815,13 @@
}
};
+ let payload_config_os = vm_payload_config.os.name.as_str();
+ if !payload_config_os.is_empty() && payload_config_os != "microdroid" {
+ bail!("'os' in payload config is deprecated");
+ }
+
// For now, the only supported OS is Microdroid and Microdroid GKI
- let os_name = vm_payload_config.os.name.as_str();
+ let os_name = config.osName.as_str();
if !is_valid_os(os_name) {
bail!("Unknown OS \"{}\"", os_name);
}
@@ -916,22 +923,13 @@
}
let task = Task { type_: TaskType::MicrodroidLauncher, command: payload_binary_name.clone() };
- let name = payload_config.osName.clone();
// The VM only cares about how many there are, these names are actually ignored.
let extra_apk_count = payload_config.extraApks.len();
let extra_apks =
(0..extra_apk_count).map(|i| ApkConfig { path: format!("extra-apk-{i}") }).collect();
- Ok(VmPayloadConfig {
- os: OsConfig { name },
- task: Some(task),
- apexes: vec![],
- extra_apks,
- prefer_staged: false,
- export_tombstones: None,
- enable_authfs: false,
- })
+ Ok(VmPayloadConfig { task: Some(task), extra_apks, ..Default::default() })
}
/// Generates a unique filename to use for a composite disk image.
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
index e11d8b8..e2063a9 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
@@ -86,4 +86,9 @@
* associated to the fake key pair when the VM requests attestation in testing mode.
*/
void enableTestAttestation();
+
+ /**
+ * Returns {@code true} if the pVM remote attestation feature is supported
+ */
+ boolean isRemoteAttestationSupported();
}
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index 29232ff..890535b 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -62,6 +62,15 @@
/** Detailed configuration for the VM, specifying how the payload will be run. */
Payload payload;
+ /**
+ * Name of the OS to run the payload. Currently "microdroid" and
+ * "microdroid_gki-android14-6.1" is supported.
+ *
+ * <p>Setting this field to a value other than "microdroid" requires
+ * android.permission.USE_CUSTOM_VIRTUAL_MACHINE
+ */
+ @utf8InCpp String osName = "microdroid";
+
enum DebugLevel {
/** Not debuggable at all */
NONE,
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
index 7ca5b62..efd363c 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
@@ -24,11 +24,6 @@
*/
@utf8InCpp String payloadBinaryName;
- /**
- * Name of the OS to run the payload. Currently "microdroid" and "microdroid_gki" is supported.
- */
- @utf8InCpp String osName = "microdroid";
-
/** Any extra APKs. */
List<ParcelFileDescriptor> extraApks;
}
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
index 8af881b..c6575c8 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
@@ -77,6 +77,11 @@
void enableTestAttestation();
/**
+ * Returns {@code true} if the pVM remote attestation feature is supported
+ */
+ boolean isRemoteAttestationSupported();
+
+ /**
* Get a list of assignable devices.
*/
AssignableDevice[] getAssignableDevices();
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 2fe14c0..05f3cf6 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -269,6 +269,13 @@
.context("Failed to generate ECDSA P-256 key pair for testing")
.with_log()
.or_service_specific_exception(-1)?;
+ // Wait until the service VM shuts down, so that the Service VM will be restarted when
+ // the key generated in the current session will be used for attestation.
+ // This ensures that different Service VM sessions have the same KEK for the key blob.
+ service_vm_manager::wait_until_service_vm_shuts_down()
+ .context("Failed to wait until the service VM shuts down")
+ .with_log()
+ .or_service_specific_exception(-1)?;
match res {
Response::GenerateEcdsaP256KeyPair(key_pair) => {
FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
@@ -299,6 +306,13 @@
))
.with_log();
}
+ if !remotely_provisioned_component_service_exists()? {
+ return Err(Status::new_exception_str(
+ ExceptionCode::UNSUPPORTED_OPERATION,
+ Some("AVF remotely provisioned component service is not declared"),
+ ))
+ .with_log();
+ }
info!("Received csr. Requestting attestation...");
let (key_blob, certificate_chain) = if test_mode {
check_use_custom_virtual_machine()?;
@@ -348,6 +362,10 @@
Ok(certificate_chain)
}
+ fn isRemoteAttestationSupported(&self) -> binder::Result<bool> {
+ remotely_provisioned_component_service_exists()
+ }
+
fn getAssignableDevices(&self) -> binder::Result<Vec<AssignableDevice>> {
check_use_custom_virtual_machine()?;
@@ -399,7 +417,7 @@
if let Some(sk_state) = &mut state.sk_state {
let user_id = multiuser_get_user_id(uid);
let app_id = multiuser_get_app_id(uid);
- info!("Recording potential existence of state for (user_id={user_id}, app_id={app_id}");
+ info!("Recording possible existence of state for (user_id={user_id}, app_id={app_id})");
if let Err(e) = sk_state.add_id(&id, user_id, app_id) {
error!("Failed to record the instance_id: {e:?}");
}
@@ -445,10 +463,16 @@
fn performReconciliation(
&self,
- _callback: &Strong<dyn IVirtualizationReconciliationCallback>,
+ callback: &Strong<dyn IVirtualizationReconciliationCallback>,
) -> binder::Result<()> {
- Err(anyhow!("performReconciliation not supported"))
- .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION)
+ let state = &mut *self.state.lock().unwrap();
+ if let Some(sk_state) = &mut state.sk_state {
+ info!("performReconciliation()");
+ sk_state.reconcile(callback).or_service_specific_exception(-1)?;
+ } else {
+ info!("ignoring performReconciliation()");
+ }
+ Ok(())
}
}
@@ -763,6 +787,10 @@
Ok(())
}
+fn remotely_provisioned_component_service_exists() -> binder::Result<bool> {
+ Ok(binder::is_declared(REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME)?)
+}
+
/// Checks whether the caller has a specific permission
fn check_permission(perm: &str) -> binder::Result<()> {
let calling_pid = get_calling_pid();
diff --git a/virtualizationservice/src/maintenance.rs b/virtualizationservice/src/maintenance.rs
index 0a367c5..219df7d 100644
--- a/virtualizationservice/src/maintenance.rs
+++ b/virtualizationservice/src/maintenance.rs
@@ -15,12 +15,20 @@
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::{
ISecretkeeper::ISecretkeeper, SecretId::SecretId,
};
-use anyhow::{Context, Result};
+use android_system_virtualizationmaintenance::aidl::android::system::virtualizationmaintenance;
+use anyhow::{anyhow, Context, Result};
+use binder::Strong;
use log::{error, info, warn};
+use virtualizationmaintenance::IVirtualizationReconciliationCallback::IVirtualizationReconciliationCallback;
mod vmdb;
use vmdb::{VmId, VmIdDb};
+/// Indicate whether an app ID belongs to a system core component.
+fn core_app_id(app_id: i32) -> bool {
+ app_id < 10000
+}
+
/// Interface name for the Secretkeeper HAL.
const SECRETKEEPER_SERVICE: &str = "android.hardware.security.secretkeeper.ISecretkeeper/default";
@@ -140,6 +148,79 @@
error!("failed to remove secret IDs from database: {e:?}");
}
}
+
+ /// Perform reconciliation to allow for possibly missed notifications of user or app removal.
+ pub fn reconcile(
+ &mut self,
+ callback: &Strong<dyn IVirtualizationReconciliationCallback>,
+ ) -> Result<()> {
+ // First, retrieve all (user_id, app_id) pairs that own a VM.
+ let owners = self.vm_id_db.get_all_owners().context("failed to retrieve owners from DB")?;
+ if owners.is_empty() {
+ info!("no VM owners, nothing to do");
+ return Ok(());
+ }
+
+ // Look for absent users.
+ let mut users: Vec<i32> = owners.iter().map(|(u, _a)| *u).collect();
+ users.sort();
+ users.dedup();
+ let users_exist = callback
+ .doUsersExist(&users)
+ .context(format!("failed to determine if {} users exist", users.len()))?;
+ if users_exist.len() != users.len() {
+ error!("callback returned {} bools for {} inputs!", users_exist.len(), users.len());
+ return Err(anyhow!("unexpected number of results from callback"));
+ }
+
+ for (user_id, present) in users.into_iter().zip(users_exist.into_iter()) {
+ if present {
+ // User is still present, but are all of the associated apps?
+ let mut apps: Vec<i32> = owners
+ .iter()
+ .filter_map(|(u, a)| if *u == user_id { Some(*a) } else { None })
+ .collect();
+ apps.sort();
+ apps.dedup();
+
+ let apps_exist = callback
+ .doAppsExist(user_id, &apps)
+ .context(format!("failed to check apps for user {user_id}"))?;
+ if apps_exist.len() != apps.len() {
+ error!(
+ "callback returned {} bools for {} inputs!",
+ apps_exist.len(),
+ apps.len()
+ );
+ return Err(anyhow!("unexpected number of results from callback"));
+ }
+
+ let missing_apps: Vec<i32> = apps
+ .iter()
+ .zip(apps_exist.into_iter())
+ .filter_map(|(app_id, present)| if present { None } else { Some(*app_id) })
+ .collect();
+
+ for app_id in missing_apps {
+ if core_app_id(app_id) {
+ info!("Skipping deletion for core app {app_id} for user {user_id}");
+ continue;
+ }
+ info!("App {app_id} for user {user_id} absent, deleting associated VM IDs");
+ if let Err(err) = self.delete_ids_for_app(user_id, app_id) {
+ error!("Failed to delete VM ID for user {user_id} app {app_id}: {err:?}");
+ }
+ }
+ } else {
+ info!("user {user_id} no longer present, deleting associated VM IDs");
+ if let Err(err) = self.delete_ids_for_user(user_id) {
+ error!("Failed to delete VM IDs for user {user_id} : {err:?}");
+ }
+ }
+ }
+
+ Ok(())
+ }
}
#[cfg(test)]
@@ -152,6 +233,9 @@
use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::{
ISecretkeeper::BnSecretkeeper
};
+ use virtualizationmaintenance::IVirtualizationReconciliationCallback::{
+ BnVirtualizationReconciliationCallback
+ };
/// Fake implementation of Secretkeeper that keeps a history of what operations were invoked.
#[derive(Default)]
@@ -195,12 +279,35 @@
State { sk, vm_id_db, batch_size }
}
+ struct Reconciliation {
+ gone_users: Vec<i32>,
+ gone_apps: Vec<i32>,
+ }
+
+ impl IVirtualizationReconciliationCallback for Reconciliation {
+ fn doUsersExist(&self, user_ids: &[i32]) -> binder::Result<Vec<bool>> {
+ Ok(user_ids.iter().map(|user_id| !self.gone_users.contains(user_id)).collect())
+ }
+ fn doAppsExist(&self, _user_id: i32, app_ids: &[i32]) -> binder::Result<Vec<bool>> {
+ Ok(app_ids.iter().map(|app_id| !self.gone_apps.contains(app_id)).collect())
+ }
+ }
+ impl binder::Interface for Reconciliation {}
+
const VM_ID1: VmId = [1u8; 64];
const VM_ID2: VmId = [2u8; 64];
const VM_ID3: VmId = [3u8; 64];
const VM_ID4: VmId = [4u8; 64];
const VM_ID5: VmId = [5u8; 64];
+ const USER1: i32 = 1;
+ const USER2: i32 = 2;
+ const USER3: i32 = 3;
+ const APP_A: i32 = 10050;
+ const APP_B: i32 = 10060;
+ const APP_C: i32 = 10070;
+ const CORE_APP_A: i32 = 45;
+
#[test]
fn test_sk_state_batching() {
let history = Arc::new(Mutex::new(Vec::new()));
@@ -228,13 +335,6 @@
#[test]
fn test_sk_state() {
- const USER1: i32 = 1;
- const USER2: i32 = 2;
- const USER3: i32 = 3;
- const APP_A: i32 = 50;
- const APP_B: i32 = 60;
- const APP_C: i32 = 70;
-
let history = Arc::new(Mutex::new(Vec::new()));
let mut sk_state = new_test_state(history.clone(), 2);
@@ -242,7 +342,7 @@
sk_state.vm_id_db.add_vm_id(&VM_ID2, USER1, APP_A).unwrap();
sk_state.vm_id_db.add_vm_id(&VM_ID3, USER2, APP_B).unwrap();
sk_state.vm_id_db.add_vm_id(&VM_ID4, USER3, APP_A).unwrap();
- sk_state.vm_id_db.add_vm_id(&VM_ID5, USER3, APP_C).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID5, USER3, APP_C).unwrap(); // Overwrites APP_A
assert_eq!((*history.lock().unwrap()).clone(), vec![]);
sk_state.delete_ids_for_app(USER2, APP_B).unwrap();
@@ -260,4 +360,71 @@
assert_eq!(empty, sk_state.vm_id_db.vm_ids_for_app(USER2, APP_B).unwrap());
assert_eq!(empty, sk_state.vm_id_db.vm_ids_for_user(USER3).unwrap());
}
+
+ #[test]
+ fn test_sk_state_reconcile() {
+ let history = Arc::new(Mutex::new(Vec::new()));
+ let mut sk_state = new_test_state(history.clone(), 20);
+
+ sk_state.vm_id_db.add_vm_id(&VM_ID1, USER1, APP_A).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID2, USER1, APP_A).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID3, USER2, APP_B).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID4, USER2, CORE_APP_A).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID5, USER3, APP_C).unwrap();
+
+ assert_eq!(vec![VM_ID1, VM_ID2], sk_state.vm_id_db.vm_ids_for_user(USER1).unwrap());
+ assert_eq!(vec![VM_ID1, VM_ID2], sk_state.vm_id_db.vm_ids_for_app(USER1, APP_A).unwrap());
+ assert_eq!(vec![VM_ID3], sk_state.vm_id_db.vm_ids_for_app(USER2, APP_B).unwrap());
+ assert_eq!(vec![VM_ID5], sk_state.vm_id_db.vm_ids_for_user(USER3).unwrap());
+
+ // Perform a reconciliation and pretend that USER1 and [CORE_APP_A, APP_B] are gone.
+ let reconciliation =
+ Reconciliation { gone_users: vec![USER1], gone_apps: vec![CORE_APP_A, APP_B] };
+ let callback = BnVirtualizationReconciliationCallback::new_binder(
+ reconciliation,
+ binder::BinderFeatures::default(),
+ );
+ sk_state.reconcile(&callback).unwrap();
+
+ let empty: Vec<VmId> = Vec::new();
+ assert_eq!(empty, sk_state.vm_id_db.vm_ids_for_user(USER1).unwrap());
+ assert_eq!(empty, sk_state.vm_id_db.vm_ids_for_app(USER1, APP_A).unwrap());
+ // VM for core app stays even though it's reported as absent.
+ assert_eq!(vec![VM_ID4], sk_state.vm_id_db.vm_ids_for_user(USER2).unwrap());
+ assert_eq!(empty, sk_state.vm_id_db.vm_ids_for_app(USER2, APP_B).unwrap());
+ assert_eq!(vec![VM_ID5], sk_state.vm_id_db.vm_ids_for_user(USER3).unwrap());
+ }
+
+ struct Irreconcilable;
+
+ impl IVirtualizationReconciliationCallback for Irreconcilable {
+ fn doUsersExist(&self, user_ids: &[i32]) -> binder::Result<Vec<bool>> {
+ panic!("doUsersExist called with {user_ids:?}");
+ }
+ fn doAppsExist(&self, user_id: i32, app_ids: &[i32]) -> binder::Result<Vec<bool>> {
+ panic!("doAppsExist called with {user_id:?}, {app_ids:?}");
+ }
+ }
+ impl binder::Interface for Irreconcilable {}
+
+ #[test]
+ fn test_sk_state_reconcile_not_needed() {
+ let history = Arc::new(Mutex::new(Vec::new()));
+ let mut sk_state = new_test_state(history.clone(), 20);
+
+ sk_state.vm_id_db.add_vm_id(&VM_ID1, USER1, APP_A).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID2, USER1, APP_A).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID3, USER2, APP_B).unwrap();
+ sk_state.vm_id_db.add_vm_id(&VM_ID5, USER3, APP_C).unwrap();
+ sk_state.delete_ids_for_user(USER1).unwrap();
+ sk_state.delete_ids_for_user(USER2).unwrap();
+ sk_state.delete_ids_for_user(USER3).unwrap();
+
+ // No extant secrets, so reconciliation should not trigger the callback.
+ let callback = BnVirtualizationReconciliationCallback::new_binder(
+ Irreconcilable,
+ binder::BinderFeatures::default(),
+ );
+ sk_state.reconcile(&callback).unwrap();
+ }
}
diff --git a/virtualizationservice/src/maintenance/vmdb.rs b/virtualizationservice/src/maintenance/vmdb.rs
index ce1e1e7..47704bc 100644
--- a/virtualizationservice/src/maintenance/vmdb.rs
+++ b/virtualizationservice/src/maintenance/vmdb.rs
@@ -265,12 +265,41 @@
while let Some(row) = rows.next().context("failed row unpack")? {
match row.get(0) {
Ok(vm_id) => vm_ids.push(vm_id),
- Err(e) => log::error!("failed to parse row: {e:?}"),
+ Err(e) => error!("failed to parse row: {e:?}"),
}
}
Ok(vm_ids)
}
+
+ /// Return all of the `(user_id, app_id)` pairs present in the database.
+ pub fn get_all_owners(&mut self) -> Result<Vec<(i32, i32)>> {
+ let mut stmt = self
+ .conn
+ .prepare("SELECT DISTINCT user_id, app_id FROM main.vmids;")
+ .context("failed to prepare SELECT stmt")?;
+ let mut rows = stmt.query(()).context("query failed")?;
+ let mut owners: Vec<(i32, i32)> = Vec::new();
+ while let Some(row) = rows.next().context("failed row unpack")? {
+ let user_id = match row.get(0) {
+ Ok(v) => v,
+ Err(e) => {
+ error!("failed to parse row: {e:?}");
+ continue;
+ }
+ };
+ let app_id = match row.get(1) {
+ Ok(v) => v,
+ Err(e) => {
+ error!("failed to parse row: {e:?}");
+ continue;
+ }
+ };
+ owners.push((user_id, app_id));
+ }
+
+ Ok(owners)
+ }
}
/// Current schema version.
@@ -417,7 +446,13 @@
db.add_vm_id(&VM_ID3, USER1, APP_A).unwrap();
db.add_vm_id(&VM_ID4, USER2, APP_B).unwrap();
db.add_vm_id(&VM_ID5, USER3, APP_A).unwrap();
- db.add_vm_id(&VM_ID5, USER3, APP_C).unwrap();
+ db.add_vm_id(&VM_ID5, USER3, APP_C).unwrap(); // Overwrites APP_A
+
+ assert_eq!(
+ vec![(USER1, APP_A), (USER2, APP_B), (USER3, APP_C)],
+ db.get_all_owners().unwrap()
+ );
+
let empty: Vec<VmId> = Vec::new();
assert_eq!(vec![VM_ID1, VM_ID2, VM_ID3], db.vm_ids_for_user(USER1).unwrap());
@@ -447,6 +482,12 @@
assert_eq!(vec![VM_ID5], db.vm_ids_for_user(USER3).unwrap());
assert_eq!(empty, db.vm_ids_for_user(USER_UNKNOWN).unwrap());
assert_eq!(empty, db.vm_ids_for_app(USER1, APP_UNKNOWN).unwrap());
+
+ assert_eq!(
+ vec![(USER1, APP_A), (USER2, APP_B), (USER3, APP_C)],
+ db.get_all_owners().unwrap()
+ );
+
show_contents(&db);
}
diff --git a/virtualizationservice/src/rkpvm.rs b/virtualizationservice/src/rkpvm.rs
index 67ba740..6898921 100644
--- a/virtualizationservice/src/rkpvm.rs
+++ b/virtualizationservice/src/rkpvm.rs
@@ -21,28 +21,25 @@
use service_vm_comm::{
ClientVmAttestationParams, GenerateCertificateRequestParams, Request, Response,
};
-use service_vm_manager::ServiceVm;
+use service_vm_manager::process_request;
pub(crate) fn request_attestation(
csr: Vec<u8>,
remotely_provisioned_key_blob: Vec<u8>,
remotely_provisioned_cert: Vec<u8>,
) -> Result<Vec<u8>> {
- let mut vm = ServiceVm::start()?;
-
let params =
ClientVmAttestationParams { csr, remotely_provisioned_key_blob, remotely_provisioned_cert };
let request = Request::RequestClientVmAttestation(params);
- match vm.process_request(request).context("Failed to process request")? {
+ match process_request(request).context("Failed to process request")? {
Response::RequestClientVmAttestation(cert) => Ok(cert),
other => bail!("Incorrect response type {other:?}"),
}
}
pub(crate) fn generate_ecdsa_p256_key_pair() -> Result<Response> {
- let mut vm = ServiceVm::start()?;
let request = Request::GenerateEcdsaP256KeyPair;
- vm.process_request(request).context("Failed to process request")
+ process_request(request).context("Failed to process request")
}
pub(crate) fn generate_certificate_request(
@@ -55,6 +52,5 @@
};
let request = Request::GenerateCertificateRequest(params);
- let mut vm = ServiceVm::start()?;
- vm.process_request(request).context("Failed to process request")
+ process_request(request).context("Failed to process request")
}
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 063f992..bc05ec3 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -33,9 +33,6 @@
use std::num::NonZeroU16;
use std::path::{Path, PathBuf};
-#[derive(Debug)]
-struct Idsigs(Vec<PathBuf>);
-
#[derive(Args, Default)]
/// Collection of flags that are at VM level and therefore applicable to all subcommands
pub struct CommonConfig {
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 57b7641..07e0276 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -127,29 +127,25 @@
if config.payload_binary_name.is_some() {
bail!("Only one of --config-path or --payload-binary-name can be defined")
}
- if config.microdroid.gki().is_some() {
- bail!("--gki cannot be defined with --config-path. Use 'os' field in the config file")
- }
Payload::ConfigPath(config_path)
} else if let Some(payload_binary_name) = config.payload_binary_name {
- let os_name = if let Some(ver) = config.microdroid.gki() {
- format!("microdroid_gki-{ver}")
- } else {
- "microdroid".to_owned()
- };
-
let extra_apk_files: Result<Vec<_>, _> = extra_apks.iter().map(File::open).collect();
let extra_apk_fds = extra_apk_files?.into_iter().map(ParcelFileDescriptor::new).collect();
Payload::PayloadConfig(VirtualMachinePayloadConfig {
payloadBinaryName: payload_binary_name,
- osName: os_name,
extraApks: extra_apk_fds,
})
} else {
bail!("Either --config-path or --payload-binary-name must be defined")
};
+ let os_name = if let Some(ver) = config.microdroid.gki() {
+ format!("microdroid_gki-{ver}")
+ } else {
+ "microdroid".to_owned()
+ };
+
let payload_config_str = format!("{:?}!{:?}", config.apk, payload);
let custom_config = CustomConfig {
@@ -180,6 +176,7 @@
memoryMib: config.common.mem.unwrap_or(0) as i32, // 0 means use the VM default
cpuTopology: config.common.cpu_topology,
customConfig: Some(custom_config),
+ osName: os_name,
});
run(
service.as_ref(),