Merge "Use LazyLock rather than lazy_static." into main
diff --git a/android/LinuxInstaller/Android.bp b/android/LinuxInstaller/Android.bp
index 5f34c63..f70452d 100644
--- a/android/LinuxInstaller/Android.bp
+++ b/android/LinuxInstaller/Android.bp
@@ -13,6 +13,7 @@
required: [
"privapp-permissions-linuxinstaller.xml",
],
+ certificate: ":com.android.virtualization.linuxinstaller_certificate",
}
android_app {
@@ -24,6 +25,7 @@
required: [
"privapp-permissions-linuxinstaller.xml",
],
+ certificate: ":com.android.virtualization.linuxinstaller_certificate",
}
prebuilt_etc {
@@ -32,3 +34,8 @@
sub_dir: "permissions",
system_ext_specific: true,
}
+
+android_app_certificate {
+ name: "com.android.virtualization.linuxinstaller_certificate",
+ certificate: "com_android_virtualization_linuxinstaller",
+}
diff --git a/android/LinuxInstaller/AndroidManifest.xml b/android/LinuxInstaller/AndroidManifest.xml
index 5b10d9e..e5653f6 100644
--- a/android/LinuxInstaller/AndroidManifest.xml
+++ b/android/LinuxInstaller/AndroidManifest.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.virtualization.linuxinstaller" >
+ package="com.android.virtualization.linuxinstaller"
+ android:versionCode="2100000000" >
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
<queries>
diff --git a/android/LinuxInstaller/com_android_virtualization_linuxinstaller.pk8 b/android/LinuxInstaller/com_android_virtualization_linuxinstaller.pk8
new file mode 100644
index 0000000..3f74303
--- /dev/null
+++ b/android/LinuxInstaller/com_android_virtualization_linuxinstaller.pk8
Binary files differ
diff --git a/android/LinuxInstaller/com_android_virtualization_linuxinstaller.x509.pem b/android/LinuxInstaller/com_android_virtualization_linuxinstaller.x509.pem
new file mode 100644
index 0000000..3ca64b7
--- /dev/null
+++ b/android/LinuxInstaller/com_android_virtualization_linuxinstaller.x509.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEETCCAvmgAwIBAgIUfBxyELS+ri3QErq8DXHu+47xx4EwDQYJKoZIhvcNAQEL
+BQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwH
+QW5kcm9pZDEyMDAGA1UEAwwpY29tX2FuZHJvaWRfdmlydHVhbGl6YXRpb25fbGlu
+dXhpbnN0YWxsZXIwIBcNMjQwODMwMTIyNjU2WhgPMjA1MjAxMTYxMjI2NTZaMIGW
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEUMBIGA1UECgwLR29vZ2xlIEluYy4xEDAOBgNVBAsMB0FuZHJv
+aWQxMjAwBgNVBAMMKWNvbV9hbmRyb2lkX3ZpcnR1YWxpemF0aW9uX2xpbnV4aW5z
+dGFsbGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8V/rH9ju6Wce
+1BdWuxfWaLmZJHGShXeDO6MB86Wrm10m26j9PFzd8/8FRKsZaujZphwNZsqBsdlt
+pWeNKts9T9luZn19Ci4E8A2EtgSxmfI8Fjwj/OJHHO0hG5+JcwIlUnmFQPcGtu/r
+EL3i7SfcF2ok+IC6aKYohnSbo+YkjyCSwb39i6POe6v6cPIZJtmOnecThS+fYCYR
+2yoMSSr3Bf8ayySrG0pJp7xZ1I5NixK6hUFZhQRLusyiv/KYTpAElMd+n1YJEYbf
+pW30DYAu+31S0hx8JXncFmI0uG3Zxx+LgNQwY8OPV6NPFfVwMPluZR6ep0tZ6q7e
+KIV2w5uC7QIDAQABo1MwUTAdBgNVHQ4EFgQU6FBYv7mW+9DR9q0c9uS4NNdX4Acw
+HwYDVR0jBBgwFoAU6FBYv7mW+9DR9q0c9uS4NNdX4AcwDwYDVR0TAQH/BAUwAwEB
+/zANBgkqhkiG9w0BAQsFAAOCAQEAj3bvUpwKjvpCggXzjMNkn7fAaQ0s1BubnkFe
+ge4zwz4tObP3OGRcxt5V9R5EZ7UY6bPcybA/rfg9FCzjcUQOBjmuepcQpbNHFW2I
+lasFa42UHkHSUFzeg2n9UC5iO3B+sclOr4EPaEE4HbG4B2vj++BYMW3C7PDyHc7R
+fq5ZsEEWcYUa8qZCO46I8AbMZ8iv1HpR4mZeQMkSxhD3uVHDQW+VqDTpzne/YBkJ
+yNfjpgFVZ/Y1E6BvvjzWZpBfj668fo7P3DekWHbvPPr/DiZ7OA6PCmAH1FBsi2c+
+xPgb9clDc2Zjb2Cd9lAoZdeB14zDOh6ZCF1c/i+qYt5tA9t+GA==
+-----END CERTIFICATE-----
diff --git a/android/TerminalApp/AndroidManifest.xml b/android/TerminalApp/AndroidManifest.xml
index d92aa8b..c92da67 100644
--- a/android/TerminalApp/AndroidManifest.xml
+++ b/android/TerminalApp/AndroidManifest.xml
@@ -6,7 +6,8 @@
<uses-permission android:name="com.android.virtualization.vmlauncher.permission.USE_VM_LAUNCHER"/>
<application
- android:label="VmTerminalApp"
+ android:label="@string/app_name"
+ android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden|navigation|uiMode|screenLayout|smallestScreenSize"
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index 9afca7f..a6723fb 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -102,17 +102,16 @@
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
- switch (item.getItemId()) {
- case R.id.copy_ip_addr:
- // TODO(b/340126051): remove this menu item when port forwarding is supported.
- getSystemService(ClipboardManager.class)
- .setPrimaryClip(ClipData.newPlainText("A VM's IP address", mVmIpAddr));
- return true;
- case R.id.stop_vm:
- VmLauncherServices.stopVmLauncherService(this);
- return true;
- default:
- return super.onMenuItemSelected(featureId, item);
+ int id = item.getItemId();
+ if (id == R.id.copy_ip_addr) {
+ // TODO(b/340126051): remove this menu item when port forwarding is supported.
+ getSystemService(ClipboardManager.class)
+ .setPrimaryClip(ClipData.newPlainText("A VM's IP address", mVmIpAddr));
+ return true;
+ } else if (id == R.id.stop_vm) {
+ VmLauncherServices.stopVmLauncherService(this);
+ return true;
}
+ return super.onMenuItemSelected(featureId, item);
}
}
diff --git a/android/TerminalApp/res/drawable/ic_launcher_background.xml b/android/TerminalApp/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/android/TerminalApp/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/android/TerminalApp/res/drawable/ic_launcher_foreground.xml b/android/TerminalApp/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..8b28c8e
--- /dev/null
+++ b/android/TerminalApp/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="142"
+ android:viewportHeight="168.75">
+ <group android:scaleX="0.37325713"
+ android:scaleY="0.44357142"
+ android:translateX="43.332314"
+ android:translateY="39.324776">
+ <group android:translateY="133.59375">
+ <path android:pathData="M9.078125,-77.484375L69.75,-51.40625L69.75,-37.765625L9.078125,-11.609375L9.078125,-28.40625L52.53125,-44.71875L9.078125,-60.75L9.078125,-77.484375Z"
+ android:fillColor="#3BBA46"/>
+ <path android:pathData="M139.76562,0L139.76562,13.5L75.21875,13.5L75.21875,0L139.76562,0Z"
+ android:fillColor="#3BBA46"/>
+ </group>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/android/TerminalApp/res/layout/activity_headless.xml b/android/TerminalApp/res/layout/activity_headless.xml
index 2a640f3..3fe5271 100644
--- a/android/TerminalApp/res/layout/activity_headless.xml
+++ b/android/TerminalApp/res/layout/activity_headless.xml
@@ -5,6 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
+ android:fitsSystemWindows="true"
tools:context=".MainActivity">
<TextView
android:id="@+id/ip_addr_textview"
diff --git a/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher.xml b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..7353dbd
--- /dev/null
+++ b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background"/>
+ <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..7353dbd
--- /dev/null
+++ b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background"/>
+ <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/android/TerminalApp/res/mipmap-hdpi/ic_launcher_round.webp b/android/TerminalApp/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9be8219
--- /dev/null
+++ b/android/TerminalApp/res/mipmap-hdpi/ic_launcher_round.webp
Binary files differ
diff --git a/android/TerminalApp/res/mipmap-mdpi/ic_launcher_round.webp b/android/TerminalApp/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..662c81e
--- /dev/null
+++ b/android/TerminalApp/res/mipmap-mdpi/ic_launcher_round.webp
Binary files differ
diff --git a/android/TerminalApp/res/mipmap-xhdpi/ic_launcher_round.webp b/android/TerminalApp/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..2d7990d
--- /dev/null
+++ b/android/TerminalApp/res/mipmap-xhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/android/TerminalApp/res/mipmap-xxhdpi/ic_launcher_round.webp b/android/TerminalApp/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..7941000
--- /dev/null
+++ b/android/TerminalApp/res/mipmap-xxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/android/TerminalApp/res/mipmap-xxxhdpi/ic_launcher_round.webp b/android/TerminalApp/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..55f8020
--- /dev/null
+++ b/android/TerminalApp/res/mipmap-xxxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/android/TerminalApp/res/values/ic_launcher_background.xml b/android/TerminalApp/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..337764a
--- /dev/null
+++ b/android/TerminalApp/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="ic_launcher_background">#070E1E</color>
+</resources>
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index eb6476d..79da7cd 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -16,7 +16,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="vm_creation_message">A VM instance is being created.</string>
- <string name="vm_stop_message">A VM instance is stopped, finish the app.</string>
- <string name="vm_error_message">A VM instance is crashed, finish the app.</string>
-</resources>
\ No newline at end of file
+ <string name="app_name">Terminal</string>
+ <string name="vm_creation_message">Virtual machine is booting. Please wait.</string>
+ <string name="vm_stop_message">Virtual machine is stopped. Exiting.</string>
+ <string name="vm_error_message">Virtual machine crashed. Exiting.</string>
+</resources>
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 158c564..fb3d353 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -622,6 +622,7 @@
boost_uclamp: config.boostUclamp,
gpu_config,
audio_config,
+ no_balloon: config.noBalloon,
};
let instance = Arc::new(
VmInstance::new(
@@ -988,6 +989,10 @@
vm_config.devices.clone_from(&custom_config.devices);
vm_config.networkSupported = custom_config.networkSupported;
+
+ for param in custom_config.extraKernelCmdlineParams.iter() {
+ append_kernel_param(param, &mut vm_config);
+ }
}
if config.memoryMib > 0 {
@@ -1540,6 +1545,17 @@
Ok(())
}
+fn check_no_extra_kernel_cmdline_params(config: &VirtualMachineConfig) -> binder::Result<()> {
+ let VirtualMachineConfig::AppConfig(config) = config else { return Ok(()) };
+ if let Some(custom_config) = &config.customConfig {
+ if !custom_config.extraKernelCmdlineParams.is_empty() {
+ return Err(anyhow!("debuggable_vms_improvements feature is disabled"))
+ .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+ }
+ }
+ Ok(())
+}
+
fn check_protected_vm_is_supported() -> binder::Result<()> {
let is_pvm_supported =
hypervisor_props::is_protected_vm_supported().or_service_specific_exception(-1)?;
@@ -1561,6 +1577,9 @@
if !cfg!(multi_tenant) {
check_no_extra_apks(config)?;
}
+ if !cfg!(debuggable_vms_improvements) {
+ check_no_extra_kernel_cmdline_params(config)?;
+ }
Ok(())
}
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index fff0399..9d688a2 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -133,6 +133,7 @@
pub boost_uclamp: bool,
pub gpu_config: Option<GpuConfig>,
pub audio_config: Option<AudioConfig>,
+ pub no_balloon: bool,
}
#[derive(Debug)]
@@ -891,7 +892,9 @@
.arg("--cid")
.arg(config.cid.to_string());
- if system_properties::read_bool("hypervisor.memory_reclaim.supported", false)? {
+ if system_properties::read_bool("hypervisor.memory_reclaim.supported", false)?
+ && !config.no_balloon
+ {
command.arg("--balloon-page-reporting");
} else {
command.arg("--no-balloon");
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index ee39d75..9123742 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -127,6 +127,9 @@
/** Whether the VM should have network feature. */
boolean networkSupported;
+
+ /** Additional parameters to pass to the VM's kernel cmdline. */
+ String[] extraKernelCmdlineParams;
}
/** Configuration parameters guarded by android.permission.USE_CUSTOM_VIRTUAL_MACHINE */
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index 07d52db..4ac401d 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -100,4 +100,6 @@
@nullable GpuConfig gpuConfig;
@nullable AudioConfig audioConfig;
+
+ boolean noBalloon;
}
diff --git a/android/vm/Android.bp b/android/vm/Android.bp
index c1d9b6b..ba8b416 100644
--- a/android/vm/Android.bp
+++ b/android/vm/Android.bp
@@ -16,6 +16,7 @@
"libbinder_rs",
"libclap",
"libenv_logger",
+ "libcfg_if",
"libglob",
"libhypervisor_props",
"liblibc",
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index 3c0887c..185ac34 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -75,14 +75,14 @@
}
impl CommonConfig {
- #[cfg(network)]
fn network_supported(&self) -> bool {
- self.network_supported
- }
-
- #[cfg(not(network))]
- fn network_supported(&self) -> bool {
- false
+ cfg_if::cfg_if! {
+ if #[cfg(network)] {
+ self.network_supported
+ } else {
+ false
+ }
+ }
}
}
@@ -109,6 +109,23 @@
/// Note: this is only supported on Android kernels android14-5.15 and higher.
#[arg(long)]
gdb: Option<NonZeroU16>,
+
+ /// Whether to enable earlycon. Only supported for debuggable Linux-based VMs.
+ #[cfg(debuggable_vms_improvements)]
+ #[arg(long)]
+ enable_earlycon: bool,
+}
+
+impl DebugConfig {
+ fn enable_earlycon(&self) -> bool {
+ cfg_if::cfg_if! {
+ if #[cfg(debuggable_vms_improvements)] {
+ self.enable_earlycon
+ } else {
+ false
+ }
+ }
+ }
}
#[derive(Args, Default)]
@@ -141,34 +158,34 @@
}
impl MicrodroidConfig {
- #[cfg(vendor_modules)]
- fn vendor(&self) -> &Option<PathBuf> {
- &self.vendor
+ fn vendor(&self) -> Option<&PathBuf> {
+ cfg_if::cfg_if! {
+ if #[cfg(vendor_modules)] {
+ self.vendor.as_ref()
+ } else {
+ None
+ }
+ }
}
- #[cfg(not(vendor_modules))]
- fn vendor(&self) -> Option<PathBuf> {
- None
- }
-
- #[cfg(vendor_modules)]
fn gki(&self) -> Option<&str> {
- self.gki.as_deref()
+ cfg_if::cfg_if! {
+ if #[cfg(vendor_modules)] {
+ self.gki.as_deref()
+ } else {
+ None
+ }
+ }
}
- #[cfg(not(vendor_modules))]
- fn gki(&self) -> Option<&str> {
- None
- }
-
- #[cfg(device_assignment)]
- fn devices(&self) -> &Vec<PathBuf> {
- &self.devices
- }
-
- #[cfg(not(device_assignment))]
- fn devices(&self) -> Vec<PathBuf> {
- Vec::new()
+ fn devices(&self) -> &[PathBuf] {
+ cfg_if::cfg_if! {
+ if #[cfg(device_assignment)] {
+ &self.devices
+ } else {
+ &[]
+ }
+ }
}
}
@@ -219,35 +236,35 @@
}
impl RunAppConfig {
- #[cfg(multi_tenant)]
fn extra_apks(&self) -> &[PathBuf] {
- &self.extra_apks
+ cfg_if::cfg_if! {
+ if #[cfg(multi_tenant)] {
+ &self.extra_apks
+ } else {
+ &[]
+ }
+ }
}
- #[cfg(not(multi_tenant))]
- fn extra_apks(&self) -> &[PathBuf] {
- &[]
- }
-
- #[cfg(llpvm_changes)]
fn instance_id(&self) -> Result<PathBuf, Error> {
- Ok(self.instance_id.clone())
+ cfg_if::cfg_if! {
+ if #[cfg(llpvm_changes)] {
+ Ok(self.instance_id.clone())
+ } else {
+ Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+ }
+ }
}
- #[cfg(not(llpvm_changes))]
- fn instance_id(&self) -> Result<PathBuf, Error> {
- Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
- }
-
- #[cfg(llpvm_changes)]
fn set_instance_id(&mut self, instance_id_file: PathBuf) -> Result<(), Error> {
- self.instance_id = instance_id_file;
- Ok(())
- }
-
- #[cfg(not(llpvm_changes))]
- fn set_instance_id(&mut self, _: PathBuf) -> Result<(), Error> {
- Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+ cfg_if::cfg_if! {
+ if #[cfg(llpvm_changes)] {
+ self.instance_id = instance_id_file;
+ Ok(())
+ } else {
+ Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+ }
+ }
}
}
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index b3743ae..823546f 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -148,7 +148,7 @@
let payload_config_str = format!("{:?}!{:?}", config.apk, payload);
- let custom_config = CustomConfig {
+ let mut custom_config = CustomConfig {
gdbPort: config.debug.gdb.map(u16::from).unwrap_or(0) as i32, // 0 means no gdb
vendorImage: vendor,
devices: config
@@ -163,6 +163,21 @@
..Default::default()
};
+ if config.debug.enable_earlycon() {
+ if config.debug.debug != DebugLevel::FULL {
+ bail!("earlycon is only supported for debuggable VMs")
+ }
+ if cfg!(target_arch = "aarch64") {
+ custom_config
+ .extraKernelCmdlineParams
+ .push(String::from("earlycon=uart8250,mmio,0x3f8"));
+ } else if cfg!(target_arch = "x86_64") {
+ custom_config.extraKernelCmdlineParams.push(String::from("earlycon=uart8250,io,0x3f8"));
+ } else {
+ bail!("unexpected architecture!");
+ }
+ }
+
let vm_config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
name: config.common.name.unwrap_or_else(|| String::from("VmRunApp")),
apk: apk_fd.into(),
diff --git a/build/Android.bp b/build/Android.bp
index 66cc626..6ab1d89 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -44,6 +44,9 @@
}) + select(release_flag("RELEASE_AVF_ENABLE_VIRT_CPUFREQ"), {
true: ["virt_cpufreq"],
default: [],
+ }) + select(release_flag("RELEASE_AVF_IMPROVE_DEBUGGABLE_VMS"), {
+ true: ["debuggable_vms_improvements"],
+ default: [],
}) + select(release_flag("RELEASE_AVF_SUPPORT_CUSTOM_VM_WITH_PARAVIRTUALIZED_DEVICES"), {
true: ["paravirtualized_devices"],
default: [],
diff --git a/guest/authfs/Android.bp b/guest/authfs/Android.bp
index b11da3d..d7a8322 100644
--- a/guest/authfs/Android.bp
+++ b/guest/authfs/Android.bp
@@ -13,7 +13,6 @@
"libanyhow",
"libauthfs_fsverity_metadata",
"libbinder_rs",
- "libcfg_if",
"libclap",
"libfsverity_digests_proto_rust",
"libfuse_rust",
diff --git a/guest/authfs/src/fusefs.rs b/guest/authfs/src/fusefs.rs
index 618b8ac..fa4076d 100644
--- a/guest/authfs/src/fusefs.rs
+++ b/guest/authfs/src/fusefs.rs
@@ -385,15 +385,6 @@
}
}
-cfg_if::cfg_if! {
- if #[cfg(all(any(target_arch = "aarch64", target_arch = "riscv64"),
- target_pointer_width = "64"))] {
- fn blk_size() -> libc::c_int { CHUNK_SIZE as libc::c_int }
- } else {
- fn blk_size() -> libc::c_long { CHUNK_SIZE as libc::c_long }
- }
-}
-
#[allow(clippy::enum_variant_names)]
enum AccessMode {
ReadOnly,
@@ -421,7 +412,7 @@
st.st_gid = 0;
st.st_size = libc::off64_t::try_from(file_size)
.map_err(|_| io::Error::from_raw_os_error(libc::EFBIG))?;
- st.st_blksize = blk_size();
+ st.st_blksize = CHUNK_SIZE.try_into().unwrap();
// Per man stat(2), st_blocks is "Number of 512B blocks allocated".
st.st_blocks = libc::c_longlong::try_from(divide_roundup(file_size, 512))
.map_err(|_| io::Error::from_raw_os_error(libc::EFBIG))?;
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index ce04317..8f9340b 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -276,8 +276,9 @@
MEMORY.lock().as_mut().unwrap().unshare_all_memory();
if let Some(mmio_guard) = get_mmio_guard() {
- // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
- if !debuggable_payload {
+ if cfg!(debuggable_vms_improvements) && debuggable_payload {
+ // Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
+ } else {
mmio_guard.unmap(UART_PAGE_ADDR).map_err(|e| {
error!("Failed to unshare the UART: {e}");
RebootReason::InternalError
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 7ae4a55..644a85a 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -724,6 +724,7 @@
Optional.ofNullable(customImageConfig.getAudioConfig())
.map(ac -> ac.toParcelable())
.orElse(null);
+ config.noBalloon = !customImageConfig.useAutoMemoryBalloon();
return config;
}
@@ -777,6 +778,7 @@
VirtualMachineAppConfig.CustomConfig customConfig =
new VirtualMachineAppConfig.CustomConfig();
customConfig.devices = EMPTY_STRING_ARRAY;
+ customConfig.extraKernelCmdlineParams = EMPTY_STRING_ARRAY;
try {
customConfig.vendorImage =
ParcelFileDescriptor.open(mVendorDiskImage, MODE_READ_ONLY);
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
index 37dc8fa..a38ee7f 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
@@ -360,7 +360,8 @@
private boolean network;
private GpuConfig gpuConfig;
private boolean trackpad;
- private boolean autoMemoryBalloon = true;
+ // TODO(b/363985291): balloon breaks Linux VM behavior
+ private boolean autoMemoryBalloon = false;
/** @hide */
public Builder() {}
diff --git a/libs/libvirtualization_jni/Android.bp b/libs/libvirtualization_jni/Android.bp
index 4a569d4..9dc86b0 100644
--- a/libs/libvirtualization_jni/Android.bp
+++ b/libs/libvirtualization_jni/Android.bp
@@ -16,7 +16,10 @@
"liblog",
"libnativehelper",
],
- static_libs: ["libavf_cc_flags"],
+ static_libs: [
+ "libavf_cc_flags",
+ "libvmclient.ffi",
+ ],
}
cc_library_shared {
diff --git a/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp b/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp
index 0538c9e..f0c9b4f 100644
--- a/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp
+++ b/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp
@@ -19,6 +19,7 @@
#include <android-base/unique_fd.h>
#include <android/avf_cc_flags.h>
#include <android/binder_ibinder_jni.h>
+#include <errno.h>
#include <jni.h>
#include <log/log.h>
#include <poll.h>
@@ -29,57 +30,25 @@
using namespace android::base;
-static constexpr const char VIRTMGR_PATH[] = "/apex/com.android.virt/bin/virtmgr";
static constexpr size_t VIRTMGR_THREADS = 2;
+void error_callback(int code, const char* msg, void* ctx) {
+ JNIEnv* env = reinterpret_cast<JNIEnv*>(ctx);
+ if (code == EPERM || code == EACCES) {
+ env->ThrowNew(env->FindClass("java/lang/SecurityException"),
+ "Virtmgr didn't send any data through pipe. Please consider checking if "
+ "android.permission.MANAGE_VIRTUAL_MACHINE permission is granted");
+ return;
+ }
+ env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"), msg);
+}
+
+extern "C" int get_virtualization_service(decltype(error_callback)*, void*);
+
extern "C" JNIEXPORT jint JNICALL
Java_android_system_virtualmachine_VirtualizationService_nativeSpawn(
JNIEnv* env, [[maybe_unused]] jclass clazz) {
- unique_fd serverFd, clientFd;
- if (!Socketpair(SOCK_STREAM, &serverFd, &clientFd)) {
- env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
- ("Failed to create socketpair: " + std::string(strerror(errno))).c_str());
- return -1;
- }
-
- unique_fd waitFd, readyFd;
- if (!Pipe(&waitFd, &readyFd, 0)) {
- env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
- ("Failed to create pipe: " + std::string(strerror(errno))).c_str());
- return -1;
- }
-
- if (fork() == 0) {
- // Close client's FDs.
- clientFd.reset();
- waitFd.reset();
-
- auto strServerFd = std::to_string(serverFd.get());
- auto strReadyFd = std::to_string(readyFd.get());
-
- execl(VIRTMGR_PATH, VIRTMGR_PATH, "--rpc-server-fd", strServerFd.c_str(), "--ready-fd",
- strReadyFd.c_str(), NULL);
- }
-
- // Close virtmgr's FDs.
- serverFd.reset();
- readyFd.reset();
-
- // Wait for the server to signal its readiness by closing its end of the pipe.
- char buf;
- int ret = read(waitFd.get(), &buf, sizeof(buf));
- if (ret < 0) {
- env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
- "Failed to wait for VirtualizationService to be ready");
- return -1;
- } else if (ret < 1) {
- env->ThrowNew(env->FindClass("java/lang/SecurityException"),
- "Virtmgr didn't send any data through pipe. Please consider checking if "
- "android.permission.MANAGE_VIRTUAL_MACHINE permission is granted");
- return -1;
- }
-
- return clientFd.release();
+ return get_virtualization_service(error_callback, env);
}
extern "C" JNIEXPORT jobject JNICALL
diff --git a/libs/libvmclient/Android.bp b/libs/libvmclient/Android.bp
index 9fdeaf8..5bd59da 100644
--- a/libs/libvmclient/Android.bp
+++ b/libs/libvmclient/Android.bp
@@ -2,8 +2,8 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-rust_library {
- name: "libvmclient",
+rust_defaults {
+ name: "libvmclient.default",
crate_name: "vmclient",
defaults: ["avf_build_flags_rust"],
srcs: ["src/lib.rs"],
@@ -25,3 +25,13 @@
"com.android.virt",
],
}
+
+rust_library {
+ name: "libvmclient",
+ defaults: ["libvmclient.default"],
+}
+
+rust_ffi_static {
+ name: "libvmclient.ffi",
+ defaults: ["libvmclient.default"],
+}
diff --git a/libs/libvmclient/src/lib.rs b/libs/libvmclient/src/lib.rs
index 7b576e6..bc9d683 100644
--- a/libs/libvmclient/src/lib.rs
+++ b/libs/libvmclient/src/lib.rs
@@ -43,7 +43,9 @@
use log::warn;
use rpcbinder::{FileDescriptorTransportMode, RpcSession};
use shared_child::SharedChild;
+use std::ffi::{c_char, c_int, c_void, CString};
use std::io::{self, Read};
+use std::os::fd::RawFd;
use std::process::Command;
use std::{
fmt::{self, Debug, Formatter},
@@ -74,6 +76,40 @@
Ok(socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::SOCK_CLOEXEC)?)
}
+/// Error handling function for `get_virtualization_service`.
+///
+/// # Safety
+/// `message` shouldn't be used outside of the lifetime of the function. Management of `ctx` is
+/// entirely up to the function.
+pub type ErrorCallback =
+ unsafe extern "C" fn(code: c_int, message: *const c_char, ctx: *mut c_void);
+
+/// Spawns a new instance of virtmgr and rerturns a file descriptor for the socket connection to
+/// the service. When error occurs, it is reported via the ErrorCallback function along with the
+/// error message and any context that is set by the client.
+///
+/// # Safety
+/// `cb` should be null or a valid function pointer of type `ErrorCallback`
+#[no_mangle]
+pub unsafe extern "C" fn get_virtualization_service(
+ cb: Option<ErrorCallback>,
+ ctx: *mut c_void,
+) -> RawFd {
+ match VirtualizationService::new() {
+ Ok(vs) => vs.client_fd.into_raw_fd(),
+ Err(e) => {
+ if let Some(cb) = cb {
+ let code = e.raw_os_error().unwrap_or(-1);
+ let msg = CString::new(e.to_string()).unwrap();
+ // SAFETY: `cb` doesn't use `msg` outside of the lifetime of the function.
+ // msg's lifetime is longer than `cb` as it is bound to a local variable.
+ unsafe { cb(code, msg.as_ptr(), ctx) };
+ }
+ -1
+ }
+ }
+}
+
/// A running instance of virtmgr which is hosting a VirtualizationService
/// RpcBinder server.
pub struct VirtualizationService {
@@ -97,10 +133,11 @@
SharedChild::spawn(&mut command)?;
- // Wait for the child to signal that the RpcBinder server is ready
- // by closing its end of the pipe.
- let _ignored = File::from(wait_fd).read(&mut [0]);
-
+ // Wait for the child to signal that the RpcBinder server is read by closing its end of the
+ // pipe. Failing to read (especially EACCESS or EPERM) can happen if the client lacks the
+ // MANAGE_VIRTUAL_MACHINE permission. Therefore, such errors are propagated instead of
+ // being ignored.
+ let _ = File::from(wait_fd).read(&mut [0])?;
Ok(VirtualizationService { client_fd })
}