Snap for 13264465 from 01c814f2dddf9fa881d6af18e4a77359e60acd7e to 25Q2-release
Change-Id: Ia31e03175d21cb44b37a3052cdcda030c796f9af
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
index 0a1090d..fe92854 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.content.Intent
import android.os.Bundle
+import android.text.method.ScrollingMovementMethod
import android.view.View
import android.widget.TextView
import java.io.IOException
@@ -34,6 +35,7 @@
val button = findViewById<View>(R.id.recovery)
button.setOnClickListener(View.OnClickListener { _ -> launchRecoveryActivity() })
+ findViewById<TextView>(R.id.cause).setMovementMethod(ScrollingMovementMethod())
}
override fun onNewIntent(intent: Intent) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
index 542265a..14855ac 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -194,7 +194,7 @@
fun closeTab(tab: TabLayout.Tab) {
if (terminalTabAdapter.tabs.size == 1) {
- finishAndRemoveTask()
+ finish()
}
viewPager.offscreenPageLimit -= 1
terminalTabAdapter.deleteTab(tab.position)
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 190acc7..161a534 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -117,6 +117,9 @@
const SECRETKEEPER_IDENTIFIER: &str =
"android.hardware.security.secretkeeper.ISecretkeeper/default";
+const VM_CAPABILITIES_HAL_IDENTIFIER: &str =
+ "android.hardware.virtualization.capabilities.IVmCapabilitiesService/default";
+
const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE";
/// crosvm requires all partitions to be a multiple of 4KiB.
@@ -765,10 +768,11 @@
}
}
- // TODO(b/391774181): handle vendor tee services (which require talking to HAL) as well.
- if !vendor_tee_services.is_empty() {
- return Err(anyhow!("support for vendor tee services is coming soon!"))
- .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+ if !vendor_tee_services.is_empty() && !is_vm_capabilities_hal_supported() {
+ return Err(anyhow!(
+ "requesting access to tee services requires {VM_CAPABILITIES_HAL_IDENTIFIER}"
+ ))
+ .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
}
// TODO(b/391774181): remove this check in a follow-up patch.
@@ -1011,6 +1015,7 @@
enable_hypervisor_specific_auth_method: config.enableHypervisorSpecificAuthMethod,
instance_id,
custom_memory_backing_files,
+ start_suspended: !vendor_tee_services.is_empty(),
};
let instance = Arc::new(
VmInstance::new(
@@ -1019,6 +1024,7 @@
requester_uid,
requester_debug_pid,
vm_context,
+ vendor_tee_services,
)
.with_context(|| format!("Failed to create VM with config {:?}", config))
.with_log()
@@ -1719,6 +1725,16 @@
fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine::IVirtualMachine> {
BnVirtualMachine::new_binder(VirtualMachine { instance }, BinderFeatures::default())
}
+
+ fn handle_vendor_tee_services(&self) -> binder::Result<()> {
+ // TODO(b/360102915): get vm_fd from crosvm
+ // TODO(b/360102915): talk to HAL
+ self.instance
+ .resume_full()
+ .with_context(|| format!("Error resuming VM with CID {}", self.instance.cid))
+ .with_log()
+ .or_service_specific_exception(-1)
+ }
}
impl Interface for VirtualMachine {}
@@ -1761,7 +1777,12 @@
.start()
.with_context(|| format!("Error starting VM with CID {}", self.instance.cid))
.with_log()
- .or_service_specific_exception(-1)
+ .or_service_specific_exception(-1)?;
+ if !self.instance.vendor_tee_services.is_empty() {
+ self.handle_vendor_tee_services()
+ } else {
+ Ok(())
+ }
}
fn stop(&self) -> binder::Result<()> {
@@ -2338,6 +2359,11 @@
.expect("Could not check for declared Secretkeeper interface")
}
+fn is_vm_capabilities_hal_supported() -> bool {
+ binder::is_declared(VM_CAPABILITIES_HAL_IDENTIFIER)
+ .expect("failed to check if {VM_CAPABILITIES_HAL_IDENTIFIER} is present")
+}
+
impl VirtualMachineService {
fn new_binder(state: Arc<Mutex<State>>, cid: Cid) -> Strong<dyn IVirtualMachineService> {
BnVirtualMachineService::new_binder(
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index 15a4199..c264185 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -142,6 +142,7 @@
pub instance_id: [u8; 64],
// (memfd, guest address, size)
pub custom_memory_backing_files: Vec<(OwnedFd, u64, u64)>,
+ pub start_suspended: bool,
}
#[derive(Debug)]
@@ -419,6 +420,8 @@
pub vm_metric: Mutex<VmMetric>,
// Whether virtio-balloon is enabled
pub balloon_enabled: bool,
+ /// List of vendor tee services this VM might access.
+ pub vendor_tee_services: Vec<String>,
/// The latest lifecycle state which the payload reported itself to be in.
payload_state: Mutex<PayloadState>,
/// Represents the condition that payload_state was updated
@@ -446,6 +449,7 @@
requester_uid: u32,
requester_debug_pid: i32,
vm_context: VmContext,
+ vendor_tee_services: Vec<String>,
) -> Result<VmInstance, Error> {
validate_config(&config)?;
let cid = config.cid;
@@ -473,6 +477,7 @@
payload_state_updated: Condvar::new(),
requester_uid_name,
balloon_enabled,
+ vendor_tee_services,
};
info!("{} created", &instance);
Ok(instance)
@@ -826,6 +831,18 @@
}
Ok(())
}
+
+ /// Performs full resume of VM.
+ pub fn resume_full(&self) -> Result<(), Error> {
+ let socket_path_cstring = path_to_cstring(&self.crosvm_control_socket_path);
+ // SAFETY: Pointer is valid for the lifetime of the call.
+ let success =
+ unsafe { crosvm_control::crosvm_client_resume_vm_full(socket_path_cstring.as_ptr()) };
+ if !success {
+ bail!("Failed to resume VM");
+ }
+ Ok(())
+ }
}
impl Rss {
@@ -1431,6 +1448,10 @@
}
}
+ if config.start_suspended {
+ command.arg("--suspended");
+ }
+
print_crosvm_args(&command);
let result = SharedChild::spawn(&mut command)?;
diff --git a/android/virtmgr/src/debug_config.rs b/android/virtmgr/src/debug_config.rs
index 6e2bfef..e552cf4 100644
--- a/android/virtmgr/src/debug_config.rs
+++ b/android/virtmgr/src/debug_config.rs
@@ -191,7 +191,7 @@
impl DebugConfig {
pub fn new(config: &VirtualMachineConfig) -> Self {
let debug_level = get_debug_level(config).unwrap_or(DebugLevel::NONE);
- let debug_policy = Self::get_debug_policy().unwrap_or_else(|| {
+ let debug_policy = Self::get_debug_policy(config).unwrap_or_else(|| {
info!("Debug policy is disabled");
Default::default()
});
@@ -204,7 +204,11 @@
Self { debug_level, debug_policy, dump_device_tree }
}
- fn get_debug_policy() -> Option<DebugPolicy> {
+ fn get_debug_policy(config: &VirtualMachineConfig) -> Option<DebugPolicy> {
+ if matches!(config, VirtualMachineConfig::RawConfig(_)) {
+ info!("Debug policy ignored for non-Microdroid VM");
+ return None;
+ }
let dp_sysprop = system_properties::read(CUSTOM_DEBUG_POLICY_OVERLAY_SYSPROP);
let custom_dp = dp_sysprop.unwrap_or_else(|e| {
warn!("Failed to read sysprop {CUSTOM_DEBUG_POLICY_OVERLAY_SYSPROP}: {e}");
diff --git a/build/microdroid/Android.bp b/build/microdroid/Android.bp
index 9152091..fac212a 100644
--- a/build/microdroid/Android.bp
+++ b/build/microdroid/Android.bp
@@ -476,19 +476,6 @@
src: ":microdroid_16k_initrd_debuggable",
}
-soong_config_module_type {
- name: "flag_aware_avb_add_hash_footer_defaults",
- module_type: "avb_add_hash_footer_defaults",
- config_namespace: "ANDROID",
- bool_variables: [
- "release_avf_enable_llpvm_changes",
- ],
- properties: [
- "rollback_index",
- "props",
- ],
-}
-
avb_add_hash_footer_defaults {
name: "microdroid_kernel_signed_defaults",
src: ":empty_file",
@@ -508,44 +495,27 @@
MICRODROID_GKI_ROLLBACK_INDEX = 2
-flag_aware_avb_add_hash_footer_defaults {
+avb_add_hash_footer_defaults {
name: "microdroid_kernel_cap_defaults",
// Below are properties that are conditionally set depending on value of build flags.
- soong_config_variables: {
- release_avf_enable_llpvm_changes: {
- rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
- props: [
- {
- name: "com.android.virt.cap",
- value: "secretkeeper_protection",
- },
- ],
+ props: [
+ {
+ name: "com.android.virt.cap",
+ value: "secretkeeper_protection",
},
- },
+ ],
+ rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
}
-flag_aware_avb_add_hash_footer_defaults {
+avb_add_hash_footer_defaults {
name: "microdroid_kernel_cap_with_uefi_defaults",
- // Below are properties that are conditionally set depending on value of build flags.
- soong_config_variables: {
- release_avf_enable_llpvm_changes: {
- rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
- props: [
- {
- name: "com.android.virt.cap",
- value: "secretkeeper_protection|supports_uefi_boot",
- },
- ],
- conditions_default: {
- props: [
- {
- name: "com.android.virt.cap",
- value: "supports_uefi_boot",
- },
- ],
- },
+ rollback_index: MICRODROID_GKI_ROLLBACK_INDEX,
+ props: [
+ {
+ name: "com.android.virt.cap",
+ value: "secretkeeper_protection|supports_uefi_boot",
},
- },
+ ],
}
avb_add_hash_footer {
diff --git a/libs/apexutil/src/lib.rs b/libs/apexutil/src/lib.rs
index 639135f..9ae5f2b 100644
--- a/libs/apexutil/src/lib.rs
+++ b/libs/apexutil/src/lib.rs
@@ -179,7 +179,7 @@
// The expected hex values were generated when we ran the method the first time.
assert_eq!(
hex::encode(res.root_digest),
- "54265da77ae1fd619e39809ad99fedc576bb20c0c7a8002190fa64438436299f"
+ "0cdeee606f2c9b468900e07d306384605684e6ca0b8bc6c51592808de9fd1c44"
);
assert_eq!(
hex::encode(res.public_key),
diff --git a/libs/libvmbase/Android.bp b/libs/libvmbase/Android.bp
index 2d0294e..c02466e 100644
--- a/libs/libvmbase/Android.bp
+++ b/libs/libvmbase/Android.bp
@@ -83,6 +83,7 @@
"liblibfdt_nostd",
"liblog_rust_nostd",
"libonce_cell_nostd",
+ "libsafe_mmio",
"libspin_nostd",
"libstatic_assertions",
"libthiserror_nostd",
diff --git a/libs/libvmbase/src/arch.rs b/libs/libvmbase/src/arch.rs
index cc42939..29d3a32 100644
--- a/libs/libvmbase/src/arch.rs
+++ b/libs/libvmbase/src/arch.rs
@@ -38,25 +38,6 @@
#[cfg(target_arch = "aarch64")]
pub use aarch64_paging::paging::VirtualAddress;
-/// Write with well-defined compiled behavior.
-///
-/// See https://github.com/rust-lang/rust/issues/131894
-///
-/// # Safety
-///
-/// `dst` must be valid for writes.
-#[inline]
-pub unsafe fn write_volatile_u8(dst: *mut u8, src: u8) {
- cfg_if::cfg_if! {
- if #[cfg(target_arch = "aarch64")] {
- // SAFETY: `dst` is valid for writes.
- unsafe { aarch64::strb(dst, src) }
- } else {
- compile_error!("Unsupported target_arch")
- }
- }
-}
-
/// Flush `size` bytes of data cache by virtual address.
#[inline]
pub(crate) fn flush_region(start: usize, size: usize) {
diff --git a/libs/libvmbase/src/arch/aarch64.rs b/libs/libvmbase/src/arch/aarch64.rs
index 9c4d256..de3bfa8 100644
--- a/libs/libvmbase/src/arch/aarch64.rs
+++ b/libs/libvmbase/src/arch/aarch64.rs
@@ -119,26 +119,6 @@
}};
}
-/// STRB intrinsics.
-///
-/// See https://github.com/rust-lang/rust/issues/131894
-///
-/// # Safety
-///
-/// `dst` must be valid for writes.
-#[inline]
-pub unsafe fn strb(dst: *mut u8, src: u8) {
- // SAFETY: strb only modifies *dst, which must be valid for writes.
- unsafe {
- core::arch::asm!(
- "strb {value:w}, [{ptr}]",
- value = in(reg) src,
- ptr = in(reg) dst,
- options(preserves_flags),
- );
- }
-}
-
/// Reads the number of words in the smallest cache line of all the data caches and unified caches.
#[inline]
pub fn min_dcache_line_size() -> usize {
diff --git a/libs/libvmbase/src/arch/aarch64/uart.rs b/libs/libvmbase/src/arch/aarch64/uart.rs
index 2ef7d7e..0e94fc6 100644
--- a/libs/libvmbase/src/arch/aarch64/uart.rs
+++ b/libs/libvmbase/src/arch/aarch64/uart.rs
@@ -14,36 +14,29 @@
//! Uart driver with backend for aarch64 using MMIO
-use crate::arch::write_volatile_u8;
use crate::uart::UartBackend;
+use core::ptr::NonNull;
+use safe_mmio::{fields::ReadWrite, UniqueMmioPointer};
/// Alias for default Uart for aarch64 backend with [`MmioBackend`]
-pub type Uart = crate::uart::Uart<MmioBackend>;
+pub type Uart = crate::uart::Uart<MmioBackend<'static>>;
-/// Backend for [`crate::uart::Uart`] that uses [`crate::arch::write_volatile_u8`] for writing to
-/// hardware registers.
-pub struct MmioBackend {
- base_address: *mut u8,
+/// Backend for [`crate::uart::Uart`] that uses `safe-mmio` for writing to hardware registers.
+pub struct MmioBackend<'a> {
+ registers: UniqueMmioPointer<'a, [ReadWrite<u8>; 8]>,
}
-impl MmioBackend {
- /// Constructs a new instance of the UART driver backend for a device at the given base address.
- ///
- /// # Safety
- ///
- /// The given base address must point to the 8 MMIO control registers of an appropriate UART
- /// device, which must be mapped into the address space of the process as device memory and not
- /// have any other aliases.
- pub unsafe fn new(base_address: usize) -> Self {
- Self { base_address: base_address as *mut u8 }
+impl<'a> MmioBackend<'a> {
+ /// Constructs a new instance of the UART driver backend for a device with the given data
+ /// register.
+ pub fn new(registers: UniqueMmioPointer<'a, [ReadWrite<u8>; 8]>) -> Self {
+ Self { registers }
}
}
-impl UartBackend for MmioBackend {
- fn write_register_u8(&self, offset: usize, byte: u8) {
- // SAFETY: We know that the base address points to the control registers of a UART device
- // which is appropriately mapped.
- unsafe { write_volatile_u8(self.base_address.add(offset), byte) }
+impl UartBackend for MmioBackend<'_> {
+ fn write_register_u8(&mut self, offset: usize, byte: u8) {
+ self.registers.get(offset).expect("Register offset out of bounds").write(byte);
}
}
@@ -52,15 +45,15 @@
///
/// # Safety
///
- /// The given base address must point to the 8 MMIO control registers of an appropriate UART
- /// device, which must be mapped into the address space of the process as device memory and not
- /// have any other aliases.
+ /// The given base address must point to the 8 MMIO control registers of an appropriate 8250
+ /// UART device, which must be mapped into the address space of the process as device memory and
+ /// not have any other aliases.
pub unsafe fn new(base_address: usize) -> Self {
- // SAFETY: Delegated to caller
- unsafe { Self::create(MmioBackend::new(base_address)) }
+ // SAFETY: The caller promises that base_address points to a mapped 8250 UART's registers
+ // with no aliases. That implies that there are 8 single-byte registers we can safely
+ // access, as required by `UniqueMmioPointer`.
+ let data_register =
+ unsafe { UniqueMmioPointer::new(NonNull::new(base_address as _).unwrap()) };
+ Self::create(MmioBackend::new(data_register))
}
}
-
-// SAFETY: `MmioBackend` just contains a pointer to device memory, which can be accessed from any
-// context.
-unsafe impl Send for MmioBackend {}
diff --git a/libs/libvmbase/src/uart.rs b/libs/libvmbase/src/uart.rs
index 857a22e..6a256ea 100644
--- a/libs/libvmbase/src/uart.rs
+++ b/libs/libvmbase/src/uart.rs
@@ -20,7 +20,7 @@
/// The backend for [`Uart`] that abstracts the access to 8250 register map
pub trait UartBackend {
/// Writes a byte value on the offset to the hardware registers.
- fn write_register_u8(&self, offset: usize, byte: u8);
+ fn write_register_u8(&mut self, offset: usize, byte: u8);
}
/// Minimal driver for an 8250 UART. This only implements enough to work with the emulated 8250
@@ -36,7 +36,7 @@
}
/// Writes a single byte to the UART.
- pub fn write_byte(&self, byte: u8) {
+ pub fn write_byte(&mut self, byte: u8) {
self.backend.write_register_u8(0, byte)
}
}
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
index 7eb7748..7c1091d 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
@@ -230,8 +230,12 @@
public boolean isFeatureEnabled(String feature) throws Exception {
CommandRunner android = new CommandRunner(getDevice());
- String result = android.run(VIRT_APEX + "bin/vm", "check-feature-enabled", feature);
- return result.contains("enabled");
+ String cmd = VIRT_APEX + "bin/vm check-feature-enabled " + feature;
+ CommandResult result = android.runForResult(cmd);
+ assumeTrue(
+ "Failed to run" + cmd + " " + result,
+ result.getStatus() == CommandStatus.SUCCESS && result.getExitCode() == 0);
+ return result.getStdout().trim().contains("Feature " + feature + " is enabled");
}
public List<AssignableDevice> getAssignableDevices() throws Exception {