Merge "Define multialg variants of the libdiced_open_dice targets." into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
index c427337..efe651e 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
@@ -18,21 +18,12 @@
import android.app.Application as AndroidApplication
import android.app.NotificationChannel
import android.app.NotificationManager
-import android.content.ComponentName
import android.content.Context
-import android.content.Intent
-import android.content.ServiceConnection
-import android.os.IBinder
-import androidx.lifecycle.DefaultLifecycleObserver
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.ProcessLifecycleOwner
public class Application : AndroidApplication() {
override fun onCreate() {
super.onCreate()
setupNotificationChannels()
- val lifecycleObserver = ApplicationLifecycleObserver()
- ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleObserver)
}
private fun setupNotificationChannels() {
@@ -61,45 +52,4 @@
fun getInstance(c: Context): Application = c.getApplicationContext() as Application
}
-
- /**
- * Observes application lifecycle events and interacts with the VmLauncherService to manage
- * virtual machine state based on application lifecycle transitions. This class binds to the
- * VmLauncherService and notifies it of application lifecycle events (onStart, onStop), allowing
- * the service to manage the VM accordingly.
- */
- inner class ApplicationLifecycleObserver() : DefaultLifecycleObserver {
- private var vmLauncherService: VmLauncherService? = null
- private val connection =
- object : ServiceConnection {
- override fun onServiceConnected(className: ComponentName, service: IBinder) {
- val binder = service as VmLauncherService.VmLauncherServiceBinder
- vmLauncherService = binder.getService()
- }
-
- override fun onServiceDisconnected(arg0: ComponentName) {
- vmLauncherService = null
- }
- }
-
- override fun onCreate(owner: LifecycleOwner) {
- super.onCreate(owner)
- bindToVmLauncherService()
- }
-
- override fun onStart(owner: LifecycleOwner) {
- super.onStart(owner)
- vmLauncherService?.processAppLifeCycleEvent(ApplicationLifeCycleEvent.APP_ON_START)
- }
-
- override fun onStop(owner: LifecycleOwner) {
- vmLauncherService?.processAppLifeCycleEvent(ApplicationLifeCycleEvent.APP_ON_STOP)
- super.onStop(owner)
- }
-
- fun bindToVmLauncherService() {
- val intent = Intent(this@Application, VmLauncherService::class.java)
- this@Application.bindService(intent, connection, 0) // No BIND_AUTO_CREATE
- }
- }
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ApplicationLifeCycleEvent.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ApplicationLifeCycleEvent.kt
deleted file mode 100644
index 4e26c3c..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ApplicationLifeCycleEvent.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2025 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.virtualization.terminal
-
-enum class ApplicationLifeCycleEvent {
- APP_ON_START,
- APP_ON_STOP,
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
index 887ae02..e035ad4 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
@@ -28,6 +28,7 @@
import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse
import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest
import com.android.virtualization.terminal.proto.ShutdownRequestItem
+import io.grpc.stub.ServerCallStreamObserver
import io.grpc.stub.StreamObserver
internal class DebianServiceImpl(context: Context) : DebianServiceImplBase() {
@@ -79,8 +80,15 @@
request: ShutdownQueueOpeningRequest?,
responseObserver: StreamObserver<ShutdownRequestItem?>,
) {
+ val serverCallStreamObserver = responseObserver as ServerCallStreamObserver<ShutdownRequestItem?>
+ serverCallStreamObserver.setOnCancelHandler {
+ shutdownRunnable = null
+ }
Log.d(TAG, "openShutdownRequestQueue")
shutdownRunnable = Runnable {
+ if (serverCallStreamObserver.isCancelled()) {
+ return@Runnable
+ }
responseObserver.onNext(ShutdownRequestItem.newBuilder().build())
responseObserver.onCompleted()
shutdownRunnable = null
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
index be1f922..54754ff 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
@@ -146,8 +146,8 @@
companion object {
private const val DIR_IN_SDCARD = "linux"
private const val ARCHIVE_NAME = "images.tar.gz"
- private const val BUILD_TAG = "latest" // TODO: use actual tag name
- private const val HOST_URL = "https://dl.google.com/android/ferrochrome/$BUILD_TAG"
+ private val BUILD_TAG = Integer.toString(Build.VERSION.SDK_INT_FULL)
+ private val HOST_URL = "https://dl.google.com/android/ferrochrome/$BUILD_TAG"
fun getSdcardPathForTesting(): Path {
return Environment.getExternalStoragePublicDirectory(DIR_IN_SDCARD).toPath()
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
index 662fef5..35c5570 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -29,7 +29,6 @@
import android.os.ConditionVariable
import android.os.Environment
import android.os.SystemProperties
-import android.os.Trace
import android.provider.Settings
import android.util.DisplayMetrics
import android.util.Log
@@ -328,7 +327,7 @@
val stopIntent = Intent()
stopIntent.setClass(this, VmLauncherService::class.java)
- stopIntent.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE)
+ stopIntent.setAction(VmLauncherService.ACTION_SHUTDOWN_VM)
val stopPendingIntent =
PendingIntent.getService(
this,
@@ -363,7 +362,6 @@
)
.build()
- Trace.beginAsyncSection("executeTerminal", 0)
run(this, this, notification, getDisplayInfo())
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt
new file mode 100644
index 0000000..7647d9b
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.system.virtualmachine.VirtualMachine
+import android.util.Log
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.ProcessLifecycleOwner
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.util.concurrent.Executors
+import java.util.concurrent.ScheduledFuture
+import java.util.concurrent.TimeUnit
+
+/**
+ * MemBalloonController is responsible for adjusting the memory ballon size of a VM depending on
+ * whether the app is visible or running in the background
+ */
+class MemBalloonController(val context: Context, val vm: VirtualMachine) {
+ companion object {
+ private const val INITIAL_PERCENT = 10
+ private const val MAX_PERCENT = 50
+ private const val INFLATION_STEP_PERCENT = 5
+ private const val INFLATION_PERIOD_SEC = 60L
+
+ private val mainHandler = Handler(Looper.getMainLooper())
+
+ private fun runOnMainThread(runnable: Runnable) {
+ mainHandler.post(runnable)
+ }
+ }
+
+ private val executor =
+ Executors.newSingleThreadScheduledExecutor(
+ TerminalThreadFactory(context.getApplicationContext())
+ )
+
+ private val observer =
+ object : DefaultLifecycleObserver {
+
+ // If the app is started or resumed, give deflate the balloon to 0 to give maximum
+ // available memory to the virtual machine
+ override fun onResume(owner: LifecycleOwner) {
+ ongoingInflation?.cancel(false)
+ executor.submit({
+ Log.v(TAG, "app resumed. deflating mem balloon to the minimum")
+ vm.setMemoryBalloonByPercent(0)
+ })
+ }
+
+ // If the app goes into background, progressively inflate the balloon from
+ // INITIAL_PERCENT until it reaches MAX_PERCENT
+ override fun onStop(owner: LifecycleOwner) {
+ ongoingInflation?.cancel(false)
+ balloonPercent = INITIAL_PERCENT
+ ongoingInflation =
+ executor.scheduleAtFixedRate(
+ {
+ if (balloonPercent <= MAX_PERCENT) {
+ Log.v(TAG, "inflating mem balloon to ${balloonPercent} %")
+ vm.setMemoryBalloonByPercent(balloonPercent)
+ balloonPercent += INFLATION_STEP_PERCENT
+ } else {
+ Log.v(TAG, "mem balloon is inflated to its max (${MAX_PERCENT} %)")
+ ongoingInflation!!.cancel(false)
+ }
+ },
+ 0 /* initialDelay */,
+ INFLATION_PERIOD_SEC,
+ TimeUnit.SECONDS,
+ )
+ }
+ }
+
+ private var balloonPercent = 0
+ private var ongoingInflation: ScheduledFuture<*>? = null
+
+ fun start() {
+ // addObserver is @MainThread
+ runOnMainThread({ ProcessLifecycleOwner.get().lifecycle.addObserver(observer) })
+ }
+
+ fun stop() {
+ // removeObserver is @MainThread
+ runOnMainThread({
+ ProcessLifecycleOwner.get().lifecycle.removeObserver(observer)
+ executor.shutdown()
+ })
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt
index 5c01ead..7e78235 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt
@@ -19,7 +19,6 @@
import android.graphics.Bitmap
import android.net.http.SslError
import android.os.Bundle
-import android.os.Trace
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@@ -145,7 +144,6 @@
object : WebView.VisualStateCallback() {
override fun onComplete(completedRequestId: Long) {
if (completedRequestId == requestId) {
- Trace.endAsyncSection("executeTerminal", 0)
bootProgressView.visibility = View.GONE
terminalView.visibility = View.VISIBLE
terminalView.mapTouchToMouseEvent()
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 94b7011..1857175 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -31,14 +31,13 @@
import android.os.Parcel
import android.os.Parcelable
import android.os.ResultReceiver
-import android.os.Trace
+import android.os.SystemProperties
import android.system.virtualmachine.VirtualMachine
import android.system.virtualmachine.VirtualMachineCustomImageConfig
import android.system.virtualmachine.VirtualMachineCustomImageConfig.AudioConfig
import android.system.virtualmachine.VirtualMachineException
import android.util.Log
import android.widget.Toast
-import com.android.internal.annotations.GuardedBy
import com.android.system.virtualmachine.flags.Flags.terminalGuiSupport
import com.android.virtualization.terminal.MainActivity.Companion.TAG
import com.android.virtualization.terminal.Runner.Companion.create
@@ -55,7 +54,6 @@
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
-import java.lang.Math.min
import java.lang.RuntimeException
import java.net.InetSocketAddress
import java.net.SocketAddress
@@ -66,55 +64,14 @@
import java.util.concurrent.TimeUnit
class VmLauncherService : Service() {
- inner class VmLauncherServiceBinder : android.os.Binder() {
- fun getService(): VmLauncherService = this@VmLauncherService
- }
-
- private val binder = VmLauncherServiceBinder()
+ private lateinit var executorService: ExecutorService
// TODO: using lateinit for some fields to avoid null
- private var executorService: ExecutorService? = null
private var virtualMachine: VirtualMachine? = null
private var resultReceiver: ResultReceiver? = null
private var server: Server? = null
private var debianService: DebianServiceImpl? = null
private var portNotifier: PortNotifier? = null
- private var mLock = Object()
- @GuardedBy("mLock") private var currentMemBalloonPercent = 0
-
- @GuardedBy("mLock") private val inflateMemBalloonHandler = Handler(Looper.getMainLooper())
- private val inflateMemBalloonTask: Runnable =
- object : Runnable {
- override fun run() {
- synchronized(mLock) {
- if (
- currentMemBalloonPercent < INITIAL_MEM_BALLOON_PERCENT ||
- currentMemBalloonPercent > MAX_MEM_BALLOON_PERCENT
- ) {
- Log.e(
- TAG,
- "currentBalloonPercent=$currentMemBalloonPercent is invalid," +
- " should be in range: " +
- "$INITIAL_MEM_BALLOON_PERCENT~$MAX_MEM_BALLOON_PERCENT",
- )
- return
- }
- // Increases the balloon size by MEM_BALLOON_PERCENT_STEP% every time
- if (currentMemBalloonPercent < MAX_MEM_BALLOON_PERCENT) {
- currentMemBalloonPercent =
- min(
- MAX_MEM_BALLOON_PERCENT,
- currentMemBalloonPercent + MEM_BALLOON_PERCENT_STEP,
- )
- virtualMachine?.setMemoryBalloonByPercent(currentMemBalloonPercent)
- inflateMemBalloonHandler.postDelayed(
- this,
- MEM_BALLOON_INFLATE_INTERVAL_MILLIS,
- )
- }
- }
- }
- }
interface VmLauncherServiceCallback {
fun onVmStart()
@@ -127,49 +84,16 @@
}
override fun onBind(intent: Intent?): IBinder? {
- return binder
+ return null
}
- /**
- * Processes application lifecycle events and adjusts the virtual machine's memory balloon
- * accordingly.
- *
- * @param event The application lifecycle event.
- */
- fun processAppLifeCycleEvent(event: ApplicationLifeCycleEvent) {
- when (event) {
- // When the app starts, reset the memory balloon to 0%.
- // This gives the app maximum available memory.
- ApplicationLifeCycleEvent.APP_ON_START -> {
- synchronized(mLock) {
- inflateMemBalloonHandler.removeCallbacks(inflateMemBalloonTask)
- currentMemBalloonPercent = 0
- virtualMachine?.setMemoryBalloonByPercent(currentMemBalloonPercent)
- }
- }
- ApplicationLifeCycleEvent.APP_ON_STOP -> {
- // When the app stops, inflate the memory balloon to INITIAL_MEM_BALLOON_PERCENT.
- // Inflate the balloon by MEM_BALLOON_PERCENT_STEP every
- // MEM_BALLOON_INFLATE_INTERVAL_MILLIS milliseconds until reaching
- // MAX_MEM_BALLOON_PERCENT of total memory. This allows the system to reclaim
- // memory while the app is in the background.
- synchronized(mLock) {
- currentMemBalloonPercent = INITIAL_MEM_BALLOON_PERCENT
- virtualMachine?.setMemoryBalloonByPercent(currentMemBalloonPercent)
- inflateMemBalloonHandler.postDelayed(
- inflateMemBalloonTask,
- MEM_BALLOON_INFLATE_INTERVAL_MILLIS,
- )
- }
- }
- else -> {
- Log.e(TAG, "unrecognized lifecycle event: $event")
- }
- }
+ override fun onCreate() {
+ super.onCreate()
+ executorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- if (intent.action == ACTION_STOP_VM_LAUNCHER_SERVICE) {
+ if (intent.action == ACTION_SHUTDOWN_VM) {
if (debianService != null && debianService!!.shutdownDebian()) {
// During shutdown, change the notification content to indicate that it's closing
val notification = createNotificationForTerminalClose()
@@ -185,7 +109,6 @@
Log.d(TAG, "VM instance is already started")
return START_NOT_STICKY
}
- executorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
val image = InstalledImage.getDefault(this)
val json = ConfigJson.from(this, image.configPath)
@@ -201,15 +124,12 @@
}
val config = configBuilder.build()
- Trace.beginSection("vmCreate")
val runner: Runner =
try {
create(this, config)
} catch (e: VirtualMachineException) {
throw RuntimeException("cannot create runner", e)
}
- Trace.endSection()
- Trace.beginAsyncSection("debianBoot", 0)
virtualMachine = runner.vm
resultReceiver =
@@ -218,12 +138,16 @@
ResultReceiver::class.java,
)
+ val mbc = MemBalloonController(this, virtualMachine!!)
+ mbc.start()
+
runner.exitStatus.thenAcceptAsync { success: Boolean ->
+ mbc.stop()
resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
stopSelf()
}
val logDir = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
- Logger.setup(virtualMachine!!, logDir, executorService!!)
+ Logger.setup(virtualMachine!!, logDir, executorService)
val notification =
intent.getParcelableExtra<Notification?>(EXTRA_NOTIFICATION, Notification::class.java)
@@ -300,7 +224,7 @@
private fun createNotificationForTerminalClose(): Notification {
val stopIntent = Intent()
stopIntent.setClass(this, VmLauncherService::class.java)
- stopIntent.setAction(ACTION_STOP_VM_LAUNCHER_SERVICE)
+ stopIntent.setAction(ACTION_SHUTDOWN_VM)
val stopPendingIntent =
PendingIntent.getService(
this,
@@ -423,7 +347,7 @@
return
}
- executorService!!.execute(
+ executorService.execute(
Runnable {
// TODO(b/373533555): we can use mDNS for that.
val debianServicePortFile = File(filesDir, "debian_service_port")
@@ -451,10 +375,9 @@
Log.e(TAG, "failed to stop a VM instance", e)
}
}
- executorService?.shutdownNow()
- executorService = null
virtualMachine = null
}
+ executorService.shutdownNow()
super.onDestroy()
}
@@ -468,8 +391,7 @@
private const val ACTION_START_VM_LAUNCHER_SERVICE =
"android.virtualization.START_VM_LAUNCHER_SERVICE"
const val EXTRA_DISPLAY_INFO = "EXTRA_DISPLAY_INFO"
- const val ACTION_STOP_VM_LAUNCHER_SERVICE: String =
- "android.virtualization.STOP_VM_LAUNCHER_SERVICE"
+ const val ACTION_SHUTDOWN_VM: String = "android.virtualization.ACTION_SHUTDOWN_VM"
private const val RESULT_START = 0
private const val RESULT_STOP = 1
@@ -479,12 +401,18 @@
private const val KEY_TERMINAL_IPADDRESS = "address"
private const val KEY_TERMINAL_PORT = "port"
- private const val VM_BOOT_TIMEOUT_SECONDS = 20
+ private val VM_BOOT_TIMEOUT_SECONDS: Int =
+ {
+ val deviceName = SystemProperties.get("ro.product.vendor.device", "")
+ val cuttlefish = deviceName.startsWith("vsoc_")
+ val goldfish = deviceName.startsWith("emu64")
- private const val INITIAL_MEM_BALLOON_PERCENT = 10
- private const val MAX_MEM_BALLOON_PERCENT = 50
- private const val MEM_BALLOON_INFLATE_INTERVAL_MILLIS = 60000L
- private const val MEM_BALLOON_PERCENT_STEP = 5
+ if (cuttlefish || goldfish) {
+ 3 * 60
+ } else {
+ 30
+ }
+ }()
private fun getMyIntent(context: Context): Intent {
return Intent(context.getApplicationContext(), VmLauncherService::class.java)
@@ -530,7 +458,7 @@
fun stop(context: Context) {
val i = getMyIntent(context)
- i.setAction(ACTION_STOP_VM_LAUNCHER_SERVICE)
+ i.setAction(ACTION_SHUTDOWN_VM)
context.startService(i)
}
}
diff --git a/guest/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index 9afbcc3..30624cd 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -41,7 +41,6 @@
use alloc::boxed::Box;
use bssl_avf::Digester;
use diced_open_dice::{bcc_handover_parse, DiceArtifacts, DiceContext, Hidden, VM_KEY_ALGORITHM};
-use hypervisor_backends::get_mem_sharer;
use libfdt::Fdt;
use log::{debug, error, info, trace, warn};
use pvmfw_avb::verify_payload;
@@ -99,15 +98,7 @@
}
let guest_page_size = verified_boot_data.page_size.unwrap_or(SIZE_4KB);
- // TODO(ptosi): Cache the (single?) granule once, in vmbase.
- let hyp_page_size = if let Some(mem_sharer) = get_mem_sharer() {
- Some(mem_sharer.granule().map_err(|e| {
- error!("Failed to get granule size: {e}");
- RebootReason::InternalError
- })?)
- } else {
- None
- };
+ let hyp_page_size = hypervisor_backends::get_granule_size();
let _ =
sanitize_device_tree(untrusted_fdt, vm_dtbo, vm_ref_dt, guest_page_size, hyp_page_size)?;
let fdt = untrusted_fdt; // DT has now been sanitized.
diff --git a/libs/libhypervisor_backends/src/hypervisor.rs b/libs/libhypervisor_backends/src/hypervisor.rs
index aa65133..7c274f5 100644
--- a/libs/libhypervisor_backends/src/hypervisor.rs
+++ b/libs/libhypervisor_backends/src/hypervisor.rs
@@ -152,3 +152,8 @@
pub fn get_device_assigner() -> Option<&'static dyn DeviceAssigningHypervisor> {
get_hypervisor().as_device_assigner()
}
+
+/// Gets the unique hypervisor granule size, if any.
+pub fn get_granule_size() -> Option<usize> {
+ get_hypervisor().get_granule_size()
+}
diff --git a/libs/libhypervisor_backends/src/hypervisor/common.rs b/libs/libhypervisor_backends/src/hypervisor/common.rs
index bfe638f..f229e14 100644
--- a/libs/libhypervisor_backends/src/hypervisor/common.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/common.rs
@@ -32,6 +32,13 @@
fn as_device_assigner(&self) -> Option<&dyn DeviceAssigningHypervisor> {
None
}
+
+ /// Returns the granule used by all APIs (MEM_SHARE, MMIO_GUARD, device assignment, ...).
+ ///
+ /// If no such API is supported or if they support different granule sizes, returns None.
+ fn get_granule_size(&self) -> Option<usize> {
+ None
+ }
}
pub trait MmioGuardedHypervisor {
diff --git a/libs/libhypervisor_backends/src/hypervisor/geniezone.rs b/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
index 76e010b..0913ff3 100644
--- a/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
@@ -84,6 +84,10 @@
fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
Some(self)
}
+
+ fn get_granule_size(&self) -> Option<usize> {
+ <Self as MemSharingHypervisor>::granule(self).ok()
+ }
}
impl MmioGuardedHypervisor for GeniezoneHypervisor {
diff --git a/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs b/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
index 233097b..f183107 100644
--- a/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
@@ -90,6 +90,10 @@
fn as_device_assigner(&self) -> Option<&dyn DeviceAssigningHypervisor> {
Some(self)
}
+
+ fn get_granule_size(&self) -> Option<usize> {
+ <Self as MemSharingHypervisor>::granule(self).ok()
+ }
}
impl MmioGuardedHypervisor for ProtectedKvmHypervisor {
diff --git a/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs b/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
index 7f9ea4d..d72f788 100644
--- a/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
@@ -84,6 +84,10 @@
fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
Some(self)
}
+
+ fn get_granule_size(&self) -> Option<usize> {
+ <Self as MemSharingHypervisor>::granule(self).ok()
+ }
}
macro_rules! vmcall {
diff --git a/libs/libhypervisor_backends/src/lib.rs b/libs/libhypervisor_backends/src/lib.rs
index 33dc5ad..3c81ac8 100644
--- a/libs/libhypervisor_backends/src/lib.rs
+++ b/libs/libhypervisor_backends/src/lib.rs
@@ -24,5 +24,6 @@
pub use error::{Error, Result};
pub use hypervisor::{
- get_device_assigner, get_mem_sharer, get_mmio_guard, DeviceAssigningHypervisor, KvmError,
+ get_device_assigner, get_granule_size, get_mem_sharer, get_mmio_guard,
+ DeviceAssigningHypervisor, KvmError,
};