Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
index b79e346..a0fca82 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
@@ -76,6 +76,7 @@
private SharedPathJson[] sharedPath;
private DisplayJson display;
private GpuJson gpu;
+ private boolean auto_memory_balloon;
/** Parses JSON file at jsonPath */
static ConfigJson from(Context context, Path jsonPath) {
@@ -145,7 +146,8 @@
.setBootloaderPath(bootloader)
.setKernelPath(kernel)
.setInitrdPath(initrd)
- .useNetwork(network);
+ .useNetwork(network)
+ .useAutoMemoryBalloon(auto_memory_balloon);
if (input != null) {
builder.useTouch(input.touchscreen)
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
new file mode 100644
index 0000000..c46effa
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 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.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.materialswitch.MaterialSwitch
+
+class SettingsPortForwardingActiveAdapter(private val mPortsStateManager: PortsStateManager) :
+ SettingsPortForwardingBaseAdapter<SettingsPortForwardingActiveAdapter.ViewHolder>() {
+
+ override fun getItems(): ArrayList<SettingsPortForwardingItem> {
+ val enabledPorts = mPortsStateManager.getEnabledPorts()
+ return mPortsStateManager
+ .getActivePorts()
+ .map { SettingsPortForwardingItem(it, enabledPorts.contains(it)) }
+ .toCollection(ArrayList())
+ }
+
+ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ val enabledSwitch: MaterialSwitch =
+ view.findViewById(R.id.settings_port_forwarding_active_item_enabled_switch)
+ val port: TextView = view.findViewById(R.id.settings_port_forwarding_active_item_port)
+ }
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
+ val view =
+ LayoutInflater.from(viewGroup.context)
+ .inflate(R.layout.settings_port_forwarding_active_item, viewGroup, false)
+ return ViewHolder(view)
+ }
+
+ override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
+ val port = mItems[position].port
+ viewHolder.port.text = port.toString()
+ viewHolder.enabledSwitch.contentDescription = viewHolder.port.text
+ viewHolder.enabledSwitch.isChecked = mItems[position].enabled
+ viewHolder.enabledSwitch.setOnCheckedChangeListener { _, isChecked ->
+ mPortsStateManager.updateEnabledPort(port, isChecked)
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
index d64c267..83a8d05 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
@@ -22,27 +22,50 @@
class SettingsPortForwardingActivity : AppCompatActivity() {
private lateinit var mPortsStateManager: PortsStateManager
- private lateinit var mAdapter: SettingsPortForwardingAdapter
+ private lateinit var mPortsStateListener: Listener
+ private lateinit var mActivePortsAdapter: SettingsPortForwardingActiveAdapter
+ private lateinit var mInactivePortsAdapter: SettingsPortForwardingInactiveAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_port_forwarding)
mPortsStateManager = PortsStateManager.getInstance(this)
- mAdapter = SettingsPortForwardingAdapter(mPortsStateManager)
- val recyclerView: RecyclerView = findViewById(R.id.settings_port_forwarding_recycler_view)
- recyclerView.layoutManager = LinearLayoutManager(this)
- recyclerView.adapter = mAdapter
+ mActivePortsAdapter = SettingsPortForwardingActiveAdapter(mPortsStateManager)
+ val activeRecyclerView: RecyclerView =
+ findViewById(R.id.settings_port_forwarding_active_recycler_view)
+ activeRecyclerView.layoutManager = LinearLayoutManager(this)
+ activeRecyclerView.adapter = mActivePortsAdapter
+
+ mInactivePortsAdapter = SettingsPortForwardingInactiveAdapter(mPortsStateManager, this)
+ val inactiveRecyclerView: RecyclerView =
+ findViewById(R.id.settings_port_forwarding_inactive_recycler_view)
+ inactiveRecyclerView.layoutManager = LinearLayoutManager(this)
+ inactiveRecyclerView.adapter = mInactivePortsAdapter
+
+ mPortsStateListener = Listener()
+ }
+
+ private fun refreshAdapters() {
+ mActivePortsAdapter.refreshItems()
+ mInactivePortsAdapter.refreshItems()
}
override fun onResume() {
super.onResume()
- mAdapter.registerPortsStateListener()
+ mPortsStateManager.registerListener(mPortsStateListener)
+ refreshAdapters()
}
override fun onPause() {
- mAdapter.unregisterPortsStateListener()
+ mPortsStateManager.unregisterListener(mPortsStateListener)
super.onPause()
}
+
+ private inner class Listener : PortsStateManager.Listener {
+ override fun onPortsStateUpdated(oldActivePorts: Set<Int>, newActivePorts: Set<Int>) {
+ refreshAdapters()
+ }
+ }
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingAdapter.kt
deleted file mode 100644
index 8282910..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingAdapter.kt
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2024 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.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.SortedList
-import androidx.recyclerview.widget.SortedListAdapterCallback
-import com.google.android.material.materialswitch.MaterialSwitch
-
-class SettingsPortForwardingAdapter(private val mPortsStateManager: PortsStateManager) :
- RecyclerView.Adapter<SettingsPortForwardingAdapter.ViewHolder>() {
-
- private var mItems: SortedList<SettingsPortForwardingItem>
- private val mPortsStateListener: Listener
-
- init {
- mItems =
- SortedList(
- SettingsPortForwardingItem::class.java,
- object : SortedListAdapterCallback<SettingsPortForwardingItem>(this) {
- override fun compare(
- o1: SettingsPortForwardingItem,
- o2: SettingsPortForwardingItem,
- ): Int {
- return o1.port - o2.port
- }
-
- override fun areContentsTheSame(
- o1: SettingsPortForwardingItem,
- o2: SettingsPortForwardingItem,
- ): Boolean {
- return o1.port == o2.port && o1.enabled == o2.enabled
- }
-
- override fun areItemsTheSame(
- o1: SettingsPortForwardingItem,
- o2: SettingsPortForwardingItem,
- ): Boolean {
- return o1.port == o2.port
- }
- },
- )
- mItems.addAll(getCurrentSettingsPortForwardingItem())
- mPortsStateListener = Listener()
- }
-
- fun registerPortsStateListener() {
- mPortsStateManager.registerListener(mPortsStateListener)
- mItems.replaceAll(getCurrentSettingsPortForwardingItem())
- }
-
- fun unregisterPortsStateListener() {
- mPortsStateManager.unregisterListener(mPortsStateListener)
- }
-
- private fun getCurrentSettingsPortForwardingItem(): ArrayList<SettingsPortForwardingItem> {
- val enabledPorts = mPortsStateManager.getEnabledPorts()
- return mPortsStateManager
- .getActivePorts()
- .map { SettingsPortForwardingItem(it, enabledPorts.contains(it)) }
- .toCollection(ArrayList())
- }
-
- class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
- val enabledSwitch: MaterialSwitch =
- view.findViewById(R.id.settings_port_forwarding_item_enabled_switch)
- val port: TextView = view.findViewById(R.id.settings_port_forwarding_item_port)
- }
-
- override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
- val view =
- LayoutInflater.from(viewGroup.context)
- .inflate(R.layout.settings_port_forwarding_item, viewGroup, false)
- return ViewHolder(view)
- }
-
- override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
- val port = mItems[position].port
- viewHolder.port.text = port.toString()
- viewHolder.enabledSwitch.contentDescription = viewHolder.port.text
- viewHolder.enabledSwitch.isChecked = mItems[position].enabled
- viewHolder.enabledSwitch.setOnCheckedChangeListener { _, isChecked ->
- mPortsStateManager.updateEnabledPort(port, isChecked)
- }
- }
-
- override fun getItemCount() = mItems.size()
-
- private inner class Listener : PortsStateManager.Listener {
- override fun onPortsStateUpdated(oldActivePorts: Set<Int>, newActivePorts: Set<Int>) {
- mItems.replaceAll(getCurrentSettingsPortForwardingItem())
- }
- }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
new file mode 100644
index 0000000..4595372
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 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 androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.SortedList
+import androidx.recyclerview.widget.SortedListAdapterCallback
+
+abstract class SettingsPortForwardingBaseAdapter<T : RecyclerView.ViewHolder>() :
+ RecyclerView.Adapter<T>() {
+ var mItems: SortedList<SettingsPortForwardingItem>
+
+ init {
+ mItems =
+ SortedList(
+ SettingsPortForwardingItem::class.java,
+ object : SortedListAdapterCallback<SettingsPortForwardingItem>(this) {
+ override fun compare(
+ o1: SettingsPortForwardingItem,
+ o2: SettingsPortForwardingItem,
+ ): Int {
+ return o1.port - o2.port
+ }
+
+ override fun areContentsTheSame(
+ o1: SettingsPortForwardingItem,
+ o2: SettingsPortForwardingItem,
+ ): Boolean {
+ return o1.port == o2.port && o1.enabled == o2.enabled
+ }
+
+ override fun areItemsTheSame(
+ o1: SettingsPortForwardingItem,
+ o2: SettingsPortForwardingItem,
+ ): Boolean {
+ return o1.port == o2.port
+ }
+ },
+ )
+ }
+
+ override fun getItemCount() = mItems.size()
+
+ abstract fun getItems(): ArrayList<SettingsPortForwardingItem>
+
+ fun refreshItems() {
+ mItems.replaceAll(getItems())
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
new file mode 100644
index 0000000..ee0bee5
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 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.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageButton
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+
+class SettingsPortForwardingInactiveAdapter(
+ private val mPortsStateManager: PortsStateManager,
+ private val mContext: Context,
+) : SettingsPortForwardingBaseAdapter<SettingsPortForwardingInactiveAdapter.ViewHolder>() {
+
+ override fun getItems(): ArrayList<SettingsPortForwardingItem> {
+ return mPortsStateManager
+ .getEnabledPorts()
+ .subtract(mPortsStateManager.getActivePorts())
+ .map { SettingsPortForwardingItem(it, true) }
+ .toCollection(ArrayList())
+ }
+
+ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ val closeButton: ImageButton =
+ view.findViewById(R.id.settings_port_forwarding_active_item_close_button)
+ val port: TextView = view.findViewById(R.id.settings_port_forwarding_inactive_item_port)
+ }
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
+ val view =
+ LayoutInflater.from(viewGroup.context)
+ .inflate(R.layout.settings_port_forwarding_inactive_item, viewGroup, false)
+ return ViewHolder(view)
+ }
+
+ override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
+ val port = mItems[position].port
+ viewHolder.port.text = port.toString()
+ viewHolder.closeButton.contentDescription =
+ mContext.getString(
+ R.string.settings_port_forwarding_other_enabled_port_close_button,
+ port,
+ )
+ viewHolder.closeButton.setOnClickListener { _ ->
+ mPortsStateManager.updateEnabledPort(port, false)
+ }
+ }
+}
diff --git a/android/TerminalApp/res/drawable/ic_close.xml b/android/TerminalApp/res/drawable/ic_close.xml
new file mode 100644
index 0000000..e21c19c
--- /dev/null
+++ b/android/TerminalApp/res/drawable/ic_close.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2024 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z"/>
+</vector>
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding.xml b/android/TerminalApp/res/layout/settings_port_forwarding.xml
index 2d21962..77b9bf7 100644
--- a/android/TerminalApp/res/layout/settings_port_forwarding.xml
+++ b/android/TerminalApp/res/layout/settings_port_forwarding.xml
@@ -31,9 +31,33 @@
android:hyphenationFrequency="full"
android:layout_marginBottom="24dp"/>
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_port_forwarding_active_ports_title"
+ android:textSize="24sp"
+ android:hyphenationFrequency="full"
+ android:layout_marginBottom="24dp"/>
+
<androidx.recyclerview.widget.RecyclerView
- android:id="@+id/settings_port_forwarding_recycler_view"
+ android:id="@+id/settings_port_forwarding_active_recycler_view"
android:layout_marginHorizontal="16dp"
+ android:layout_marginBottom="24dp"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_port_forwarding_other_enabled_ports_title"
+ android:textSize="24sp"
+ android:hyphenationFrequency="full"
+ android:layout_marginBottom="24dp"/>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/settings_port_forwarding_inactive_recycler_view"
+ android:layout_marginHorizontal="16dp"
+ android:layout_marginBottom="24dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
</LinearLayout>
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding_item.xml b/android/TerminalApp/res/layout/settings_port_forwarding_active_item.xml
similarity index 81%
rename from android/TerminalApp/res/layout/settings_port_forwarding_item.xml
rename to android/TerminalApp/res/layout/settings_port_forwarding_active_item.xml
index 8a57b41..2a74146 100644
--- a/android/TerminalApp/res/layout/settings_port_forwarding_item.xml
+++ b/android/TerminalApp/res/layout/settings_port_forwarding_active_item.xml
@@ -19,21 +19,26 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minHeight="48dp"
app:layout_constraintCircleRadius="@dimen/material_emphasis_medium">
<TextView
- android:id="@+id/settings_port_forwarding_item_port"
+ android:id="@+id/settings_port_forwarding_active_item_port"
android:layout_height="wrap_content"
android:layout_width="match_parent"
+ android:textSize="16sp"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<com.google.android.material.materialswitch.MaterialSwitch
- android:id="@+id/settings_port_forwarding_item_enabled_switch"
+ android:id="@+id/settings_port_forwarding_active_item_enabled_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding_item.xml b/android/TerminalApp/res/layout/settings_port_forwarding_inactive_item.xml
similarity index 74%
copy from android/TerminalApp/res/layout/settings_port_forwarding_item.xml
copy to android/TerminalApp/res/layout/settings_port_forwarding_inactive_item.xml
index 8a57b41..127b152 100644
--- a/android/TerminalApp/res/layout/settings_port_forwarding_item.xml
+++ b/android/TerminalApp/res/layout/settings_port_forwarding_inactive_item.xml
@@ -19,21 +19,28 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minHeight="48dp"
app:layout_constraintCircleRadius="@dimen/material_emphasis_medium">
<TextView
- android:id="@+id/settings_port_forwarding_item_port"
+ android:id="@+id/settings_port_forwarding_inactive_item_port"
android:layout_height="wrap_content"
android:layout_width="match_parent"
+ android:textSize="16sp"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
- <com.google.android.material.materialswitch.MaterialSwitch
- android:id="@+id/settings_port_forwarding_item_enabled_switch"
+ <ImageButton
+ android:id="@+id/settings_port_forwarding_active_item_close_button"
+ android:src="@drawable/ic_close"
+ android:background="@android:color/transparent"
+ android:contentDescription="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index d21ded1..9cb6e4d 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -89,6 +89,8 @@
<string name="settings_port_forwarding_active_ports_title">Listening ports</string>
<!-- Title for other enabled ports setting in port forwarding [CHAR LIMIT=none] -->
<string name="settings_port_forwarding_other_enabled_ports_title">Saved allowed ports</string>
+ <!-- Description of close button for other enabled ports. Used for talkback. [CHAR LIMIT=none] -->
+ <string name="settings_port_forwarding_other_enabled_port_close_button">Delete <xliff:g id="port_number" example="8000">%d</xliff:g></string>
<!-- Dialog title for enabling a new port [CHAR LIMIT=none] -->
<string name="settings_port_forwarding_dialog_title">Allow a new port</string>
diff --git a/android/virtmgr/Android.bp b/android/virtmgr/Android.bp
index ad63995..3883c34 100644
--- a/android/virtmgr/Android.bp
+++ b/android/virtmgr/Android.bp
@@ -69,7 +69,7 @@
"liblibfdt",
"libfsfdt",
"libhypervisor_props",
- "libzerocopy",
+ "libzerocopy-0.7.35",
"libuuid",
// TODO(b/202115393) stabilize the interface
"packagemanager_aidl-rust",
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 82a5573..79c7d81 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -787,7 +787,7 @@
boost_uclamp: config.boostUclamp,
gpu_config,
audio_config,
- no_balloon: config.noBalloon,
+ balloon: config.balloon,
usb_config,
dump_dt_fd,
};
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index a385b82..2bfa4e1 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -133,7 +133,7 @@
pub boost_uclamp: bool,
pub gpu_config: Option<GpuConfig>,
pub audio_config: Option<AudioConfig>,
- pub no_balloon: bool,
+ pub balloon: bool,
pub usb_config: UsbConfig,
pub dump_dt_fd: Option<File>,
}
@@ -975,8 +975,7 @@
.arg("--cid")
.arg(config.cid.to_string());
- if system_properties::read_bool("hypervisor.memory_reclaim.supported", false)?
- && !config.no_balloon
+ if system_properties::read_bool("hypervisor.memory_reclaim.supported", false)? && config.balloon
{
command.arg("--balloon-page-reporting");
} else {
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index 5728a68..3393546 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -106,7 +106,7 @@
@nullable AudioConfig audioConfig;
- boolean noBalloon;
+ boolean balloon;
/** Enable or disable USB passthrough support */
@nullable UsbConfig usbConfig;
diff --git a/android/virtualizationservice/vfio_handler/Android.bp b/android/virtualizationservice/vfio_handler/Android.bp
index 3635cf1..fec61f1 100644
--- a/android/virtualizationservice/vfio_handler/Android.bp
+++ b/android/virtualizationservice/vfio_handler/Android.bp
@@ -28,7 +28,7 @@
"liblog_rust",
"libnix",
"librustutils",
- "libzerocopy",
+ "libzerocopy-0.7.35",
],
apex_available: ["com.android.virt"],
}
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 19894c2..cc38dfd 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -11,6 +11,7 @@
echo "Options:"
echo "-h Print usage and this help message and exit."
echo "-a ARCH Architecture of the image [default is host arch: $(uname -m)]"
+ echo "-k Build and use our custom kernel [default is cloud kernel]"
echo "-r Release mode build"
echo "-w Save temp work directory [for debugging]"
}
@@ -22,7 +23,7 @@
}
parse_options() {
- while getopts "a:hrw" option; do
+ while getopts "a:hkrw" option; do
case ${option} in
h)
show_help ; exit
@@ -30,6 +31,9 @@
a)
arch="$OPTARG"
;;
+ k)
+ use_custom_kernel=1
+ ;;
r)
mode=release
;;
@@ -117,6 +121,33 @@
linux-image-generic
)
fi
+
+ if [[ "$use_custom_kernel" -eq 1 ]]; then
+ packages+=(
+ bc
+ bison
+ debhelper
+ dh-exec
+ flex
+ gcc-12
+ kernel-wedge
+ libelf-dev
+ libpci-dev
+ lz4
+ pahole
+ python3-jinja2
+ python3-docutils
+ quilt
+ rsync
+ )
+ if [[ "$arch" == "aarch64" ]]; then
+ packages+=(
+ gcc-arm-linux-gnueabihf
+ gcc-12-aarch64-linux-gnu
+ )
+ fi
+ fi
+
DEBIAN_FRONTEND=noninteractive \
apt install --no-install-recommends --assume-yes "${packages[@]}"
@@ -195,6 +226,74 @@
build_rust_binary_and_copy shutdown_runner
}
+package_custom_kernel() {
+ if [[ "$use_custom_kernel" != 1 ]]; then
+ echo "linux-headers-generic" >> "${config_space}/package_config/AVF"
+ return
+ fi
+
+ # NOTE: 6.1 is the latest LTS kernel for which Debian's kernel build scripts
+ # work on Python 3.10, the default version on our Ubuntu 22.04 builders.
+ local debian_kver="6.1.119-1"
+ local custom_flavour="avf"
+ local ksrc_base_url="https://deb.debian.org/debian/pool/main/l/linux"
+
+ local debian_ksrc_url="${ksrc_base_url}/linux_${debian_kver}.debian.tar.xz"
+ local orig_ksrc_url="${ksrc_base_url}/linux_${debian_kver%-*}.orig.tar.xz"
+
+ # 1. Grab original kernel source, merge debian patches etc.
+ mkdir -p "${workdir}/kernel/avf-${debian_arch}"
+ pushd "${workdir}/kernel" > /dev/null
+ wget "$orig_ksrc_url"
+ pushd "avf-${debian_arch}" > /dev/null
+ wget "${debian_ksrc_url}" -O - | tar xJ
+ # TODO: Copy our own kernel patches to debian/patches
+ # and add patch file names in the desired order to debian/patches/series
+ ./debian/rules orig
+
+ local abi_kver="$(sed -nE 's;Package: linux-support-(.*);\1;p' debian/control)"
+ local debarch_flavour="${custom_flavour}-${debian_arch}"
+ local abi_flavour="${abi_kver}-${debarch_flavour}"
+
+ # 2. Define our custom flavour and regenerate control file
+ # NOTE: Our flavour extends Debian's `cloud` config on the `none` featureset.
+ cat > debian/config/${debian_arch}/config.${debarch_flavour} <<EOF
+# TODO: Add our custom kernel config to this file
+EOF
+
+ sed -z "s;\[base\]\nflavours:;[base]\nflavours:\n ${debarch_flavour};" \
+ -i debian/config/${debian_arch}/none/defines
+ cat >> debian/config/${debian_arch}/none/defines <<EOF
+[${debarch_flavour}_image]
+configs:
+ config.cloud
+ ${debian_arch}/config.${debarch_flavour}
+EOF
+ cat >> debian/config/${debian_arch}/defines <<EOF
+[${debarch_flavour}_description]
+hardware: ${arch} AVF
+hardware-long: ${arch} Android Virtualization Framework
+EOF
+ ./debian/rules debian/control || true
+
+ # 3. Build the kernel and generate Debian packages
+ ./debian/rules source
+ [[ "$arch" == "$(uname -m)" ]] || export $(dpkg-architecture -a $debian_arch)
+ make -j$(nproc) -f debian/rules.gen \
+ "binary-arch_${debian_arch}_none_${debarch_flavour}"
+
+ # 4. Copy the packages to localdebs and add their names to package_config/AVF
+ popd > /dev/null
+ cp "linux-headers-${abi_flavour}_${debian_kver}_${debian_arch}.deb" \
+ "linux-image-${abi_flavour}-unsigned_${debian_kver}_${debian_arch}.deb" \
+ "${debian_cloud_image}/localdebs/"
+ popd > /dev/null
+ cat >> "${config_space}/package_config/AVF" <<EOF
+linux-headers-${abi_flavour}
+linux-image-${abi_flavour}-unsigned
+EOF
+}
+
run_fai() {
local out="${built_image}"
make -C "${debian_cloud_image}" "image_bookworm_nocloud_${debian_arch}"
@@ -238,12 +337,14 @@
arch="$(uname -m)"
mode=debug
save_workdir=0
+use_custom_kernel=0
parse_options "$@"
check_sudo
install_prerequisites
download_debian_cloud_image
copy_android_config
+package_custom_kernel
run_fai
fdisk -l "${built_image}"
images=()
diff --git a/build/debian/build_in_container.sh b/build/debian/build_in_container.sh
index 5028b74..967f5ab 100755
--- a/build/debian/build_in_container.sh
+++ b/build/debian/build_in_container.sh
@@ -6,17 +6,19 @@
echo "Options:"
echo "-h Print usage and this help message and exit."
echo "-a ARCH Architecture of the image [default is host arch: $(uname -m)]"
+ echo "-k Build and use our custom kernel [default is cloud kernel]"
echo "-r Release mode build"
echo "-s Leave a shell open [default: only if the build fails]"
echo "-w Save temp work directory in the container [for debugging]"
}
arch="$(uname -m)"
+kernel_flag=
release_flag=
save_workdir_flag=
shell_condition="||"
-while getopts "a:rsw" option; do
+while getopts "a:hkrsw" option; do
case ${option} in
a)
arch="$OPTARG"
@@ -24,6 +26,9 @@
h)
show_help ; exit
;;
+ k)
+ kernel_flag="-k"
+ ;;
r)
release_flag="-r"
;;
@@ -53,4 +58,4 @@
-v "$ANDROID_BUILD_TOP/packages/modules/Virtualization:/root/Virtualization" \
--workdir /root/Virtualization/build/debian \
ubuntu:22.04 \
- bash -c "/root/Virtualization/build/debian/build.sh -a $arch $release_flag $save_workdir_flag $shell_condition bash"
+ bash -c "/root/Virtualization/build/debian/build.sh -a $arch $release_flag $kernel_flag $save_workdir_flag $shell_condition bash"
diff --git a/build/debian/fai_config/package_config/AVF b/build/debian/fai_config/package_config/AVF
index 2e55e90..a91c354 100644
--- a/build/debian/fai_config/package_config/AVF
+++ b/build/debian/fai_config/package_config/AVF
@@ -1,5 +1,4 @@
PACKAGES install
bpfcc-tools
-linux-headers-generic
procps
diff --git a/build/debian/kokoro/gcp_ubuntu_docker/x86_64/build.sh b/build/debian/kokoro/gcp_ubuntu_docker/x86_64/build.sh
index 22ac595..a935591 100644
--- a/build/debian/kokoro/gcp_ubuntu_docker/x86_64/build.sh
+++ b/build/debian/kokoro/gcp_ubuntu_docker/x86_64/build.sh
@@ -5,7 +5,7 @@
cd "${KOKORO_ARTIFACTS_DIR}/git/avf/build/debian/"
sudo losetup -D
grep vmx /proc/cpuinfo || true
-sudo ./build.sh -r -a x86_64
+sudo ./build.sh -a x86_64 -k -r
sudo mv images.tar.gz ${KOKORO_ARTIFACTS_DIR} || true
mkdir -p ${KOKORO_ARTIFACTS_DIR}/logs
sudo cp -r /var/log/fai/* ${KOKORO_ARTIFACTS_DIR}/logs || true
diff --git a/guest/apkdmverity/Android.bp b/guest/apkdmverity/Android.bp
index 0cb8ca1..64dde3e 100644
--- a/guest/apkdmverity/Android.bp
+++ b/guest/apkdmverity/Android.bp
@@ -22,7 +22,7 @@
"libnum_traits",
"libscopeguard",
"libuuid",
- "libzerocopy",
+ "libzerocopy-0.7.35",
],
proc_macros: ["libnum_derive"],
multilib: {
diff --git a/guest/microdroid_manager/src/vm_secret.rs b/guest/microdroid_manager/src/vm_secret.rs
index 1ad2d88..5cc90ff 100644
--- a/guest/microdroid_manager/src/vm_secret.rs
+++ b/guest/microdroid_manager/src/vm_secret.rs
@@ -36,6 +36,8 @@
use secretkeeper_comm::data_types::error::SecretkeeperError;
use std::fs;
use zeroize::Zeroizing;
+use std::sync::Mutex;
+use std::sync::Arc;
const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
const AUTHORITY_HASH: i64 = -4670549;
@@ -98,27 +100,20 @@
let explicit_dice = OwnedDiceArtifactsWithExplicitKey::from_owned_artifacts(dice_artifacts)
.context("Failed to get Dice artifacts in explicit key format")?;
- // For pVM, skp_secret are stored in Secretkeeper. For non-protected it is all 0s.
+ let session = SkVmSession::new(vm_service, &explicit_dice)?;
+ let id = super::get_instance_id()?.ok_or(anyhow!("Missing instance_id"))?;
+ let explicit_dice_chain = explicit_dice
+ .explicit_key_dice_chain()
+ .ok_or(anyhow!("Missing explicit dice chain, this is unusual"))?;
+ let policy = sealing_policy(explicit_dice_chain)
+ .map_err(|e| anyhow!("Failed to build a sealing_policy: {e}"))?;
let mut skp_secret = Zeroizing::new([0u8; SECRET_SIZE]);
- if super::is_strict_boot() {
- let sk_service = get_secretkeeper_service(vm_service)?;
- let mut session =
- SkSession::new(sk_service, &explicit_dice, Some(get_secretkeeper_identity()?))?;
- let id = super::get_instance_id()?.ok_or(anyhow!("Missing instance_id"))?;
- let explicit_dice_chain = explicit_dice
- .explicit_key_dice_chain()
- .ok_or(anyhow!("Missing explicit dice chain, this is unusual"))?;
- let policy = sealing_policy(explicit_dice_chain)
- .map_err(|e| anyhow!("Failed to build a sealing_policy: {e}"))?;
- if let Some(secret) = get_secret(&mut session, id, Some(policy.clone()))? {
- *skp_secret = secret;
- } else {
- log::warn!(
- "No entry found in Secretkeeper for this VM instance, creating new secret."
- );
- *skp_secret = rand::random();
- store_secret(&mut session, id, skp_secret.clone(), policy)?;
- }
+ if let Some(secret) = session.get_secret(id, Some(policy.clone()))? {
+ *skp_secret = secret
+ } else {
+ log::warn!("No entry found in Secretkeeper for this VM instance, creating new secret.");
+ *skp_secret = rand::random();
+ session.store_secret(id, skp_secret.clone(), policy)?;
}
Ok(Self::V2 {
dice_artifacts: explicit_dice,
@@ -231,48 +226,67 @@
.map_err(|e| format!("DicePolicy construction failed {e:?}"))
}
-fn store_secret(
- session: &mut SkSession,
- id: [u8; ID_SIZE],
- secret: Zeroizing<[u8; SECRET_SIZE]>,
- sealing_policy: Vec<u8>,
-) -> Result<()> {
- let store_request = StoreSecretRequest { id: Id(id), secret: Secret(*secret), sealing_policy };
- log::info!("Secretkeeper operation: {:?}", store_request);
+// The secure session between VM & Secretkeeper
+struct SkVmSession(Arc<Mutex<SkSession>>);
+impl SkVmSession {
+ fn new(
+ vm_service: &Strong<dyn IVirtualMachineService>,
+ dice: &OwnedDiceArtifactsWithExplicitKey,
+ ) -> Result<Self> {
+ let secretkeeper_proxy = get_secretkeeper_service(vm_service)?;
+ let secure_session =
+ SkSession::new(secretkeeper_proxy, dice, Some(get_secretkeeper_identity()?))?;
+ let secure_session = Arc::new(Mutex::new(secure_session));
+ Ok(Self(secure_session))
+ }
- let store_request = store_request.serialize_to_packet().to_vec().map_err(anyhow_err)?;
- let store_response = session.secret_management_request(&store_request)?;
- let store_response = ResponsePacket::from_slice(&store_response).map_err(anyhow_err)?;
- let response_type = store_response.response_type().map_err(anyhow_err)?;
- ensure!(
- response_type == ResponseType::Success,
- "Secretkeeper store failed with error: {:?}",
- *SecretkeeperError::deserialize_from_packet(store_response).map_err(anyhow_err)?
- );
- Ok(())
-}
+ fn store_secret(
+ &self,
+ id: [u8; ID_SIZE],
+ secret: Zeroizing<[u8; SECRET_SIZE]>,
+ sealing_policy: Vec<u8>,
+ ) -> Result<()> {
+ let store_request =
+ StoreSecretRequest { id: Id(id), secret: Secret(*secret), sealing_policy };
+ log::info!("Secretkeeper operation: {:?}", store_request);
-fn get_secret(
- session: &mut SkSession,
- id: [u8; ID_SIZE],
- updated_sealing_policy: Option<Vec<u8>>,
-) -> Result<Option<[u8; SECRET_SIZE]>> {
- let get_request = GetSecretRequest { id: Id(id), updated_sealing_policy };
- log::info!("Secretkeeper operation: {:?}", get_request);
- let get_request = get_request.serialize_to_packet().to_vec().map_err(anyhow_err)?;
- let get_response = session.secret_management_request(&get_request)?;
- let get_response = ResponsePacket::from_slice(&get_response).map_err(anyhow_err)?;
- let response_type = get_response.response_type().map_err(anyhow_err)?;
- if response_type == ResponseType::Success {
- let get_response =
- *GetSecretResponse::deserialize_from_packet(get_response).map_err(anyhow_err)?;
- Ok(Some(get_response.secret.0))
- } else {
- let error = SecretkeeperError::deserialize_from_packet(get_response).map_err(anyhow_err)?;
- if *error == SecretkeeperError::EntryNotFound {
- return Ok(None);
+ let store_request = store_request.serialize_to_packet().to_vec().map_err(anyhow_err)?;
+ let session = &mut *self.0.lock().unwrap();
+ let store_response = session.secret_management_request(&store_request)?;
+ let store_response = ResponsePacket::from_slice(&store_response).map_err(anyhow_err)?;
+ let response_type = store_response.response_type().map_err(anyhow_err)?;
+ ensure!(
+ response_type == ResponseType::Success,
+ "Secretkeeper store failed with error: {:?}",
+ *SecretkeeperError::deserialize_from_packet(store_response).map_err(anyhow_err)?
+ );
+ Ok(())
+ }
+
+ fn get_secret(
+ &self,
+ id: [u8; ID_SIZE],
+ updated_sealing_policy: Option<Vec<u8>>,
+ ) -> Result<Option<[u8; SECRET_SIZE]>> {
+ let get_request = GetSecretRequest { id: Id(id), updated_sealing_policy };
+ log::info!("Secretkeeper operation: {:?}", get_request);
+ let get_request = get_request.serialize_to_packet().to_vec().map_err(anyhow_err)?;
+ let session = &mut *self.0.lock().unwrap();
+ let get_response = session.secret_management_request(&get_request)?;
+ let get_response = ResponsePacket::from_slice(&get_response).map_err(anyhow_err)?;
+ let response_type = get_response.response_type().map_err(anyhow_err)?;
+ if response_type == ResponseType::Success {
+ let get_response =
+ *GetSecretResponse::deserialize_from_packet(get_response).map_err(anyhow_err)?;
+ Ok(Some(get_response.secret.0))
+ } else {
+ let error =
+ SecretkeeperError::deserialize_from_packet(get_response).map_err(anyhow_err)?;
+ if *error == SecretkeeperError::EntryNotFound {
+ return Ok(None);
+ }
+ Err(anyhow!("Secretkeeper get failed: {error:?}"))
}
- Err(anyhow!("Secretkeeper get failed: {error:?}"))
}
}
diff --git a/guest/pvmfw/Android.bp b/guest/pvmfw/Android.bp
index 51f7802..23755cf 100644
--- a/guest/pvmfw/Android.bp
+++ b/guest/pvmfw/Android.bp
@@ -32,7 +32,7 @@
"libuuid_nostd",
"libvirtio_drivers",
"libvmbase",
- "libzerocopy_nostd",
+ "libzerocopy-0.7.35_nostd",
"libzeroize_nostd",
],
}
@@ -77,7 +77,7 @@
"liblibfdt",
"liblog_rust",
"libpvmfw_fdt_template",
- "libzerocopy",
+ "libzerocopy-0.7.35",
],
data: [
":test_pvmfw_devices_vm_dtbo",
@@ -119,7 +119,7 @@
"libdiced_open_dice_nostd",
"libpvmfw_avb_nostd",
"libdiced_sample_inputs_nostd",
- "libzerocopy_nostd",
+ "libzerocopy-0.7.35_nostd",
"libhex",
],
static_libs: ["libopen_dice_clear_memory"],
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index 7c46515..862fb1d 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -15,10 +15,9 @@
//! Low-level entry and exit points of pvmfw.
use crate::config;
-use crate::memory;
+use crate::memory::MemorySlices;
use core::arch::asm;
use core::mem::size_of;
-use core::ops::Range;
use core::slice;
use log::error;
use log::warn;
@@ -88,14 +87,14 @@
let reboot_reason = match main_wrapper(fdt_address, payload_start, payload_size) {
Err(r) => r,
- Ok((next_stage, bcc)) => match next_stage {
- NextStage::LinuxBootWithUart(ep) => jump_to_payload(fdt_address, ep, bcc),
+ Ok((next_stage, slices)) => match next_stage {
+ NextStage::LinuxBootWithUart(ep) => jump_to_payload(ep, &slices),
NextStage::LinuxBoot(ep) => {
if let Err(e) = unshare_uart() {
error!("Failed to unmap UART: {e}");
RebootReason::InternalError
} else {
- jump_to_payload(fdt_address, ep, bcc)
+ jump_to_payload(ep, &slices)
}
}
},
@@ -112,11 +111,11 @@
///
/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
/// the assumption that its environment has been properly configured.
-fn main_wrapper(
+fn main_wrapper<'a>(
fdt: usize,
payload: usize,
payload_size: usize,
-) -> Result<(NextStage, Range<usize>), RebootReason> {
+) -> Result<(NextStage, MemorySlices<'a>), RebootReason> {
// Limitations in this function:
// - only access MMIO once (and while) it has been mapped and configured
// - only perform logging once the logger has been initialized
@@ -136,7 +135,7 @@
let config_entries = appended.get_entries();
- let slices = memory::MemorySlices::new(fdt, payload, payload_size)?;
+ let mut slices = MemorySlices::new(fdt, payload, payload_size)?;
// This wrapper allows main() to be blissfully ignorant of platform details.
let (next_bcc, debuggable_payload) = crate::main(
@@ -148,6 +147,7 @@
config_entries.vm_dtbo,
config_entries.vm_ref_dt,
)?;
+ slices.add_dice_chain(next_bcc);
// Keep UART MMIO_GUARD-ed for debuggable payloads, to enable earlycon.
let keep_uart = cfg!(debuggable_vms_improvements) && debuggable_payload;
@@ -162,7 +162,7 @@
let next_stage = select_next_stage(slices.kernel, keep_uart);
- Ok((next_stage, next_bcc))
+ Ok((next_stage, slices))
}
fn select_next_stage(kernel: &[u8], keep_uart: bool) -> NextStage {
@@ -173,7 +173,16 @@
}
}
-fn jump_to_payload(fdt_address: usize, payload_start: usize, bcc: Range<usize>) -> ! {
+fn jump_to_payload(entrypoint: usize, slices: &MemorySlices) -> ! {
+ let fdt_address = slices.fdt.as_ptr() as usize;
+ let bcc = slices
+ .dice_chain
+ .map(|slice| {
+ let r = slice.as_ptr_range();
+ (r.start as usize)..(r.end as usize)
+ })
+ .expect("Missing DICE chain");
+
deactivate_dynamic_page_tables();
const ASM_STP_ALIGN: usize = size_of::<u64>() * 2;
@@ -313,7 +322,7 @@
eh_stack_end = in(reg) u64::try_from(eh_stack.end.0).unwrap(),
dcache_line_size = in(reg) u64::try_from(min_dcache_line_size()).unwrap(),
in("x0") u64::try_from(fdt_address).unwrap(),
- in("x30") u64::try_from(payload_start).unwrap(),
+ in("x30") u64::try_from(entrypoint).unwrap(),
options(noreturn),
);
};
diff --git a/guest/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index d04db06..a28a039 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -40,7 +40,6 @@
use alloc::borrow::Cow;
use alloc::boxed::Box;
use bssl_avf::Digester;
-use core::ops::Range;
use cstr::cstr;
use diced_open_dice::{bcc_handover_parse, DiceArtifacts, DiceContext, Hidden, VM_KEY_ALGORITHM};
use libfdt::{Fdt, FdtNode};
@@ -54,7 +53,7 @@
use vmbase::rand;
use vmbase::virtio::pci;
-fn main(
+fn main<'a>(
untrusted_fdt: &mut Fdt,
signed_kernel: &[u8],
ramdisk: Option<&[u8]>,
@@ -62,7 +61,7 @@
mut debug_policy: Option<&[u8]>,
vm_dtbo: Option<&mut [u8]>,
vm_ref_dt: Option<&[u8]>,
-) -> Result<(Range<usize>, bool), RebootReason> {
+) -> Result<(&'a [u8], bool), RebootReason> {
info!("pVM firmware");
debug!("FDT: {:?}", untrusted_fdt.as_ptr());
debug!("Signed kernel: {:?} ({:#x} bytes)", signed_kernel.as_ptr(), signed_kernel.len());
@@ -201,13 +200,7 @@
})?;
info!("Starting payload...");
-
- let bcc_range = {
- let r = next_bcc.as_ptr_range();
- (r.start as usize)..(r.end as usize)
- };
-
- Ok((bcc_range, debuggable))
+ Ok((next_bcc, debuggable))
}
// Get the "salt" which is one of the input for DICE derivation.
diff --git a/guest/pvmfw/src/memory.rs b/guest/pvmfw/src/memory.rs
index d2f63b5..a663008 100644
--- a/guest/pvmfw/src/memory.rs
+++ b/guest/pvmfw/src/memory.rs
@@ -31,6 +31,7 @@
pub fdt: &'a mut libfdt::Fdt,
pub kernel: &'a [u8],
pub ramdisk: Option<&'a [u8]>,
+ pub dice_chain: Option<&'a [u8]>,
}
impl<'a> MemorySlices<'a> {
@@ -111,6 +112,12 @@
None
};
- Ok(Self { fdt: untrusted_fdt, kernel, ramdisk })
+ let dice_chain = None;
+
+ Ok(Self { fdt: untrusted_fdt, kernel, ramdisk, dice_chain })
+ }
+
+ pub fn add_dice_chain(&mut self, dice_chain: &'a [u8]) {
+ self.dice_chain = Some(dice_chain)
}
}
diff --git a/guest/trusty/security_vm/launcher/src/main.rs b/guest/trusty/security_vm/launcher/src/main.rs
index 9611f26..f0af9b6 100644
--- a/guest/trusty/security_vm/launcher/src/main.rs
+++ b/guest/trusty/security_vm/launcher/src/main.rs
@@ -78,6 +78,7 @@
memoryMib: args.memory_size_mib,
cpuTopology: args.cpu_topology,
platformVersion: "~1.0".to_owned(),
+ balloon: true, // TODO: probably don't want ballooning.
// TODO: add instanceId
..Default::default()
});
diff --git a/libs/devicemapper/Android.bp b/libs/devicemapper/Android.bp
index 5332469..17727f1 100644
--- a/libs/devicemapper/Android.bp
+++ b/libs/devicemapper/Android.bp
@@ -16,7 +16,7 @@
"libhex",
"libnix",
"libuuid",
- "libzerocopy",
+ "libzerocopy-0.7.35",
],
multilib: {
lib32: {
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 3829f9f..4508573 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -621,8 +621,8 @@
&& this.mVmOutputCaptured == other.mVmOutputCaptured
&& this.mVmConsoleInputSupported == other.mVmConsoleInputSupported
&& this.mConnectVmConsole == other.mConnectVmConsole
- && this.mConsoleInputDevice == other.mConsoleInputDevice
&& (this.mVendorDiskImage == null) == (other.mVendorDiskImage == null)
+ && Objects.equals(this.mConsoleInputDevice, other.mConsoleInputDevice)
&& Objects.equals(this.mPayloadConfigPath, other.mPayloadConfigPath)
&& Objects.equals(this.mPayloadBinaryName, other.mPayloadBinaryName)
&& Objects.equals(this.mPackageName, other.mPackageName)
@@ -798,7 +798,7 @@
Optional.ofNullable(customImageConfig.getAudioConfig())
.map(ac -> ac.toParcelable())
.orElse(null);
- config.noBalloon = !customImageConfig.useAutoMemoryBalloon();
+ config.balloon = customImageConfig.useAutoMemoryBalloon();
config.usbConfig =
Optional.ofNullable(customImageConfig.getUsbConfig())
.map(
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
index 93f29a9..1708caa 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
@@ -486,7 +486,6 @@
private boolean network;
private GpuConfig gpuConfig;
private boolean trackpad;
- // TODO(b/363985291): balloon breaks Linux VM behavior
private boolean autoMemoryBalloon = false;
private UsbConfig usbConfig;
diff --git a/libs/libavf/include/android/virtualization.h b/libs/libavf/include/android/virtualization.h
index f33ee75..85bf3a2 100644
--- a/libs/libavf/include/android/virtualization.h
+++ b/libs/libavf/include/android/virtualization.h
@@ -18,6 +18,8 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <time.h>
__BEGIN_DECLS
@@ -40,9 +42,9 @@
* VM by calling {@link AVirtualMachine_createRaw} or releasing it by calling
* {@link AVirtualMachineRawConfig_destroy}.
*
- * \return A new virtual machine raw config object.
+ * \return A new virtual machine raw config object. On failure (such as out of memory), it aborts.
*/
-AVirtualMachineRawConfig* AVirtualMachineRawConfig_create();
+AVirtualMachineRawConfig* _Nonnull AVirtualMachineRawConfig_create() __INTRODUCED_IN(36);
/**
* Destroy a virtual machine config object.
@@ -52,61 +54,69 @@
* `AVirtualMachineRawConfig_destroy` does nothing if `config` is null. A destroyed config object
* must not be reused.
*/
-void AVirtualMachineRawConfig_destroy(AVirtualMachineRawConfig* config);
+void AVirtualMachineRawConfig_destroy(AVirtualMachineRawConfig* _Nullable config)
+ __INTRODUCED_IN(36);
/**
* Set a name of a virtual machine.
*
* \param config a virtual machine config object.
- * \param name a pointer to a null-terminated string for the name.
+ * \param name a pointer to a null-terminated, UTF-8 encoded string for the name.
*
- * \return If successful, it returns 0.
+ * \return If successful, it returns 0. If `name` is not a null-terminated UTF-8 encoded string,
+ * it returns -EINVAL.
*/
-int AVirtualMachineRawConfig_setName(AVirtualMachineRawConfig* config, const char* name);
+int AVirtualMachineRawConfig_setName(AVirtualMachineRawConfig* _Nonnull config,
+ const char* _Nonnull name) __INTRODUCED_IN(36);
/**
* Set an instance ID of a virtual machine.
*
* \param config a virtual machine config object.
* \param instanceId a pointer to a 64-byte buffer for the instance ID.
+ * \param instanceIdSize the number of bytes in `instanceId`.
*
- * \return If successful, it returns 0.
+ * \return If successful, it returns 0. If `instanceIdSize` is incorrect, it returns -EINVAL.
*/
-int AVirtualMachineRawConfig_setInstanceId(AVirtualMachineRawConfig* config,
- const int8_t* instanceId);
+int AVirtualMachineRawConfig_setInstanceId(AVirtualMachineRawConfig* _Nonnull config,
+ const int8_t* _Nonnull instanceId, size_t instanceIdSize)
+ __INTRODUCED_IN(36);
/**
* Set a kernel image of a virtual machine.
*
* \param config a virtual machine config object.
- * \param fd a readable file descriptor containing the kernel image, or -1 to unset.
- * `AVirtualMachineRawConfig_setKernel` takes ownership of `fd`.
- *
- * \return If successful, it returns 0.
+ * \param fd a readable, seekable, and sized (i.e. report a valid size using fstat()) file
+ * descriptor containing the kernel image, or -1 to unset. `AVirtualMachineRawConfig_setKernel`
+ * takes ownership of `fd`.
*/
-int AVirtualMachineRawConfig_setKernel(AVirtualMachineRawConfig* config, int fd);
+void AVirtualMachineRawConfig_setKernel(AVirtualMachineRawConfig* _Nonnull config, int fd)
+ __INTRODUCED_IN(36);
/**
* Set an init rd of a virtual machine.
*
* \param config a virtual machine config object.
- * \param fd a readable file descriptor containing the kernel image, or -1 to unset.
- * `AVirtualMachineRawConfig_setInitRd` takes ownership of `fd`.
- *
- * \return If successful, it returns 0.
+ * \param fd a readable, seekable, and sized (i.e. report a valid size using fstat()) file
+ * descriptor containing the init rd image, or -1 to unset. `AVirtualMachineRawConfig_setInitRd`
+ * takes ownership of `fd`.
*/
-int AVirtualMachineRawConfig_setInitRd(AVirtualMachineRawConfig* config, int fd);
+void AVirtualMachineRawConfig_setInitRd(AVirtualMachineRawConfig* _Nonnull config, int fd)
+ __INTRODUCED_IN(36);
/**
* Add a disk for a virtual machine.
*
* \param config a virtual machine config object.
- * \param fd a readable file descriptor containing the disk image.
- * `AVirtualMachineRawConfig_addDisk` takes ownership of `fd`.
+ * \param fd a readable, seekable, and sized (i.e. report a valid size using fstat()) file
+ * descriptor containing the disk. `fd` must be writable if If `writable` is true.
+ * `AVirtualMachineRawConfig_addDisk` takes ownership of `fd`.
+ * \param writable whether this disk should be writable by the virtual machine.
*
* \return If successful, it returns 0. If `fd` is invalid, it returns -EINVAL.
*/
-int AVirtualMachineRawConfig_addDisk(AVirtualMachineRawConfig* config, int fd);
+int AVirtualMachineRawConfig_addDisk(AVirtualMachineRawConfig* _Nonnull config, int fd,
+ bool writable) __INTRODUCED_IN(36);
/**
* Set how much memory will be given to a virtual machine.
@@ -114,40 +124,32 @@
* \param config a virtual machine config object.
* \param memoryMib the amount of RAM to give the virtual machine, in MiB. 0 or negative to use the
* default.
- *
- * \return If successful, it returns 0.
*/
-int AVirtualMachineRawConfig_setMemoryMib(AVirtualMachineRawConfig* config, int32_t memoryMib);
+void AVirtualMachineRawConfig_setMemoryMib(AVirtualMachineRawConfig* _Nonnull config,
+ int32_t memoryMib) __INTRODUCED_IN(36);
/**
- * Set whether a virtual machine is protected or not.
+ * Set whether the virtual machine's memory will be protected from the host, so the host can't
+ * access its memory.
*
* \param config a virtual machine config object.
* \param protectedVm whether the virtual machine should be protected.
- *
- * \return If successful, it returns 0.
*/
-int AVirtualMachineRawConfig_setProtectedVm(AVirtualMachineRawConfig* config, bool protectedVm);
-
-/**
- * Set whether a virtual machine uses memory ballooning or not.
- *
- * \param config a virtual machine config object.
- * \param balloon whether the virtual machine should use memory ballooning.
- *
- * \return If successful, it returns 0.
- */
-int AVirtualMachineRawConfig_setBalloon(AVirtualMachineRawConfig* config, bool balloon);
+void AVirtualMachineRawConfig_setProtectedVm(AVirtualMachineRawConfig* _Nonnull config,
+ bool protectedVm) __INTRODUCED_IN(36);
/**
* Set whether to use an alternate, hypervisor-specific authentication method
- * for protected VMs. You don't want to use this.
+ * for protected VMs.
+ *
+ * This option is discouraged. Prefer to use the default authentication method, which is better
+ * tested and integrated into Android. This option must only be used from the vendor partition.
*
* \return If successful, it returns 0. It returns `-ENOTSUP` if the hypervisor doesn't have an
* alternate auth mode.
*/
-int AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(AVirtualMachineRawConfig* config,
- bool enable);
+int AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
+ AVirtualMachineRawConfig* _Nonnull config, bool enable) __INTRODUCED_IN(36);
/**
* Use the specified fd as the backing memfd for a range of the guest
@@ -155,14 +157,15 @@
*
* \param config a virtual machine config object.
* \param fd a memfd
- * \param rangeStart range start IPA
- * \param rangeEnd range end IPA
+ * \param rangeStart range start of guest memory addresses
+ * \param rangeEnd range end of guest memory addresses
*
* \return If successful, it returns 0. It returns `-ENOTSUP` if the hypervisor doesn't support
* backing memfd.
*/
-int AVirtualMachineRawConfig_addCustomMemoryBackingFile(AVirtualMachineRawConfig* config, int fd,
- size_t rangeStart, size_t rangeEnd);
+int AVirtualMachineRawConfig_addCustomMemoryBackingFile(AVirtualMachineRawConfig* _Nonnull config,
+ int fd, uint64_t rangeStart,
+ uint64_t rangeEnd) __INTRODUCED_IN(36);
/**
* Represents a handle on a virtualization service, responsible for managing virtual machines.
@@ -176,8 +179,10 @@
* The caller takes ownership of the returned service object, and is responsible for releasing it
* by calling {@link AVirtualizationService_destroy}.
*
- * \param early set to true when running a service for early virtual machines. See
- * [`early_vm.md`](../../../../docs/early_vm.md) for more details on early virtual machines.
+ * \param early set to true when running a service for early virtual machines. Early VMs are
+ * specialized virtual machines that can run even before the `/data` partition is mounted.
+ * Early VMs must be pre-defined in XML files located at `{partition}/etc/avf/early_vms*.xml`, and
+ * clients of early VMs must be pre-installed under the same partition.
* \param service an out parameter that will be set to the service handle.
*
* \return
@@ -187,7 +192,8 @@
* - If it fails to connect to the spawned `virtmgr`, it leaves `service` untouched and returns
* `-ECONNREFUSED`.
*/
-int AVirtualizationService_create(AVirtualizationService** service, bool early);
+int AVirtualizationService_create(AVirtualizationService* _Null_unspecified* _Nonnull service,
+ bool early) __INTRODUCED_IN(36);
/**
* Destroy a VirtualizationService object.
@@ -197,7 +203,7 @@
*
* \param service a handle on a virtualization service.
*/
-void AVirtualizationService_destroy(AVirtualizationService* service);
+void AVirtualizationService_destroy(AVirtualizationService* _Nullable service) __INTRODUCED_IN(36);
/**
* Represents a handle on a virtual machine.
@@ -208,55 +214,55 @@
* The reason why a virtual machine stopped.
* @see AVirtualMachine_waitForStop
*/
-enum StopReason : int32_t {
+enum AVirtualMachineStopReason : int32_t {
/**
* VirtualizationService died.
*/
- VIRTUALIZATION_SERVICE_DIED = 1,
+ AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED = 1,
/**
* There was an error waiting for the virtual machine.
*/
- INFRASTRUCTURE_ERROR = 2,
+ AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR = 2,
/**
* The virtual machine was killed.
*/
- KILLED = 3,
+ AVIRTUAL_MACHINE_KILLED = 3,
/**
* The virtual machine stopped for an unknown reason.
*/
- UNKNOWN = 4,
+ AVIRTUAL_MACHINE_UNKNOWN = 4,
/**
* The virtual machine requested to shut down.
*/
- SHUTDOWN = 5,
+ AVIRTUAL_MACHINE_SHUTDOWN = 5,
/**
* crosvm had an error starting the virtual machine.
*/
- START_FAILED = 6,
+ AVIRTUAL_MACHINE_START_FAILED = 6,
/**
* The virtual machine requested to reboot, possibly as the result of a kernel panic.
*/
- REBOOT = 7,
+ AVIRTUAL_MACHINE_REBOOT = 7,
/**
* The virtual machine or crosvm crashed.
*/
- CRASH = 8,
+ AVIRTUAL_MACHINE_CRASH = 8,
/**
* The pVM firmware failed to verify the VM because the public key doesn't match.
*/
- PVM_FIRMWARE_PUBLIC_KEY_MISMATCH = 9,
+ AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH = 9,
/**
* The pVM firmware failed to verify the VM because the instance image changed.
*/
- PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED = 10,
+ AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED = 10,
/**
* The virtual machine was killed due to hangup.
*/
- HANGUP = 11,
+ AVIRTUAL_MACHINE_HANGUP = 11,
/**
* VirtualizationService sent a stop reason which was not recognised by the client library.
*/
- UNRECOGNISED = 0,
+ AVIRTUAL_MACHINE_UNRECOGNISED = 0,
};
/**
@@ -282,45 +288,67 @@
* \return If successful, it sets `vm` and returns 0. Otherwise, it leaves `vm` untouched and
* returns `-EIO`.
*/
-int AVirtualMachine_createRaw(const AVirtualizationService* service,
- AVirtualMachineRawConfig* config, int consoleOutFd, int consoleInFd,
- int logFd, AVirtualMachine** vm);
+int AVirtualMachine_createRaw(const AVirtualizationService* _Nonnull service,
+ AVirtualMachineRawConfig* _Nonnull config, int consoleOutFd,
+ int consoleInFd, int logFd,
+ AVirtualMachine* _Null_unspecified* _Nonnull vm) __INTRODUCED_IN(36);
/**
- * Start a virtual machine.
+ * Start a virtual machine. `AVirtualMachine_start` is synchronous and blocks until the virtual
+ * machine is initialized and free to start executing code, or until an error happens.
*
* \param vm a handle on a virtual machine.
*
* \return If successful, it returns 0. Otherwise, it returns `-EIO`.
*/
-int AVirtualMachine_start(AVirtualMachine* vm);
+int AVirtualMachine_start(AVirtualMachine* _Nonnull vm) __INTRODUCED_IN(36);
/**
- * Stop a virtual machine.
+ * Stop a virtual machine. Stopping a virtual machine is like pulling the plug on a real computer;
+ * the machine halts immediately. Software running on the virtual machine is not notified of the
+ * event, the instance might be left in an inconsistent state.
+ *
+ * For a graceful shutdown, you could request the virtual machine to exit itself, and wait for the
+ * virtual machine to stop by `AVirtualMachine_waitForStop`.
+ *
+ * A stopped virtual machine can be re-started by calling `AVirtualMachine_start`.
+ *
+ * `AVirtualMachine_stop` stops a virtual machine by sending a signal to the process. This operation
+ * is synchronous and `AVirtualMachine_stop` may block.
*
* \param vm a handle on a virtual machine.
*
* \return If successful, it returns 0. Otherwise, it returns `-EIO`.
*/
-int AVirtualMachine_stop(AVirtualMachine* vm);
+int AVirtualMachine_stop(AVirtualMachine* _Nonnull vm) __INTRODUCED_IN(36);
/**
- * Wait until a virtual machine stops.
+ * Wait until a virtual machine stops or the given timeout elapses.
*
* \param vm a handle on a virtual machine.
+ * \param timeout the timeout, or null to wait indefinitely.
+ * \param reason An out parameter that will be set to the reason why the virtual machine stopped.
*
- * \return The reason why the virtual machine stopped.
+ * \return
+ * - If the virtual machine stops within the timeout (or indefinitely if `timeout` is null), it
+ * sets `reason` and returns true.
+ * - If the timeout expired, it returns `false`.
*/
-enum StopReason AVirtualMachine_waitForStop(AVirtualMachine* vm);
+bool AVirtualMachine_waitForStop(AVirtualMachine* _Nonnull vm,
+ const struct timespec* _Nullable timeout,
+ enum AVirtualMachineStopReason* _Nonnull reason)
+ __INTRODUCED_IN(36);
/**
- * Destroy a virtual machine.
+ * Destroy a virtual machine object. If the virtual machine is still running,
+ * `AVirtualMachine_destroy` first stops the virtual machine by sending a signal to the process.
+ * This operation is synchronous and `AVirtualMachine_destroy` may block.
*
* `AVirtualMachine_destroy` does nothing if `vm` is null. A destroyed virtual machine must not be
* reused.
*
* \param vm a handle on a virtual machine.
*/
-void AVirtualMachine_destroy(AVirtualMachine* vm);
+void AVirtualMachine_destroy(AVirtualMachine* _Nullable vm) __INTRODUCED_IN(36);
__END_DECLS
diff --git a/libs/libavf/libavf.map.txt b/libs/libavf/libavf.map.txt
index ecb4cc9..f476566 100644
--- a/libs/libavf/libavf.map.txt
+++ b/libs/libavf/libavf.map.txt
@@ -9,7 +9,6 @@
AVirtualMachineRawConfig_addDisk; # apex llndk
AVirtualMachineRawConfig_setMemoryMib; # apex llndk
AVirtualMachineRawConfig_setProtectedVm; # apex llndk
- AVirtualMachineRawConfig_setBalloon; # apex llndk
AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod; # apex llndk
AVirtualMachineRawConfig_addCustomMemoryBackingFile; # apex llndk
AVirtualizationService_create; # apex llndk
diff --git a/libs/libavf/src/lib.rs b/libs/libavf/src/lib.rs
index 0a8f891..5988fae 100644
--- a/libs/libavf/src/lib.rs
+++ b/libs/libavf/src/lib.rs
@@ -19,6 +19,7 @@
use std::os::fd::FromRawFd;
use std::os::raw::{c_char, c_int};
use std::ptr;
+use std::time::Duration;
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::{
@@ -28,7 +29,8 @@
},
binder::{ParcelFileDescriptor, Strong},
};
-use avf_bindgen::StopReason;
+use avf_bindgen::AVirtualMachineStopReason;
+use libc::timespec;
use vmclient::{DeathReason, VirtualizationService, VmInstance};
/// Create a new virtual machine config object with no properties.
@@ -70,8 +72,14 @@
// AVirtualMachineRawConfig_create. It's the only reference to the object.
let config = unsafe { &mut *config };
// SAFETY: `name` is assumed to be a pointer to a valid C string.
- config.name = unsafe { CStr::from_ptr(name) }.to_string_lossy().into_owned();
- 0
+ let name = unsafe { CStr::from_ptr(name) };
+ match name.to_str() {
+ Ok(name) => {
+ config.name = name.to_owned();
+ 0
+ }
+ Err(_) => -libc::EINVAL,
+ }
}
/// Set an instance ID of a virtual machine.
@@ -83,7 +91,12 @@
pub unsafe extern "C" fn AVirtualMachineRawConfig_setInstanceId(
config: *mut VirtualMachineRawConfig,
instance_id: *const u8,
+ instance_id_size: usize,
) -> c_int {
+ if instance_id_size != 64 {
+ return -libc::EINVAL;
+ }
+
// SAFETY: `config` is assumed to be a valid, non-null pointer returned by
// AVirtualMachineRawConfig_create. It's the only reference to the object.
let config = unsafe { &mut *config };
@@ -91,7 +104,7 @@
// is assumed to be a valid object returned by AVirtuaMachineConfig_create.
// Both never overlap.
unsafe {
- ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), 64);
+ ptr::copy_nonoverlapping(instance_id, config.instanceId.as_mut_ptr(), instance_id_size);
}
0
}
@@ -106,13 +119,12 @@
pub unsafe extern "C" fn AVirtualMachineRawConfig_setKernel(
config: *mut VirtualMachineRawConfig,
fd: c_int,
-) -> c_int {
+) {
let file = get_file_from_fd(fd);
// SAFETY: `config` is assumed to be a valid, non-null pointer returned by
// AVirtualMachineRawConfig_create. It's the only reference to the object.
let config = unsafe { &mut *config };
config.kernel = file.map(ParcelFileDescriptor::new);
- 0
}
/// Set an init rd of a virtual machine.
@@ -125,13 +137,12 @@
pub unsafe extern "C" fn AVirtualMachineRawConfig_setInitRd(
config: *mut VirtualMachineRawConfig,
fd: c_int,
-) -> c_int {
+) {
let file = get_file_from_fd(fd);
// SAFETY: `config` is assumed to be a valid, non-null pointer returned by
// AVirtualMachineRawConfig_create. It's the only reference to the object.
let config = unsafe { &mut *config };
config.initrd = file.map(ParcelFileDescriptor::new);
- 0
}
/// Add a disk for a virtual machine.
@@ -172,12 +183,11 @@
pub unsafe extern "C" fn AVirtualMachineRawConfig_setMemoryMib(
config: *mut VirtualMachineRawConfig,
memory_mib: i32,
-) -> c_int {
+) {
// SAFETY: `config` is assumed to be a valid, non-null pointer returned by
// AVirtualMachineRawConfig_create. It's the only reference to the object.
let config = unsafe { &mut *config };
config.memoryMib = memory_mib;
- 0
}
/// Set whether a virtual machine is protected or not.
@@ -188,28 +198,11 @@
pub unsafe extern "C" fn AVirtualMachineRawConfig_setProtectedVm(
config: *mut VirtualMachineRawConfig,
protected_vm: bool,
-) -> c_int {
+) {
// SAFETY: `config` is assumed to be a valid, non-null pointer returned by
// AVirtualMachineRawConfig_create. It's the only reference to the object.
let config = unsafe { &mut *config };
config.protectedVm = protected_vm;
- 0
-}
-
-/// Set whether a virtual machine uses memory ballooning or not.
-///
-/// # Safety
-/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
-#[no_mangle]
-pub unsafe extern "C" fn AVirtualMachineRawConfig_setBalloon(
- config: *mut VirtualMachineRawConfig,
- balloon: bool,
-) -> c_int {
- // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
- // AVirtualMachineRawConfig_create. It's the only reference to the object.
- let config = unsafe { &mut *config };
- config.noBalloon = !balloon;
- 0
}
/// NOT IMPLEMENTED.
@@ -232,8 +225,8 @@
pub extern "C" fn AVirtualMachineRawConfig_addCustomMemoryBackingFile(
_config: *mut VirtualMachineRawConfig,
_fd: c_int,
- _range_start: usize,
- _range_end: usize,
+ _range_start: u64,
+ _range_end: u64,
) -> c_int {
-libc::ENOTSUP
}
@@ -360,31 +353,64 @@
}
}
-/// Wait until a virtual machine stops.
+fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
+ match death_reason {
+ DeathReason::VirtualizationServiceDied => {
+ AVirtualMachineStopReason::AVIRTUAL_MACHINE_VIRTUALIZATION_SERVICE_DIED
+ }
+ DeathReason::InfrastructureError => {
+ AVirtualMachineStopReason::AVIRTUAL_MACHINE_INFRASTRUCTURE_ERROR
+ }
+ DeathReason::Killed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_KILLED,
+ DeathReason::Unknown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNKNOWN,
+ DeathReason::Shutdown => AVirtualMachineStopReason::AVIRTUAL_MACHINE_SHUTDOWN,
+ DeathReason::StartFailed => AVirtualMachineStopReason::AVIRTUAL_MACHINE_START_FAILED,
+ DeathReason::Reboot => AVirtualMachineStopReason::AVIRTUAL_MACHINE_REBOOT,
+ DeathReason::Crash => AVirtualMachineStopReason::AVIRTUAL_MACHINE_CRASH,
+ DeathReason::PvmFirmwarePublicKeyMismatch => {
+ AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_PUBLIC_KEY_MISMATCH
+ }
+ DeathReason::PvmFirmwareInstanceImageChanged => {
+ AVirtualMachineStopReason::AVIRTUAL_MACHINE_PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
+ }
+ DeathReason::Hangup => AVirtualMachineStopReason::AVIRTUAL_MACHINE_HANGUP,
+ _ => AVirtualMachineStopReason::AVIRTUAL_MACHINE_UNRECOGNISED,
+ }
+}
+
+/// Wait until a virtual machine stops or the timeout elapses.
///
/// # Safety
-/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`.
+/// `vm` must be a pointer returned by `AVirtualMachine_createRaw`. `timeout` must be a valid
+/// pointer to a `struct timespec` object or null. `reason` must be a valid, non-null pointer to an
+/// AVirtualMachineStopReason object.
#[no_mangle]
-pub unsafe extern "C" fn AVirtualMachine_waitForStop(vm: *const VmInstance) -> StopReason {
+pub unsafe extern "C" fn AVirtualMachine_waitForStop(
+ vm: *const VmInstance,
+ timeout: *const timespec,
+ reason: *mut AVirtualMachineStopReason,
+) -> bool {
// SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
// AVirtualMachine_create. It's the only reference to the object.
let vm = unsafe { &*vm };
- match vm.wait_for_death() {
- DeathReason::VirtualizationServiceDied => StopReason::VIRTUALIZATION_SERVICE_DIED,
- DeathReason::InfrastructureError => StopReason::INFRASTRUCTURE_ERROR,
- DeathReason::Killed => StopReason::KILLED,
- DeathReason::Unknown => StopReason::UNKNOWN,
- DeathReason::Shutdown => StopReason::SHUTDOWN,
- DeathReason::StartFailed => StopReason::START_FAILED,
- DeathReason::Reboot => StopReason::REBOOT,
- DeathReason::Crash => StopReason::CRASH,
- DeathReason::PvmFirmwarePublicKeyMismatch => StopReason::PVM_FIRMWARE_PUBLIC_KEY_MISMATCH,
- DeathReason::PvmFirmwareInstanceImageChanged => {
- StopReason::PVM_FIRMWARE_INSTANCE_IMAGE_CHANGED
+
+ let death_reason = if timeout.is_null() {
+ vm.wait_for_death()
+ } else {
+ // SAFETY: `timeout` is assumed to be a valid pointer to a `struct timespec` object if
+ // non-null.
+ let timeout = unsafe { &*timeout };
+ let timeout = Duration::new(timeout.tv_sec as u64, timeout.tv_nsec as u32);
+ match vm.wait_for_death_with_timeout(timeout) {
+ Some(death_reason) => death_reason,
+ None => return false,
}
- DeathReason::Hangup => StopReason::HANGUP,
- _ => StopReason::UNRECOGNISED,
- }
+ };
+
+ // SAFETY: `reason` is assumed to be a valid, non-null pointer to an
+ // AVirtualMachineStopReason object.
+ unsafe { *reason = death_reason_to_stop_reason(death_reason) };
+ true
}
/// Destroy a virtual machine.
diff --git a/libs/libfdt/Android.bp b/libs/libfdt/Android.bp
index 09f288d..1e24ff4 100644
--- a/libs/libfdt/Android.bp
+++ b/libs/libfdt/Android.bp
@@ -38,7 +38,7 @@
"libcstr",
"liblibfdt_bindgen",
"libstatic_assertions",
- "libzerocopy_nostd",
+ "libzerocopy-0.7.35_nostd",
],
}
diff --git a/libs/libservice_vm_manager/src/lib.rs b/libs/libservice_vm_manager/src/lib.rs
index 0f322bb..5bb97d7 100644
--- a/libs/libservice_vm_manager/src/lib.rs
+++ b/libs/libservice_vm_manager/src/lib.rs
@@ -238,7 +238,8 @@
memoryMib: VM_MEMORY_MB,
cpuTopology: CpuTopology::ONE_CPU,
platformVersion: "~1.0".to_string(),
- gdbPort: 0, // No gdb
+ gdbPort: 0, // No gdb
+ balloon: true, // TODO: probably don't want ballooning.
..Default::default()
});
let console_out = Some(android_log_fd()?);
diff --git a/libs/libvmbase/Android.bp b/libs/libvmbase/Android.bp
index 3088633..7bcdc1d 100644
--- a/libs/libvmbase/Android.bp
+++ b/libs/libvmbase/Android.bp
@@ -91,7 +91,7 @@
"libtinyvec_nostd",
"libuuid_nostd",
"libvirtio_drivers",
- "libzerocopy_nostd",
+ "libzerocopy-0.7.35_nostd",
"libzeroize_nostd",
],
whole_static_libs: [
diff --git a/libs/vmconfig/src/lib.rs b/libs/vmconfig/src/lib.rs
index ef932c2..e520f0e 100644
--- a/libs/vmconfig/src/lib.rs
+++ b/libs/vmconfig/src/lib.rs
@@ -133,6 +133,7 @@
.collect::<Result<_>>()?,
consoleInputDevice: self.console_input_device.clone(),
usbConfig: usb_config,
+ balloon: true,
..Default::default()
})
}
diff --git a/microfuchsia/microfuchsiad/src/instance_starter.rs b/microfuchsia/microfuchsiad/src/instance_starter.rs
index 8216039..e3c4e8d 100644
--- a/microfuchsia/microfuchsiad/src/instance_starter.rs
+++ b/microfuchsia/microfuchsiad/src/instance_starter.rs
@@ -86,6 +86,7 @@
platformVersion: "1.0.0".into(),
#[cfg(enable_console)]
consoleInputDevice: Some("ttyS0".into()),
+ balloon: true,
..Default::default()
});
let vm_instance = VmInstance::create(