Merge "Check API version levels for backcompat tests" into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
index efe651e..9f4909d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
@@ -18,12 +18,21 @@
import android.app.Application as AndroidApplication
import android.app.NotificationChannel
import android.app.NotificationManager
+import android.content.ComponentName
import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.IBinder
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.ProcessLifecycleOwner
public class Application : AndroidApplication() {
override fun onCreate() {
super.onCreate()
setupNotificationChannels()
+ val lifecycleObserver = ApplicationLifecycleObserver()
+ ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleObserver)
}
private fun setupNotificationChannels() {
@@ -52,4 +61,53 @@
fun getInstance(c: Context): Application = c.getApplicationContext() as Application
}
+
+ /**
+ * Observes application lifecycle events and interacts with the VmLauncherService to manage
+ * virtual machine state based on application lifecycle transitions. This class binds to the
+ * VmLauncherService and notifies it of application lifecycle events (onStart, onStop), allowing
+ * the service to manage the VM accordingly.
+ */
+ inner class ApplicationLifecycleObserver() : DefaultLifecycleObserver {
+ private var vmLauncherService: VmLauncherService? = null
+ private val connection =
+ object : ServiceConnection {
+ override fun onServiceConnected(className: ComponentName, service: IBinder) {
+ val binder = service as VmLauncherService.VmLauncherServiceBinder
+ vmLauncherService = binder.getService()
+ }
+
+ override fun onServiceDisconnected(arg0: ComponentName) {
+ vmLauncherService = null
+ }
+ }
+
+ override fun onCreate(owner: LifecycleOwner) {
+ super.onCreate(owner)
+ bindToVmLauncherService()
+ }
+
+ override fun onStart(owner: LifecycleOwner) {
+ super.onStart(owner)
+ vmLauncherService?.processAppLifeCycleEvent(ApplicationLifeCycleEvent.APP_ON_START)
+ }
+
+ override fun onStop(owner: LifecycleOwner) {
+ vmLauncherService?.processAppLifeCycleEvent(ApplicationLifeCycleEvent.APP_ON_STOP)
+ super.onStop(owner)
+ }
+
+ override fun onDestroy(owner: LifecycleOwner) {
+ if (vmLauncherService != null) {
+ this@Application.unbindService(connection)
+ vmLauncherService = null
+ }
+ super.onDestroy(owner)
+ }
+
+ fun bindToVmLauncherService() {
+ val intent = Intent(this@Application, VmLauncherService::class.java)
+ this@Application.bindService(intent, connection, 0) // No BIND_AUTO_CREATE
+ }
+ }
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ApplicationLifeCycleEvent.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ApplicationLifeCycleEvent.kt
new file mode 100644
index 0000000..4e26c3c
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ApplicationLifeCycleEvent.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+enum class ApplicationLifeCycleEvent {
+ APP_ON_START,
+ APP_ON_STOP,
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
index 017ff89..be1f922 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
@@ -65,6 +65,14 @@
}
}
+ /** Returns path to the archive. */
+ fun getPath(): String {
+ return when (source) {
+ is UrlSource -> source.value.toString()
+ is PathSource -> source.value.toString()
+ }
+ }
+
/** Returns size of the archive in bytes */
@Throws(IOException::class)
fun getSize(): Long {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
index 7180e87..01c3880 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
@@ -150,21 +150,26 @@
private fun downloadFromSdcard(): Boolean {
val archive = fromSdCard()
+ val archive_path = archive.getPath()
// Installing from sdcard is preferred, but only supported only in debuggable build.
- if (Build.isDebuggable() && archive.exists()) {
- Log.i(TAG, "trying to install /sdcard/linux/images.tar.gz")
+ if (!Build.isDebuggable()) {
+ Log.i(TAG, "Non-debuggable build doesn't support installation from $archive_path")
+ return false
+ }
+ if (!archive.exists()) {
+ return false
+ }
- val dest = getDefault(this).installDir
- try {
- archive.installTo(dest, null)
- Log.i(TAG, "image is installed from /sdcard/linux/images.tar.gz")
- return true
- } catch (e: IOException) {
- Log.i(TAG, "Failed to install /sdcard/linux/images.tar.gz", e)
- }
- } else {
- Log.i(TAG, "Non-debuggable build doesn't support installation from /sdcard/linux")
+ Log.i(TAG, "trying to install $archive_path")
+
+ val dest = getDefault(this).installDir
+ try {
+ archive.installTo(dest, null)
+ Log.i(TAG, "image is installed from $archive_path")
+ return true
+ } catch (e: IOException) {
+ Log.i(TAG, "Failed to install $archive_path", e)
}
return false
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 6301da4..4aac37a 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -62,6 +62,12 @@
import java.util.concurrent.Executors
class VmLauncherService : Service() {
+ inner class VmLauncherServiceBinder : android.os.Binder() {
+ fun getService(): VmLauncherService = this@VmLauncherService
+ }
+
+ private val binder = VmLauncherServiceBinder()
+
// TODO: using lateinit for some fields to avoid null
private var executorService: ExecutorService? = null
private var virtualMachine: VirtualMachine? = null
@@ -79,7 +85,32 @@
}
override fun onBind(intent: Intent?): IBinder? {
- return null
+ return binder
+ }
+
+ /**
+ * Processes application lifecycle events and adjusts the virtual machine's memory balloon
+ * accordingly.
+ *
+ * @param event The application lifecycle event.
+ */
+ fun processAppLifeCycleEvent(event: ApplicationLifeCycleEvent) {
+ when (event) {
+ // When the app starts, reset the memory balloon to 0%.
+ // This gives the app maximum available memory.
+ ApplicationLifeCycleEvent.APP_ON_START -> {
+ virtualMachine?.setMemoryBalloonByPercent(0)
+ }
+ ApplicationLifeCycleEvent.APP_ON_STOP -> {
+ // When the app stops, inflate the memory balloon to 10%.
+ // This allows the system to reclaim memory while the app is in the background.
+ // TODO(b/400590341) Inflate the balloon while the application remains Stop status.
+ virtualMachine?.setMemoryBalloonByPercent(10)
+ }
+ else -> {
+ Log.e(TAG, "unrecognized lifecycle event: $event")
+ }
+ }
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
@@ -108,10 +139,7 @@
val displaySize = intent.getParcelableExtra(EXTRA_DISPLAY_INFO, DisplayInfo::class.java)
customImageConfigBuilder.setAudioConfig(
- AudioConfig.Builder()
- .setUseSpeaker(true)
- .setUseMicrophone(true)
- .build()
+ AudioConfig.Builder().setUseSpeaker(true).setUseMicrophone(true).build()
)
if (overrideConfigIfNecessary(customImageConfigBuilder, displaySize)) {
configBuilder.setCustomImageConfig(customImageConfigBuilder.build())
@@ -227,6 +255,21 @@
)
Toast.makeText(this, R.string.virgl_enabled, Toast.LENGTH_SHORT).show()
changed = true
+ } else if (Files.exists(ImageArchive.getSdcardPathForTesting().resolve("gfxstream"))) {
+ // TODO: check if the configuration is right. current config comes from cuttlefish's one
+ builder.setGpuConfig(
+ VirtualMachineCustomImageConfig.GpuConfig.Builder()
+ .setBackend("gfxstream")
+ .setRendererUseEgl(false)
+ .setRendererUseGles(false)
+ .setRendererUseGlx(false)
+ .setRendererUseSurfaceless(true)
+ .setRendererUseVulkan(true)
+ .setContextTypes(arrayOf<String>("gfxstream-vulkan", "gfxstream-composer"))
+ .build()
+ )
+ Toast.makeText(this, "gfxstream", Toast.LENGTH_SHORT).show()
+ changed = true
}
// Set the initial display size
diff --git a/android/TerminalApp/res/values-af/strings.xml b/android/TerminalApp/res/values-af/strings.xml
index 6928614..d906b07 100644
--- a/android/TerminalApp/res/values-af/strings.xml
+++ b/android/TerminalApp/res/values-af/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> is geaktiveer"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Take wat lank neem"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Stelselgebeurtenisse"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
</resources>
diff --git a/android/TerminalApp/res/values-az/strings.xml b/android/TerminalApp/res/values-az/strings.xml
index 9b84701..b3ad1f6 100644
--- a/android/TerminalApp/res/values-az/strings.xml
+++ b/android/TerminalApp/res/values-az/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> aktivləşdirilib"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Uzunmüddətli tapşırıqlar"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Sistem tədbirləri"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
</resources>
diff --git a/android/TerminalApp/res/values-b+sr+Latn/strings.xml b/android/TerminalApp/res/values-b+sr+Latn/strings.xml
index 1bdef6d..6ec0a06 100644
--- a/android/TerminalApp/res/values-b+sr+Latn/strings.xml
+++ b/android/TerminalApp/res/values-b+sr+Latn/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> je omogućen"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Dugotrajni zadaci"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Sistemski događaji"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Kartica"</string>
</resources>
diff --git a/android/TerminalApp/res/values-be/strings.xml b/android/TerminalApp/res/values-be/strings.xml
index a056517..e78ba9c 100644
--- a/android/TerminalApp/res/values-be/strings.xml
+++ b/android/TerminalApp/res/values-be/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Модуль <xliff:g id="ID_1">VirGL</xliff:g> уключаны"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Працяглыя задачы"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Сістэмныя падзеі"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Укладка"</string>
</resources>
diff --git a/android/TerminalApp/res/values-bn/strings.xml b/android/TerminalApp/res/values-bn/strings.xml
index e81c3ea..f871f00 100644
--- a/android/TerminalApp/res/values-bn/strings.xml
+++ b/android/TerminalApp/res/values-bn/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> চালু করা আছে"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"দীর্ঘ সময় ধরে চালানো টাস্ক"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"সিস্টেম ইভেন্ট"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"ট্যাব"</string>
</resources>
diff --git a/android/TerminalApp/res/values-bs/strings.xml b/android/TerminalApp/res/values-bs/strings.xml
index 914cff9..1971481 100644
--- a/android/TerminalApp/res/values-bs/strings.xml
+++ b/android/TerminalApp/res/values-bs/strings.xml
@@ -90,5 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Omogućeno: <xliff:g id="ID_1">VirGL</xliff:g>"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Dugotrajni zadaci"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Događaji sistema"</string>
- <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
+ <string name="tab_default_title" msgid="2300417689389397930">"Kartica"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ca/strings.xml b/android/TerminalApp/res/values-ca/strings.xml
index 7cb50d9..db72829 100644
--- a/android/TerminalApp/res/values-ca/strings.xml
+++ b/android/TerminalApp/res/values-ca/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> està activat"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Tasques de llarga durada"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Esdeveniments del sistema"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
</resources>
diff --git a/android/TerminalApp/res/values-cs/strings.xml b/android/TerminalApp/res/values-cs/strings.xml
index 41e7756..14fcd27 100644
--- a/android/TerminalApp/res/values-cs/strings.xml
+++ b/android/TerminalApp/res/values-cs/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Modul <xliff:g id="ID_1">VirGL</xliff:g> je aktivován"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Dlouho spuštěné úlohy"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Systémové události"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Karta"</string>
</resources>
diff --git a/android/TerminalApp/res/values-da/strings.xml b/android/TerminalApp/res/values-da/strings.xml
index e3eb0a8..4e153ef 100644
--- a/android/TerminalApp/res/values-da/strings.xml
+++ b/android/TerminalApp/res/values-da/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> er aktiveret"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Længerevarende opgaver"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Systemhændelser"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Fane"</string>
</resources>
diff --git a/android/TerminalApp/res/values-es/strings.xml b/android/TerminalApp/res/values-es/strings.xml
index 3cabc84..76ebaf9 100644
--- a/android/TerminalApp/res/values-es/strings.xml
+++ b/android/TerminalApp/res/values-es/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> se ha habilitado"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Tareas de larga duración"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Eventos del sistema"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
</resources>
diff --git a/android/TerminalApp/res/values-et/strings.xml b/android/TerminalApp/res/values-et/strings.xml
index 4adaa33..5234a4e 100644
--- a/android/TerminalApp/res/values-et/strings.xml
+++ b/android/TerminalApp/res/values-et/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> on lubatud"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Pikalt kestvad ülesanded"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Süsteemisündmused"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tabulaator"</string>
</resources>
diff --git a/android/TerminalApp/res/values-eu/strings.xml b/android/TerminalApp/res/values-eu/strings.xml
index 63aa7bb..403c305 100644
--- a/android/TerminalApp/res/values-eu/strings.xml
+++ b/android/TerminalApp/res/values-eu/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> gaituta dago"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Luze exekutatzen diren zereginak"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Sistemako gertaerak"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Fitxa"</string>
</resources>
diff --git a/android/TerminalApp/res/values-fr-rCA/strings.xml b/android/TerminalApp/res/values-fr-rCA/strings.xml
index 3660576..d4c1235 100644
--- a/android/TerminalApp/res/values-fr-rCA/strings.xml
+++ b/android/TerminalApp/res/values-fr-rCA/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> est activé"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Tâches de longue durée"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Événements système"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Onglet"</string>
</resources>
diff --git a/android/TerminalApp/res/values-hu/strings.xml b/android/TerminalApp/res/values-hu/strings.xml
index afde089..bd4fe52 100644
--- a/android/TerminalApp/res/values-hu/strings.xml
+++ b/android/TerminalApp/res/values-hu/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"A(z) <xliff:g id="ID_1">VirGL</xliff:g> engedélyezve van"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Hosszan futó feladatok"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Rendszeresemények"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Lap"</string>
</resources>
diff --git a/android/TerminalApp/res/values-hy/strings.xml b/android/TerminalApp/res/values-hy/strings.xml
index 0df7a91..d33642c 100644
--- a/android/TerminalApp/res/values-hy/strings.xml
+++ b/android/TerminalApp/res/values-hy/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g>-ը միացված է"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Երկար աշխատող առաջադրանքներ"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Համակարգի իրադարձություններ"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Ներդիր"</string>
</resources>
diff --git a/android/TerminalApp/res/values-is/strings.xml b/android/TerminalApp/res/values-is/strings.xml
index 4d3d7a6..e7aad2b 100644
--- a/android/TerminalApp/res/values-is/strings.xml
+++ b/android/TerminalApp/res/values-is/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Kveikt er á <xliff:g id="ID_1">VirGL</xliff:g>"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Langvarandi verkefni"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Kerfistilvik"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Flipi"</string>
</resources>
diff --git a/android/TerminalApp/res/values-iw/strings.xml b/android/TerminalApp/res/values-iw/strings.xml
index 6b56764..6d2a0f3 100644
--- a/android/TerminalApp/res/values-iw/strings.xml
+++ b/android/TerminalApp/res/values-iw/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> מופעל"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"משימות ממושכות"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"אירועי מערכת"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"כרטיסייה"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ky/strings.xml b/android/TerminalApp/res/values-ky/strings.xml
index 814c808..c80f891 100644
--- a/android/TerminalApp/res/values-ky/strings.xml
+++ b/android/TerminalApp/res/values-ky/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> иштетилди"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Узак тапшырмалар"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Тутумдук иш-чаралар"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Өтмөк"</string>
</resources>
diff --git a/android/TerminalApp/res/values-lv/strings.xml b/android/TerminalApp/res/values-lv/strings.xml
index 412b454..b87f61f 100644
--- a/android/TerminalApp/res/values-lv/strings.xml
+++ b/android/TerminalApp/res/values-lv/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> ir iespējots"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Ilgstoši uzdevumi"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Sistēmas notikumi"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Cilne"</string>
</resources>
diff --git a/android/TerminalApp/res/values-mk/strings.xml b/android/TerminalApp/res/values-mk/strings.xml
index 00ee26b..d071f41 100644
--- a/android/TerminalApp/res/values-mk/strings.xml
+++ b/android/TerminalApp/res/values-mk/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Овозможено: <xliff:g id="ID_1">VirGL</xliff:g>"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Задачи што се извршуваат долго"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Системски настани"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Картичка"</string>
</resources>
diff --git a/android/TerminalApp/res/values-nb/strings.xml b/android/TerminalApp/res/values-nb/strings.xml
index 3d3a50a..7481be8 100644
--- a/android/TerminalApp/res/values-nb/strings.xml
+++ b/android/TerminalApp/res/values-nb/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> er aktivert"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Langvarige oppgaver"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Systemhendelser"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Fane"</string>
</resources>
diff --git a/android/TerminalApp/res/values-pl/strings.xml b/android/TerminalApp/res/values-pl/strings.xml
index 59710d0..b5ad6d7 100644
--- a/android/TerminalApp/res/values-pl/strings.xml
+++ b/android/TerminalApp/res/values-pl/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Układ <xliff:g id="ID_1">VirGL</xliff:g> jest włączony"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Długotrwałe zadania"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Zdarzenia systemowe"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Karta"</string>
</resources>
diff --git a/android/TerminalApp/res/values-pt/strings.xml b/android/TerminalApp/res/values-pt/strings.xml
index ddfb46d..8c05964 100644
--- a/android/TerminalApp/res/values-pt/strings.xml
+++ b/android/TerminalApp/res/values-pt/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"O <xliff:g id="ID_1">VirGL</xliff:g> está ativado"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Tarefas de longa duração"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Eventos do sistema"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Guia"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ro/strings.xml b/android/TerminalApp/res/values-ro/strings.xml
index b5575b4..c333535 100644
--- a/android/TerminalApp/res/values-ro/strings.xml
+++ b/android/TerminalApp/res/values-ro/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> este activat"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Activități de durată"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Evenimente de sistem"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ru/strings.xml b/android/TerminalApp/res/values-ru/strings.xml
index c8ab061..7e86cb1 100644
--- a/android/TerminalApp/res/values-ru/strings.xml
+++ b/android/TerminalApp/res/values-ru/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g>: включено."</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Длительные задачи"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Системные события"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Вкладка"</string>
</resources>
diff --git a/android/TerminalApp/res/values-si/strings.xml b/android/TerminalApp/res/values-si/strings.xml
index 84c4840..7085d17 100644
--- a/android/TerminalApp/res/values-si/strings.xml
+++ b/android/TerminalApp/res/values-si/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> සබලයි"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"දිගු කාලයක් ධාවනය වන කාර්යයන්"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"පද්ධති සිදුවීම්"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"පටිත්ත"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sk/strings.xml b/android/TerminalApp/res/values-sk/strings.xml
index 35a9806..b11ada0 100644
--- a/android/TerminalApp/res/values-sk/strings.xml
+++ b/android/TerminalApp/res/values-sk/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Procesor <xliff:g id="ID_1">VirGL</xliff:g> je aktivovaný"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Dlho spustené úlohy"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Systémové udalosti"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sl/strings.xml b/android/TerminalApp/res/values-sl/strings.xml
index ecd3931..8785b84 100644
--- a/android/TerminalApp/res/values-sl/strings.xml
+++ b/android/TerminalApp/res/values-sl/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> je omogočen"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Dolgotrajna opravila"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Sistemski dogodki"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Zavihek"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sq/strings.xml b/android/TerminalApp/res/values-sq/strings.xml
index d1a5fe1..f540af8 100644
--- a/android/TerminalApp/res/values-sq/strings.xml
+++ b/android/TerminalApp/res/values-sq/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> është aktivizuar"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Detyrat afatgjata"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Ngjarjet e sistemit"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Tab"</string>
</resources>
diff --git a/android/TerminalApp/res/values-sr/strings.xml b/android/TerminalApp/res/values-sr/strings.xml
index 635c467..8620b8a 100644
--- a/android/TerminalApp/res/values-sr/strings.xml
+++ b/android/TerminalApp/res/values-sr/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> је омогућен"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Дуготрајни задаци"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Системски догађаји"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Картица"</string>
</resources>
diff --git a/android/TerminalApp/res/values-ta/strings.xml b/android/TerminalApp/res/values-ta/strings.xml
index 1b4c766..ba6edbf 100644
--- a/android/TerminalApp/res/values-ta/strings.xml
+++ b/android/TerminalApp/res/values-ta/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> இயக்கப்பட்டது"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"நீண்ட நேரம் இயங்கும் பணிகள்"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"சிஸ்டம் நிகழ்வுகள்"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"பிரிவு"</string>
</resources>
diff --git a/android/TerminalApp/res/values-tr/strings.xml b/android/TerminalApp/res/values-tr/strings.xml
index e97728c..cc3812e 100644
--- a/android/TerminalApp/res/values-tr/strings.xml
+++ b/android/TerminalApp/res/values-tr/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> etkinleştirildi"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Uzun süredir çalışan görevler"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Sistem etkinlikleri"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Sekme"</string>
</resources>
diff --git a/android/TerminalApp/res/values-uk/strings.xml b/android/TerminalApp/res/values-uk/strings.xml
index 8cb7601..4224d98 100644
--- a/android/TerminalApp/res/values-uk/strings.xml
+++ b/android/TerminalApp/res/values-uk/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> увімкнено"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Довготривалі завдання"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Події системи"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Вкладка"</string>
</resources>
diff --git a/android/TerminalApp/res/values-zh-rTW/strings.xml b/android/TerminalApp/res/values-zh-rTW/strings.xml
index 7ddb8cd..94f473d 100644
--- a/android/TerminalApp/res/values-zh-rTW/strings.xml
+++ b/android/TerminalApp/res/values-zh-rTW/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"<xliff:g id="ID_1">VirGL</xliff:g> 已啟用"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"長時間執行的工作"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"系統事件"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"分頁"</string>
</resources>
diff --git a/android/TerminalApp/res/values-zu/strings.xml b/android/TerminalApp/res/values-zu/strings.xml
index 1af2744..432102b 100644
--- a/android/TerminalApp/res/values-zu/strings.xml
+++ b/android/TerminalApp/res/values-zu/strings.xml
@@ -90,6 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"I-<xliff:g id="ID_1">VirGL</xliff:g> inikwe amandla."</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Imisebenzi esebenza isikhathi eside"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Imicimbi yesistimu"</string>
- <!-- no translation found for tab_default_title (2300417689389397930) -->
- <skip />
+ <string name="tab_default_title" msgid="2300417689389397930">"Ithebhu"</string>
</resources>
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 1a263bd..1c4c2eb 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -151,6 +151,17 @@
}
});
+// TODO(ioffe): add service for guest-ffa.
+const KNOWN_TEE_SERVICES: [&str; 0] = [];
+
+fn check_known_tee_service(tee_service: &str) -> binder::Result<()> {
+ if !KNOWN_TEE_SERVICES.contains(&tee_service) {
+ return Err(anyhow!("unknown tee_service {tee_service}"))
+ .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+ }
+ Ok(())
+}
+
fn create_or_update_idsig_file(
input_fd: &ParcelFileDescriptor,
idsig_fd: &ParcelFileDescriptor,
@@ -303,6 +314,34 @@
Ok(())
}
+ fn setEncryptedStorageSize(
+ &self,
+ image_fd: &ParcelFileDescriptor,
+ size: i64,
+ ) -> binder::Result<()> {
+ check_manage_access()?;
+
+ let size = size
+ .try_into()
+ .with_context(|| format!("Invalid size: {}", size))
+ .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?;
+ let size = round_up(size, PARTITION_GRANULARITY_BYTES);
+
+ let image = clone_file(image_fd)?;
+ let image_size = image.metadata().unwrap().len();
+
+ if image_size > size {
+ return Err(Status::new_exception_str(
+ ExceptionCode::ILLEGAL_ARGUMENT,
+ Some("Can't shrink encrypted storage"),
+ ));
+ }
+ // Reset the file length. In most filesystems, this will not allocate any physical disk
+ // space, it will only change the logical size.
+ image.set_len(size).context("Failed to extend file").or_service_specific_exception(-1)?;
+ Ok(())
+ }
+
/// Creates or update the idsig file by digesting the input APK file.
fn createOrUpdateIdsigFile(
&self,
@@ -459,6 +498,12 @@
if path.starts_with("/system/product/") {
return Ok(CallingPartition::Product);
}
+ if path.starts_with("/data/nativetest/vendor/")
+ || path.starts_with("/data/nativetest64/vendor/")
+ {
+ return Ok(CallingPartition::Vendor);
+ }
+
let partition = {
let mut components = path.components();
let Some(std::path::Component::Normal(partition)) = components.nth(1) else {
@@ -682,11 +727,38 @@
*is_protected = config.protectedVm;
if !config.teeServices.is_empty() {
+ if !config.protectedVm {
+ return Err(anyhow!("only protected VMs can request tee services"))
+ .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+ }
check_tee_service_permission(&caller_secontext, &config.teeServices)
.with_log()
.or_binder_exception(ExceptionCode::SECURITY)?;
}
+ let mut system_tee_services = Vec::new();
+ let mut vendor_tee_services = Vec::new();
+ for tee_service in config.teeServices.clone() {
+ if !tee_service.starts_with("vendor.") {
+ check_known_tee_service(&tee_service)?;
+ system_tee_services.push(tee_service);
+ } else {
+ vendor_tee_services.push(tee_service);
+ }
+ }
+
+ // TODO(b/391774181): handle vendor tee services (which require talking to HAL) as well.
+ if !vendor_tee_services.is_empty() {
+ return Err(anyhow!("support for vendor tee services is coming soon!"))
+ .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+ }
+
+ // TODO(b/391774181): remove this check in a follow-up patch.
+ if !system_tee_services.is_empty() {
+ return Err(anyhow!("support for system tee services is coming soon!"))
+ .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+ }
+
let kernel = maybe_clone_file(&config.kernel)?;
let initrd = maybe_clone_file(&config.initrd)?;
@@ -863,6 +935,20 @@
})
.collect::<binder::Result<_>>()?;
+ let memory_reclaim_supported =
+ system_properties::read_bool("hypervisor.memory_reclaim.supported", false)
+ .unwrap_or(false);
+
+ let balloon = config.balloon && memory_reclaim_supported;
+
+ if !balloon {
+ warn!(
+ "Memory balloon not enabled:
+ config.balloon={},hypervisor.memory_reclaim.supported={}",
+ config.balloon, memory_reclaim_supported
+ );
+ }
+
// Actually start the VM.
let crosvm_config = CrosvmConfig {
cid,
@@ -902,7 +988,7 @@
boost_uclamp: config.boostUclamp,
gpu_config,
audio_config,
- balloon: config.balloon,
+ balloon,
usb_config,
dump_dt_fd,
enable_hypervisor_specific_auth_method: config.enableHypervisorSpecificAuthMethod,
@@ -1374,7 +1460,7 @@
calling_partition: CallingPartition,
) -> Result<()> {
let path = format!("/proc/self/fd/{}", fd.as_raw_fd());
- let link = fs::read_link(&path).context(format!("can't read_link {path}"))?;
+ let link = fs::read_link(&path).with_context(|| format!("can't read_link {path}"))?;
// microdroid vendor image is OK
if cfg!(vendor_modules) && link == Path::new("/vendor/etc/avf/microdroid/microdroid_vendor.img")
@@ -1382,7 +1468,10 @@
return Ok(());
}
- let is_fd_vendor = link.starts_with("/vendor") || link.starts_with("/odm");
+ let fd_partition = find_partition(Some(&link))
+ .with_context(|| format!("can't find_partition {}", link.display()))?;
+ let is_fd_vendor =
+ fd_partition == CallingPartition::Vendor || fd_partition == CallingPartition::Odm;
let is_caller_vendor =
calling_partition == CallingPartition::Vendor || calling_partition == CallingPartition::Odm;
@@ -1558,9 +1647,8 @@
| "virtualizationservice_data_file" // files created by VS / VirtMgr
| "vendor_microdroid_file" // immutable dm-verity protected partition (/vendor/etc/avf/microdroid/.*)
=> Ok(()),
- // It is difficult to require specific label types for vendor initiated VM's files, so we
- // allow anything with a vendor prefix.
- t if calling_partition == CallingPartition::Vendor && t.starts_with("vendor_") => Ok(()),
+ // It is difficult to require specific label types for vendor initiated VM's files.
+ _ if calling_partition == CallingPartition::Vendor => Ok(()),
_ => bail!("Label {} is not allowed", context),
}
}
@@ -1659,6 +1747,10 @@
.or_service_specific_exception(-1)
}
+ fn isMemoryBalloonEnabled(&self) -> binder::Result<bool> {
+ Ok(self.instance.balloon_enabled)
+ }
+
fn getMemoryBalloon(&self) -> binder::Result<i64> {
let balloon = self
.instance
@@ -2210,6 +2302,10 @@
fn requestAttestation(&self, csr: &[u8], test_mode: bool) -> binder::Result<Vec<Certificate>> {
GLOBAL_SERVICE.requestAttestation(csr, get_calling_uid() as i32, test_mode)
}
+
+ fn claimSecretkeeperEntry(&self, id: &[u8; 64]) -> binder::Result<()> {
+ GLOBAL_SERVICE.claimSecretkeeperEntry(id)
+ }
}
fn is_secretkeeper_supported() -> bool {
@@ -2762,6 +2858,14 @@
}
#[test]
+ fn test_vendor_in_data() {
+ assert_eq!(
+ CallingPartition::Vendor,
+ find_partition(Some(Path::new("/data/nativetest64/vendor/file"))).unwrap()
+ );
+ }
+
+ #[test]
fn early_vm_exe_paths_match_succeeds_with_same_paths() {
let early_vm = EarlyVm {
name: "vm_demo_native_early".to_owned(),
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index 77710c3..5f81e90 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -417,6 +417,8 @@
pub vm_service: Mutex<Option<Strong<dyn IVirtualMachineService>>>,
/// Recorded metrics of VM such as timestamp or cpu / memory usage.
pub vm_metric: Mutex<VmMetric>,
+ // Whether virtio-balloon is enabled
+ pub balloon_enabled: bool,
/// The latest lifecycle state which the payload reported itself to be in.
payload_state: Mutex<PayloadState>,
/// Represents the condition that payload_state was updated
@@ -449,6 +451,7 @@
let cid = config.cid;
let name = config.name.clone();
let protected = config.protected;
+ let balloon_enabled = config.balloon;
let requester_uid_name = User::from_uid(Uid::from_raw(requester_uid))
.ok()
.flatten()
@@ -469,6 +472,7 @@
payload_state: Mutex::new(PayloadState::Starting),
payload_state_updated: Condvar::new(),
requester_uid_name,
+ balloon_enabled,
};
info!("{} created", &instance);
Ok(instance)
@@ -722,6 +726,9 @@
/// Returns current virtio-balloon size.
pub fn get_memory_balloon(&self) -> Result<u64, Error> {
+ if !self.balloon_enabled {
+ bail!("virtio-balloon is not enabled");
+ }
let socket_path_cstring = path_to_cstring(&self.crosvm_control_socket_path);
let mut balloon_actual = 0u64;
// SAFETY: Pointers are valid for the lifetime of the call. Null `stats` is valid.
@@ -741,6 +748,9 @@
/// Inflates the virtio-balloon by `num_bytes` to reclaim guest memory. Called in response to
/// memory-trimming notifications.
pub fn set_memory_balloon(&self, num_bytes: u64) -> Result<(), Error> {
+ if !self.balloon_enabled {
+ bail!("virtio-balloon is not enabled");
+ }
let socket_path_cstring = path_to_cstring(&self.crosvm_control_socket_path);
// SAFETY: Pointer is valid for the lifetime of the call.
let success = unsafe {
@@ -1038,8 +1048,7 @@
.arg("--cid")
.arg(config.cid.to_string());
- if system_properties::read_bool("hypervisor.memory_reclaim.supported", false)? && config.balloon
- {
+ if config.balloon {
command.arg("--balloon-page-reporting");
} else {
command.arg("--no-balloon");
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
index a01d385..e7aeefd 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
@@ -49,6 +49,7 @@
void stop();
/** Access to the VM's memory balloon. */
+ boolean isMemoryBalloonEnabled();
long getMemoryBalloon();
void setMemoryBalloon(long num_bytes);
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
index 169c3dc..37222ba 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
@@ -58,6 +58,13 @@
in ParcelFileDescriptor imageFd, long sizeBytes, PartitionType type);
/**
+ * Set the encrypted storage size.
+ *
+ * The file must be open with both read and write permissions.
+ */
+ void setEncryptedStorageSize(in ParcelFileDescriptor imageFd, long size);
+
+ /**
* Create or update an idsig file that digests the given APK file. The idsig file follows the
* idsig format that is defined by the APK Signature Scheme V4. The idsig file is not updated
* when it is up to date with the input file, which is checked by comparing the
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
index 0da7755..4f549cb 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
@@ -134,4 +134,10 @@
* @param file descriptor of the TAP network interface.
*/
void deleteTapInterface(in ParcelFileDescriptor tapFd);
+
+ /**
+ * Account the caller for the corresponding Secretkeeper entry.
+ * @param id Identifier for the secret held in Secretkeeper for the caller
+ */
+ void claimSecretkeeperEntry(in byte[64] id);
}
diff --git a/android/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/android/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index 662c8f1..7fe11e9 100644
--- a/android/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -63,4 +63,10 @@
* that Secretkeeper is supported from Linux device tree before calling this.
*/
ISecretkeeper getSecretkeeper();
+
+ /**
+ * Account the caller for the corresponding Secretkeeper entry.
+ * @param id Identifier for the secret held in Secretkeeper for the caller
+ */
+ void claimSecretkeeperEntry(in byte[64] id);
}
diff --git a/android/virtualizationservice/src/aidl.rs b/android/virtualizationservice/src/aidl.rs
index f4e64e3..62cede8 100644
--- a/android/virtualizationservice/src/aidl.rs
+++ b/android/virtualizationservice/src/aidl.rs
@@ -196,6 +196,28 @@
service
}
+
+ // Attempt to update the sk_state maintenance database. Errors are ignored - calling app
+ // can not really do much to fix the errors & letting AVF VMs run irrespective of such internal
+ // error is acceptable.
+ fn try_updating_sk_state(&self, id: &[u8; 64]) {
+ let state = &mut *self.state.lock().unwrap();
+ if let Some(sk_state) = &mut state.sk_state {
+ let uid = get_calling_uid();
+ let user_id = multiuser_get_user_id(uid);
+ let app_id = multiuser_get_app_id(uid);
+ info!(
+ "Recording possible new owner of Secretkeeper entry={:?}:
+ (user_id={user_id}, app_id={app_id},)",
+ hex::encode(id)
+ );
+ if let Err(e) = sk_state.add_id(id, user_id, app_id) {
+ error!("Failed to update the Secretkeeper entry owner: {e:?}");
+ }
+ } else {
+ info!("ignoring update of Secretkeeper entry as no ISecretkeeper");
+ }
+ }
}
impl Interface for VirtualizationServiceInternal {}
@@ -467,16 +489,7 @@
.or_service_specific_exception(-1)?;
let uid = get_calling_uid();
info!("Allocated a VM's instance_id: {:?}..., for uid: {:?}", &hex::encode(id)[..8], uid);
- let state = &mut *self.state.lock().unwrap();
- if let Some(sk_state) = &mut state.sk_state {
- let user_id = multiuser_get_user_id(uid);
- let app_id = multiuser_get_app_id(uid);
- info!("Recording possible existence of state for (user_id={user_id}, app_id={app_id})");
- if let Err(e) = sk_state.add_id(&id, user_id, app_id) {
- error!("Failed to record the instance_id: {e:?}");
- }
- }
-
+ self.try_updating_sk_state(&id);
Ok(id)
}
@@ -500,24 +513,8 @@
}
fn claimVmInstance(&self, instance_id: &[u8; 64]) -> binder::Result<()> {
- let state = &mut *self.state.lock().unwrap();
- if let Some(sk_state) = &mut state.sk_state {
- let uid = get_calling_uid();
- info!(
- "Claiming a VM's instance_id: {:?}, for uid: {:?}",
- hex::encode(instance_id),
- uid
- );
-
- let user_id = multiuser_get_user_id(uid);
- let app_id = multiuser_get_app_id(uid);
- info!("Recording possible new owner of state for (user_id={user_id}, app_id={app_id})");
- if let Err(e) = sk_state.add_id(instance_id, user_id, app_id) {
- error!("Failed to update the instance_id owner: {e:?}");
- }
- } else {
- info!("ignoring claimVmInstance() as no ISecretkeeper");
- }
+ info!("Claiming a VM's instance_id: {:?}", hex::encode(instance_id));
+ self.try_updating_sk_state(instance_id);
Ok(())
}
@@ -559,6 +556,12 @@
NETWORK_SERVICE.deleteTapInterface(tap_fd)
}
+
+ fn claimSecretkeeperEntry(&self, id: &[u8; 64]) -> binder::Result<()> {
+ info!("Claiming Secretkeeper entry: {:?}", hex::encode(id));
+ self.try_updating_sk_state(id);
+ Ok(())
+ }
}
impl IVirtualizationMaintenance for VirtualizationServiceInternal {
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index ff846a1..7178de5 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -22,8 +22,6 @@
CpuOptions::CpuTopology::CpuTopology, IVirtualizationService::IVirtualizationService,
PartitionType::PartitionType, VirtualMachineAppConfig::DebugLevel::DebugLevel,
};
-#[cfg(not(llpvm_changes))]
-use anyhow::anyhow;
use anyhow::{bail, Context, Error};
use binder::{ProcessState, Strong};
use clap::{Args, Parser};
@@ -220,7 +218,6 @@
instance: PathBuf,
/// Path to file containing instance_id. Required iff llpvm feature is enabled.
- #[cfg(llpvm_changes)]
#[arg(long = "instance-id-file")]
instance_id: PathBuf,
@@ -255,26 +252,8 @@
}
}
- fn instance_id(&self) -> Result<PathBuf, Error> {
- 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"))
- }
- }
- }
-
- fn set_instance_id(&mut self, instance_id_file: PathBuf) -> Result<(), Error> {
- cfg_if::cfg_if! {
- if #[cfg(llpvm_changes)] {
- self.instance_id = instance_id_file;
- Ok(())
- } else {
- let _ = instance_id_file;
- Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
- }
- }
+ fn set_instance_id(&mut self, instance_id_file: PathBuf) {
+ self.instance_id = instance_id_file;
}
}
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index a362b8e..1033164 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -35,6 +35,7 @@
use rand::{distributions::Alphanumeric, Rng};
use std::fs;
use std::fs::File;
+use std::fs::OpenOptions;
use std::io;
use std::io::{Read, Write};
use std::os::fd::AsFd;
@@ -86,8 +87,8 @@
)?;
}
- let instance_id = if cfg!(llpvm_changes) {
- let id_file = config.instance_id()?;
+ let instance_id = {
+ let id_file = config.instance_id;
if id_file.exists() {
let mut id = [0u8; 64];
let mut instance_id_file = File::open(id_file)?;
@@ -99,9 +100,6 @@
instance_id_file.write_all(&id)?;
id
}
- } else {
- // if llpvm feature flag is disabled, instance_id is not used.
- [0u8; 64]
};
let storage = if let Some(ref path) = config.microdroid.storage {
@@ -112,6 +110,8 @@
config.microdroid.storage_size.unwrap_or(10 * 1024 * 1024),
PartitionType::ENCRYPTEDSTORE,
)?;
+ } else if let Some(storage_size) = config.microdroid.storage_size {
+ set_encrypted_storage(service.as_ref(), path, storage_size)?;
}
Some(open_parcel_file(path, true)?)
} else {
@@ -251,10 +251,8 @@
..Default::default()
};
- if cfg!(llpvm_changes) {
- app_config.set_instance_id(work_dir.join("instance_id"))?;
- println!("instance_id file path: {}", app_config.instance_id()?.display());
- }
+ app_config.set_instance_id(work_dir.join("instance_id"));
+ println!("instance_id file path: {}", app_config.instance_id.display());
command_run_app(app_config)
}
@@ -370,6 +368,22 @@
Ok(config.extra_apks.into_iter().map(|x| x.path.into()).collect())
}
+fn set_encrypted_storage(
+ service: &dyn IVirtualizationService,
+ image_path: &Path,
+ size: u64,
+) -> Result<(), Error> {
+ let image = OpenOptions::new()
+ .create_new(false)
+ .read(true)
+ .write(true)
+ .open(image_path)
+ .with_context(|| format!("Failed to open {:?}", image_path))?;
+
+ service.setEncryptedStorageSize(&ParcelFileDescriptor::new(image), size.try_into()?)?;
+ Ok(())
+}
+
struct Callback {}
impl vmclient::VmCallback for Callback {
diff --git a/android/vm_demo_native/main.cpp b/android/vm_demo_native/main.cpp
index e1acc05..8fc14bf 100644
--- a/android/vm_demo_native/main.cpp
+++ b/android/vm_demo_native/main.cpp
@@ -329,11 +329,15 @@
&ARpcSession_free);
ARpcSession_setMaxIncomingThreads(session.get(), 1);
+ auto param = std::make_unique<std::shared_ptr<IVirtualMachine>>(std::move(vm));
+ auto paramDeleteFd = [](void* param) {
+ delete static_cast<std::shared_ptr<IVirtualMachine>*>(param);
+ };
+
AIBinder* binder = ARpcSession_setupPreconnectedClient(
session.get(),
[](void* param) {
- std::shared_ptr<IVirtualMachine> vm =
- *static_cast<std::shared_ptr<IVirtualMachine>*>(param);
+ IVirtualMachine* vm = static_cast<std::shared_ptr<IVirtualMachine>*>(param)->get();
ScopedFileDescriptor sock_fd;
ScopedAStatus ret = vm->connectVsock(ITestService::PORT, &sock_fd);
if (!ret.isOk()) {
@@ -341,7 +345,7 @@
}
return sock_fd.release();
},
- &vm);
+ param.release(), paramDeleteFd);
if (binder == nullptr) {
return Error() << "Failed to connect to vm payload";
}
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index 20f44fe..79675cb 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -251,11 +251,6 @@
srcs: [
"sign_virt_apex.py",
],
- version: {
- py3: {
- embedded_launcher: true,
- },
- },
required: [
// sign_virt_apex should be runnable from outside the source tree,
// therefore, any required tool should be listed in build/make/core/Makefile as well.
@@ -324,11 +319,6 @@
srcs: [
"replace_bytes.py",
],
- version: {
- py3: {
- embedded_launcher: true,
- },
- },
}
// Encapsulate the contributions made by the com.android.virt to the bootclasspath.
diff --git a/build/apex/manifest.json b/build/apex/manifest.json
index b32aa7b..e596ce1 100644
--- a/build/apex/manifest.json
+++ b/build/apex/manifest.json
@@ -3,6 +3,7 @@
"version": 2,
"requireNativeLibs": [
"libEGL.so",
- "libGLESv2.so"
+ "libGLESv2.so",
+ "libvulkan.so"
]
}
diff --git a/build/compos/CompOSPayloadApp/Android.bp b/build/compos/CompOSPayloadApp/Android.bp
index c6192b9..04465b3 100644
--- a/build/compos/CompOSPayloadApp/Android.bp
+++ b/build/compos/CompOSPayloadApp/Android.bp
@@ -5,5 +5,6 @@
android_app {
name: "CompOSPayloadApp",
sdk_version: "current",
+ system_ext_specific: true,
apex_available: ["com.android.compos"],
}
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 63035ae..9c4d4b1 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -114,14 +114,6 @@
)
fi
- # TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
- if [[ "$arch" == "x86_64" ]]; then
- packages+=(
- libguestfs-tools
- linux-image-generic
- )
- fi
-
if [[ "$use_generic_kernel" != 1 ]]; then
packages+=(
bc
@@ -326,9 +318,8 @@
generate_output_package() {
fdisk -l "${raw_disk_image}"
- local vm_config="$SCRIPT_DIR/vm_config.json.${arch}"
+ local vm_config="$SCRIPT_DIR/vm_config.json"
local root_partition_num=1
- local bios_partition_num=14
local efi_partition_num=15
pushd ${workdir} > /dev/null
@@ -337,9 +328,6 @@
loop=$(losetup -f --show --partscan $raw_disk_image)
dd if="${loop}p$root_partition_num" of=root_part
- if [[ "$arch" == "x86_64" ]]; then
- dd if="${loop}p$bios_partition_num" of=bios_part
- fi
dd if="${loop}p$efi_partition_num" of=efi_part
losetup -d "${loop}"
@@ -350,36 +338,19 @@
fi
sed -i "s/{root_part_guid}/$(sfdisk --part-uuid $raw_disk_image $root_partition_num)/g" vm_config.json
- if [[ "$arch" == "x86_64" ]]; then
- sed -i "s/{bios_part_guid}/$(sfdisk --part-uuid $raw_disk_image $bios_partition_num)/g" vm_config.json
- fi
sed -i "s/{efi_part_guid}/$(sfdisk --part-uuid $raw_disk_image $efi_partition_num)/g" vm_config.json
- images=()
- if [[ "$arch" == "aarch64" ]]; then
- images+=(
- root_part
- efi_part
- )
- # TODO(b/365955006): remove these lines when uboot supports x86_64 EFI application
- elif [[ "$arch" == "x86_64" ]]; then
- rm -f vmlinuz initrd.img
- virt-get-kernel -a "${raw_disk_image}"
- mv vmlinuz* vmlinuz
- mv initrd.img* initrd.img
- images+=(
- bios_part
- root_part
- efi_part
- vmlinuz
- initrd.img
- )
- fi
-
popd > /dev/null
+ contents=(
+ build_id
+ root_part
+ efi_part
+ vm_config.json
+ )
+
# --sparse option isn't supported in apache-commons-compress
- tar czv -f ${output} -C ${workdir} build_id "${images[@]}" vm_config.json
+ tar czv -f ${output} -C ${workdir} "${contents[@]}"
}
clean_up() {
diff --git a/build/debian/vm_config.json.aarch64 b/build/debian/vm_config.json
similarity index 100%
rename from build/debian/vm_config.json.aarch64
rename to build/debian/vm_config.json
diff --git a/build/debian/vm_config.json.x86_64 b/build/debian/vm_config.json.x86_64
deleted file mode 100644
index bc4e00a..0000000
--- a/build/debian/vm_config.json.x86_64
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "name": "debian",
- "disks": [
- {
- "partitions": [
- {
- "label": "ROOT",
- "path": "$PAYLOAD_DIR/root_part",
- "writable": true,
- "guid": "{root_part_guid}"
- },
- {
- "label": "BIOS",
- "path": "$PAYLOAD_DIR/bios_part",
- "writable": true,
- "guid": "{bios_part_guid}"
- },
- {
- "label": "EFI",
- "path": "$PAYLOAD_DIR/efi_part",
- "writable": false,
- "guid": "{efi_part_guid}"
- }
- ],
- "writable": true
- }
- ],
- "sharedPath": [
- {
- "sharedPath": "/storage/emulated"
- },
- {
- "sharedPath": "$APP_DATA_DIR/files"
- }
- ],
- "kernel": "$PAYLOAD_DIR/vmlinuz",
- "initrd": "$PAYLOAD_DIR/initrd.img",
- "params": "root=/dev/vda1",
- "protected": false,
- "cpu_topology": "match_host",
- "platform_version": "~1.0",
- "memory_mib": 4096,
- "debuggable": true,
- "console_out": true,
- "console_input_device": "ttyS0",
- "network": true,
- "auto_memory_balloon": true,
- "gpu": {
- "backend": "2d"
- }
-}
diff --git a/build/microdroid/Android.bp b/build/microdroid/Android.bp
index 059077a..10b492b 100644
--- a/build/microdroid/Android.bp
+++ b/build/microdroid/Android.bp
@@ -82,7 +82,9 @@
"microdroid_file_contexts",
"microdroid_manifest",
"microdroid_property_contexts",
+ "e2fsck.microdroid",
"mke2fs.microdroid",
+ "resize2fs.microdroid",
"microdroid_fstab",
"libvm_payload", // used by payload to interact with microdroid manager
diff --git a/guest/apkdmverity/Android.bp b/guest/apkdmverity/Android.bp
index 3f45bb4..6e928f6 100644
--- a/guest/apkdmverity/Android.bp
+++ b/guest/apkdmverity/Android.bp
@@ -41,7 +41,6 @@
name: "apkdmverity.test",
defaults: [
"apkdmverity.defaults",
- "rdroidtest.defaults",
],
test_suites: ["general-tests"],
compile_multilib: "first",
diff --git a/guest/apkdmverity/src/main.rs b/guest/apkdmverity/src/main.rs
index 2fc964b..167f5d4 100644
--- a/guest/apkdmverity/src/main.rs
+++ b/guest/apkdmverity/src/main.rs
@@ -160,12 +160,8 @@
}
#[cfg(test)]
-rdroidtest::test_main!();
-
-#[cfg(test)]
mod tests {
use crate::*;
- use rdroidtest::{ignore_if, rdroidtest};
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::ops::Deref;
@@ -236,9 +232,11 @@
});
}
- #[rdroidtest]
- #[ignore_if(should_skip())]
+ #[test]
fn correct_inputs() {
+ if should_skip() {
+ return;
+ }
let apk = include_bytes!("../testdata/test.apk");
let idsig = include_bytes!("../testdata/test.apk.idsig");
run_test(apk.as_ref(), idsig.as_ref(), "correct", |ctx| {
@@ -250,9 +248,11 @@
}
// A single byte change in the APK file causes an IO error
- #[rdroidtest]
- #[ignore_if(should_skip())]
+ #[test]
fn incorrect_apk() {
+ if should_skip() {
+ return;
+ }
let apk = include_bytes!("../testdata/test.apk");
let idsig = include_bytes!("../testdata/test.apk.idsig");
@@ -268,9 +268,11 @@
}
// A single byte change in the merkle tree also causes an IO error
- #[rdroidtest]
- #[ignore_if(should_skip())]
+ #[test]
fn incorrect_merkle_tree() {
+ if should_skip() {
+ return;
+ }
let apk = include_bytes!("../testdata/test.apk");
let idsig = include_bytes!("../testdata/test.apk.idsig");
@@ -293,9 +295,11 @@
// APK is not altered when the verity device is created, but later modified. IO error should
// occur when trying to read the data around the modified location. This is the main scenario
// that we'd like to protect.
- #[rdroidtest]
- #[ignore_if(should_skip())]
+ #[test]
fn tampered_apk() {
+ if should_skip() {
+ return;
+ }
let apk = include_bytes!("../testdata/test.apk");
let idsig = include_bytes!("../testdata/test.apk.idsig");
@@ -315,9 +319,11 @@
// idsig file is not alread when the verity device is created, but later modified. Unlike to
// the APK case, this doesn't occur IO error because the merkle tree is already cached.
- #[rdroidtest]
- #[ignore_if(should_skip())]
+ #[test]
fn tampered_idsig() {
+ if should_skip() {
+ return;
+ }
let apk = include_bytes!("../testdata/test.apk");
let idsig = include_bytes!("../testdata/test.apk.idsig");
run_test(apk.as_ref(), idsig.as_ref(), "tampered_idsig", |ctx| {
@@ -333,9 +339,11 @@
}
// test if both files are already block devices
- #[rdroidtest]
- #[ignore_if(should_skip())]
+ #[test]
fn inputs_are_block_devices() {
+ if should_skip() {
+ return;
+ }
let apk = include_bytes!("../testdata/test.apk");
let idsig = include_bytes!("../testdata/test.apk.idsig");
@@ -383,9 +391,11 @@
}
// test with custom roothash
- #[rdroidtest]
- #[ignore_if(should_skip())]
+ #[test]
fn correct_custom_roothash() {
+ if should_skip() {
+ return;
+ }
let apk = include_bytes!("../testdata/test.apk");
let idsig = include_bytes!("../testdata/test.apk.idsig");
let roothash = V4Signature::from_idsig_path("testdata/test.apk.idsig")
@@ -406,7 +416,7 @@
);
}
- #[rdroidtest]
+ #[test]
fn verify_command() {
// Check that the command parsing has been configured in a valid way.
clap_command().debug_assert();
diff --git a/guest/encryptedstore/src/main.rs b/guest/encryptedstore/src/main.rs
index dd4ee3b..8647003 100644
--- a/guest/encryptedstore/src/main.rs
+++ b/guest/encryptedstore/src/main.rs
@@ -30,7 +30,9 @@
use std::path::{Path, PathBuf};
use std::process::Command;
+const E2FSCK_BIN: &str = "/system/bin/e2fsck";
const MK2FS_BIN: &str = "/system/bin/mke2fs";
+const RESIZE2FS_BIN: &str = "/system/bin/resize2fs";
const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE";
fn main() {
@@ -91,6 +93,8 @@
if needs_formatting {
info!("Freshly formatting the crypt device");
format_ext4(&crypt_device)?;
+ } else {
+ resize_fs(&crypt_device)?;
}
mount(&crypt_device, mountpoint)
.with_context(|| format!("Unable to mount {:?}", crypt_device))?;
@@ -174,6 +178,27 @@
Ok(())
}
+fn resize_fs(device: &Path) -> Result<()> {
+ // Check the partition
+ Command::new(E2FSCK_BIN)
+ .arg("-fvy")
+ .arg(device)
+ .status()
+ .context("failed to execute e2fsck")?;
+
+ // Resize the filesystem to the size of the device.
+ Command::new(RESIZE2FS_BIN).arg(device).status().context("failed to execute resize2fs")?;
+
+ // Finally check again if we were successful.
+ Command::new(E2FSCK_BIN)
+ .arg("-fvy")
+ .arg(device)
+ .status()
+ .context("failed to execute e2fsck")?;
+
+ Ok(())
+}
+
fn mount(source: &Path, mountpoint: &Path) -> Result<()> {
create_dir_all(mountpoint).with_context(|| format!("Failed to create {:?}", &mountpoint))?;
let mount_options = CString::new(
diff --git a/guest/forwarder_guest_launcher/debian/service b/guest/forwarder_guest_launcher/debian/service
index 6824c70..ad57a26 100644
--- a/guest/forwarder_guest_launcher/debian/service
+++ b/guest/forwarder_guest_launcher/debian/service
@@ -11,6 +11,8 @@
RestartSec=1
User=root
Group=root
+StandardOutput=journal
+StandardError=journal
[Install]
WantedBy=multi-user.target
diff --git a/guest/microdroid_manager/src/main.rs b/guest/microdroid_manager/src/main.rs
index 57ad35d..4537834 100644
--- a/guest/microdroid_manager/src/main.rs
+++ b/guest/microdroid_manager/src/main.rs
@@ -244,13 +244,14 @@
fn verify_payload_with_instance_img(
metadata: &Metadata,
dice: &DiceDriver,
+ state: &mut VmInstanceState,
) -> Result<MicrodroidData> {
let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
let saved_data = instance.read_microdroid_data(dice).context("Failed to read identity data")?;
if is_strict_boot() {
// Provisioning must happen on the first boot and never again.
- if is_new_instance_legacy() {
+ if Path::new(AVF_NEW_INSTANCE).exists() {
ensure!(
saved_data.is_none(),
MicrodroidError::PayloadInvalidConfig(
@@ -286,12 +287,14 @@
);
info!("Saved data is verified.");
}
+ *state = VmInstanceState::PreviouslySeen;
saved_data
} else {
info!("Saving verified data.");
instance
.write_microdroid_data(&extracted_data, dice)
.context("Failed to write identity data")?;
+ *state = VmInstanceState::NewlyCreated;
extracted_data
};
Ok(instance_data)
@@ -321,13 +324,14 @@
.context("Failed to load DICE from driver")?
};
+ let mut state = VmInstanceState::Unknown;
// Microdroid skips checking payload against instance image iff the device supports
- // secretkeeper. In that case Microdroid use VmSecret::V2, which provide protection against
- // rollback of boot images and packages.
+ // secretkeeper. In that case Microdroid use VmSecret::V2, which provides instance state
+ // and protection against rollback of boot images and packages.
let instance_data = if should_defer_rollback_protection() {
verify_payload(&metadata, None)?
} else {
- verify_payload_with_instance_img(&metadata, &dice)?
+ verify_payload_with_instance_img(&metadata, &dice, &mut state)?
};
let payload_metadata = metadata.payload.ok_or_else(|| {
@@ -337,7 +341,6 @@
// To minimize the exposure to untrusted data, derive dice profile as soon as possible.
info!("DICE derivation for payload");
let dice_artifacts = dice_derivation(dice, &instance_data, &payload_metadata)?;
- let mut state = VmInstanceState::Unknown;
let vm_secret = VmSecret::new(dice_artifacts, service, &mut state)
.context("Failed to create VM secrets")?;
@@ -345,15 +348,7 @@
VmInstanceState::NewlyCreated => true,
VmInstanceState::PreviouslySeen => false,
VmInstanceState::Unknown => {
- // VmSecret instantiation was not able to determine the state. This should only happen
- // for legacy secret mechanism (V1) - in which case fallback to legacy
- // instance.img based determination of state.
- ensure!(
- !should_defer_rollback_protection(),
- "VmInstanceState is Unknown whilst guest is expected to use V2 based secrets.
- This should've never happened"
- );
- is_new_instance_legacy()
+ bail!("Vm instance state is still unknown, this should not have happened");
}
};
@@ -368,14 +363,6 @@
umount2("/microdroid_resources", MntFlags::MNT_DETACH)?;
}
- // Run encryptedstore binary to prepare the storage
- let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
- info!("Preparing encryptedstore ...");
- Some(prepare_encryptedstore(&vm_secret).context("encryptedstore run")?)
- } else {
- None
- };
-
let mut zipfuse = Zipfuse::default();
// Before reading a file from the APK, start zipfuse
@@ -410,6 +397,19 @@
);
mount_extra_apks(&config, &mut zipfuse)?;
+ // Wait until apex config is done. (e.g. linker configuration for apexes)
+ wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")?;
+
+ // Run encryptedstore binary to prepare the storage
+ // Postpone initialization until apex mount completes to ensure e2fsck and resize2fs binaries
+ // are accessible.
+ let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
+ info!("Preparing encryptedstore ...");
+ Some(prepare_encryptedstore(&vm_secret).context("encryptedstore run")?)
+ } else {
+ None
+ };
+
register_vm_payload_service(
allow_restricted_apis,
service.clone(),
@@ -425,9 +425,6 @@
.context("set microdroid_manager.export_tombstones.enabled")?;
}
- // Wait until apex config is done. (e.g. linker configuration for apexes)
- wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")?;
-
// Trigger init post-fs-data. This will start authfs if we wask it to.
if config.enable_authfs {
system_properties::write("microdroid_manager.authfs.enabled", "1")
@@ -517,10 +514,6 @@
Path::new(AVF_STRICT_BOOT).exists()
}
-fn is_new_instance_legacy() -> bool {
- Path::new(AVF_NEW_INSTANCE).exists()
-}
-
fn is_verified_boot() -> bool {
!Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
}
diff --git a/guest/microdroid_manager/src/vm_secret.rs b/guest/microdroid_manager/src/vm_secret.rs
index 6331074..674f010 100644
--- a/guest/microdroid_manager/src/vm_secret.rs
+++ b/guest/microdroid_manager/src/vm_secret.rs
@@ -35,6 +35,9 @@
StoreSecretRequest, GetSecretResponse, GetSecretRequest};
use secretkeeper_comm::data_types::error::SecretkeeperError;
use std::fs;
+use std::thread;
+use rand::Rng;
+use std::time::Duration;
use zeroize::Zeroizing;
use std::sync::Mutex;
use std::sync::Arc;
@@ -63,6 +66,8 @@
0x55, 0xF8, 0x08, 0x23, 0x81, 0x5F, 0xF5, 0x16, 0x20, 0x3E, 0xBE, 0xBA, 0xB7, 0xA8, 0x43, 0x92,
];
+const BACKOFF_SK_ACCESS_MS: u64 = 100;
+
pub enum VmSecret {
// V2 secrets are derived from 2 independently secured secrets:
// 1. Secretkeeper protected secrets (skp secret).
@@ -77,6 +82,7 @@
dice_artifacts: OwnedDiceArtifactsWithExplicitKey,
skp_secret: ZVec,
secretkeeper_session: SkVmSession,
+ virtual_machine_service: Strong<dyn IVirtualMachineService>,
},
// V1 secrets are not protected against rollback of boot images.
// They are reliable only if rollback of images was prevented by verified boot ie,
@@ -117,20 +123,25 @@
.map_err(|e| anyhow!("Failed to build a sealing_policy: {e}"))?;
let session = SkVmSession::new(vm_service, &explicit_dice, policy)?;
let mut skp_secret = Zeroizing::new([0u8; SECRET_SIZE]);
- if let Some(secret) = session.get_secret(id)? {
- *skp_secret = secret;
- *state = VmInstanceState::PreviouslySeen;
- } 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())?;
- *state = VmInstanceState::NewlyCreated;
- }
+ get_or_create_sk_secret(&session, id, &mut skp_secret, state).or_else(|e| {
+ // TODO(b/399304956): Secretkeeper rejects requests when overloaded with
+ // connections from multiple clients. Backoff & retry again, hoping it is
+ // less busy then. Secretkeeper changes are required for more robust solutions.
+ log::info!(
+ "get_or_create_sk_secret failed with {e:?}. Refreshing connection & retrying!"
+ );
+ let mut rng = rand::thread_rng();
+ let backoff = rng.gen_range(BACKOFF_SK_ACCESS_MS..2 * BACKOFF_SK_ACCESS_MS);
+ thread::sleep(Duration::from_millis(backoff));
+ session.refresh()?;
+ get_or_create_sk_secret(&session, id, &mut skp_secret, state)
+ })?;
Ok(Self::V2 {
instance_id: id,
dice_artifacts: explicit_dice,
skp_secret: ZVec::try_from(skp_secret.to_vec())?,
secretkeeper_session: session,
+ virtual_machine_service: vm_service.clone(),
})
}
@@ -180,10 +191,20 @@
pub fn write_payload_data_rp(&self, data: &[u8; SECRET_SIZE]) -> Result<()> {
let data = Zeroizing::new(*data);
- let Self::V2 { instance_id, secretkeeper_session, .. } = self else {
+ let Self::V2 { instance_id, secretkeeper_session, virtual_machine_service, .. } = self
+ else {
return Err(anyhow!("Rollback protected data is not available with V1 secrets"));
};
let payload_id = sha::sha512(instance_id);
+ // Claim the Secretkeeper entry - this pings AVF host to account this Secretkeeper entry
+ // correctly.
+ virtual_machine_service.claimSecretkeeperEntry(&payload_id).map_err(|e| {
+ // TODO rename this error!
+ super::MicrodroidError::FailedToConnectToVirtualizationService(format!(
+ "Failed to claim Secretkeeper entry: {e:?}"
+ ))
+ })?;
+
if let Err(e) = secretkeeper_session.store_secret(payload_id, data.clone()) {
log::info!("Secretkeeper store failed with {e:?}. Refreshing connection & retrying!");
secretkeeper_session.refresh()?;
@@ -271,8 +292,6 @@
sealing_policy: Vec<u8>,
}
-// TODO(b/378911776): This get_secret/store_secret fails on expired session.
-// Introduce retry after refreshing the session
impl SkVmSession {
fn new(
vm_service: &Strong<dyn IVirtualMachineService>,
@@ -354,3 +373,21 @@
))
})?)
}
+
+fn get_or_create_sk_secret(
+ session: &SkVmSession,
+ id: [u8; ID_SIZE],
+ skp_secret: &mut Zeroizing<[u8; SECRET_SIZE]>,
+ state: &mut VmInstanceState,
+) -> Result<()> {
+ if let Some(secret) = session.get_secret(id)? {
+ **skp_secret = secret;
+ *state = VmInstanceState::PreviouslySeen;
+ } 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())?;
+ *state = VmInstanceState::NewlyCreated;
+ }
+ Ok(())
+}
diff --git a/guest/shutdown_runner/debian/service b/guest/shutdown_runner/debian/service
index 7188d36..2668930 100644
--- a/guest/shutdown_runner/debian/service
+++ b/guest/shutdown_runner/debian/service
@@ -10,6 +10,8 @@
RestartSec=1
User=root
Group=root
+StandardOutput=journal
+StandardError=journal
[Install]
WantedBy=multi-user.target
diff --git a/guest/trusty/common/Android.bp b/guest/trusty/common/Android.bp
index d6c524f..1a4c4d7 100644
--- a/guest/trusty/common/Android.bp
+++ b/guest/trusty/common/Android.bp
@@ -1,22 +1,3 @@
-soong_config_module_type {
- name: "trusty_vm_prebuilt_etc",
- module_type: "prebuilt_etc",
- config_namespace: "trusty_system_vm",
- bool_variables: [
- "enabled",
- "placeholder_trusted_hal",
- ],
- properties: ["src"],
-}
-
-soong_config_module_type {
- name: "trusty_vm_avb_add_hash_footer",
- module_type: "avb_add_hash_footer",
- config_namespace: "trusty_system_vm",
- bool_variables: ["enabled"],
- properties: ["src"],
-}
-
prebuilt_etc {
name: "early_vms.xml",
filename: "early_vms.xml",
diff --git a/guest/trusty/security_vm/launcher/security_vm_launcher-arm64.rc b/guest/trusty/security_vm/launcher/security_vm_launcher-arm64.rc
index c0e0537..b9c7147 100644
--- a/guest/trusty/security_vm/launcher/security_vm_launcher-arm64.rc
+++ b/guest/trusty/security_vm/launcher/security_vm_launcher-arm64.rc
@@ -1,9 +1,9 @@
-# TODO(b/393848713): use --protected for the vm launcher when issues are fixed
# TODO(b/393848753): determine whether task_profiles shall be defined
service trusty_security_vm_launcher /system_ext/bin/trusty_security_vm_launcher \
--name trusty_security_vm_launcher \
--kernel /system_ext/etc/vm/trusty_vm/trusty_security_vm.elf \
---memory-size-mib 32
+--memory-size-mib 32 \
+--protected
disabled
user system
group system virtualmachine
diff --git a/guest/trusty/security_vm/vm/Android.bp b/guest/trusty/security_vm/vm/Android.bp
index cc01d1c..35d7313 100644
--- a/guest/trusty/security_vm/vm/Android.bp
+++ b/guest/trusty/security_vm/vm/Android.bp
@@ -2,11 +2,6 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-soong_config_module_type_import {
- from: "packages/modules/Virtualization/guest/trusty/common/Android.bp",
- module_types: ["trusty_vm_avb_add_hash_footer"],
-}
-
// - Trusty VM payloads on arm64 are pvmfw enabled
// AVF VM build system uses the raw binary image (:trusty_security_vm_unsigned),
// adds pvmfw footer and generates a pvmfw-compliant signed elf file)
@@ -115,7 +110,7 @@
TRUSTY_SECURITY_VM_VERSION = 1
-trusty_vm_avb_add_hash_footer {
+avb_add_hash_footer {
name: "trusty_security_vm_signed_bin",
filename: "trusty_security_vm_signed.bin",
partition_name: "boot",
diff --git a/guest/trusty/test_vm/Android.bp b/guest/trusty/test_vm/Android.bp
index 699b673..06b7d9d 100644
--- a/guest/trusty/test_vm/Android.bp
+++ b/guest/trusty/test_vm/Android.bp
@@ -20,6 +20,7 @@
prebuilt_etc {
name: "trusty_test_vm_config",
enabled: false,
+ installable: false,
arch: {
arm64: {
src: "trusty-test_vm-config-arm64.json",
@@ -33,38 +34,10 @@
filename: "trusty-test_vm-config.json",
}
-prebuilt_etc {
- name: "trusty_vm_launcher_sh",
- enabled: false,
- arch: {
- arm64: {
- enabled: true,
- },
- x86_64: {
- enabled: true,
- },
- },
- src: "trusty-vm-launcher.sh",
- filename: "trusty-vm-launcher.sh",
-}
-
-prebuilt_etc {
- name: "trusty_wait_ready_sh",
- enabled: false,
- arch: {
- arm64: {
- enabled: true,
- },
- x86_64: {
- enabled: true,
- },
- },
- src: "trusty-wait-ready.sh",
- filename: "trusty-wait-ready.sh",
-}
-
sh_test {
- name: "TrustyTestVM_UnitTests",
+ // VTS tests for all Trusted HALs defined
+ // under hardware/interfaces/security/see
+ name: "VtsSeeHalTargetTest",
src: "trusty-ut-ctrl.sh",
enabled: false,
arch: {
@@ -81,9 +54,8 @@
":trusty_test_vm_config",
"trusty-vm-launcher.sh",
"trusty-wait-ready.sh",
+ ":trusty-ut-ctrl.system",
],
- // TODO(b/378367793) use the AndroidTest.xml generated from the trusty
- // test-map for test_vm payload
test_config_template: "AndroidTest.xml",
test_suites: [
"general-tests",
diff --git a/guest/trusty/test_vm/AndroidTest.xml b/guest/trusty/test_vm/AndroidTest.xml
index 6fb0879..925b43c 100644
--- a/guest/trusty/test_vm/AndroidTest.xml
+++ b/guest/trusty/test_vm/AndroidTest.xml
@@ -23,6 +23,7 @@
<!-- Target Preparers - Run Shell Commands -->
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
+ <option name="push-file" key="trusty-ut-ctrl.system" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl" />
<option name="push-file" key="trusty-ut-ctrl.sh" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh" />
<option name="push-file" key="trusty-vm-launcher.sh" value="/data/local/tmp/trusty_test_vm/trusty-vm-launcher.sh" />
<option name="push-file" key="trusty-wait-ready.sh" value="/data/local/tmp/trusty_test_vm/trusty-wait-ready.sh" />
@@ -34,76 +35,16 @@
<!--Note: the first run-command shall not expect the background command to have started -->
<option name="run-bg-command" value="sh /data/local/tmp/trusty_test_vm/trusty-vm-launcher.sh" />
<option name="run-command" value="sh /data/local/tmp/trusty_test_vm/trusty-wait-ready.sh" />
- <option name="run-command" value="start storageproxyd_test_system" />
- <option name="teardown-command" value="stop storageproxyd_test_system" />
- <option name="teardown-command" value="killall storageproxyd_test_system || true" />
+ <option name="run-command" value="start storageproxyd_test_vm" />
+ <option name="teardown-command" value="stop storageproxyd_test_vm" />
+ <option name="teardown-command" value="killall storageproxyd_test_vm || true" />
</target_preparer>
<test class="com.android.tradefed.testtype.binary.ExecutableTargetTest" >
<option name="parse-gtest" value="true" />
<option name="abort-if-device-lost" value="true"/>
<option name="abort-if-root-lost" value="true" />
<option name="per-binary-timeout" value="10m" />
- <option name="test-command-line" key="com.android.kernel.mmutest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.mmutest"/>
- <option name="test-command-line" key="com.android.kernel.threadtest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.threadtest"/>
- <option name="test-command-line" key="com.android.kernel.iovectest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.iovectest"/>
- <option name="test-command-line" key="com.android.kernel.timertest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.timertest"/>
- <option name="test-command-line" key="com.android.kernel.btitest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.btitest"/>
- <option name="test-command-line" key="com.android.kernel.cachetest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.cachetest"/>
- <option name="test-command-line" key="com.android.kernel.console-unittest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.console-unittest"/>
- <option name="test-command-line" key="com.android.kernel.dpc-unittest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.dpc-unittest"/>
- <option name="test-command-line" key="com.android.kernel.iovectest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.iovectest"/>
- <option name="test-command-line" key="com.android.kernel.ktipc.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.ktipc.test"/>
- <option name="test-command-line" key="com.android.kernel.memorytest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.memorytest"/>
- <option name="test-command-line" key="com.android.kernel.pactest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.pactest"/>
- <option name="test-command-line" key="com.android.kernel.uirq-unittest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.uirq-unittest"/>
- <option name="test-command-line" key="com.android.kernel.usercopy-unittest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.usercopy-unittest"/>
- <option name="test-command-line" key="com.android.kernel.userscstest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.kernel.userscstest"/>
- <option name="test-command-line" key="com.android.trusty.rust.keymint.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.keymint.test"/>
- <option name="test-command-line" key="com.android.manifesttest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.manifesttest"/>
- <option name="test-command-line" key="com.android.memref.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.memref.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.memref.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.memref.test"/>
- <option name="test-command-line" key="com.android.timer-unittest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.timer-unittest"/>
- <option name="test-command-line" key="com.android.ipc-unittest.ctrl" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.ipc-unittest.ctrl"/>
- <!--option name="test-command-line" key="com.android.trusty.cfitest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.cfitest"/-->
- <option name="test-command-line" key="com.android.trusty.crashtest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.crashtest"/>
- <option name="test-command-line" key="com.android.trusty.dlmalloctest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.dlmalloctest"/>
- <option name="test-command-line" key="com.android.trusty.hwaes.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.hwaes.test"/>
- <option name="test-command-line" key="com.android.trusty.hwbcc.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.hwbcc.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.tipc.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.tipc.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.hwkey.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.hwkey.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.hwbcc.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.hwbcc.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.hwwsk.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.hwwsk.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.storage.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.storage.test"/>
- <option name="test-command-line" key="com.android.trusty.smc.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.smc.test"/>
- <option name="test-command-line" key="com.android.uirq-unittest" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.uirq-unittest"/>
- <!-- Unit tests for legacy hwcrypto services - these hwcrypto services are used by hwcryptohal /-->
- <option name="test-command-line" key="com.android.trusty.hwcrypto.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.hwcrypto.test"/>
- <option name="test-command-line" key="com.android.trusty.hwrng.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.hwrng.test"/>
- <!-- Unit tests for hwcryptohal (exposing IHWCryptoKey/IHWCryptoOperations AIDL) - Note: VTS tests are defined alongside the interface /-->
- <option name="test-command-line" key="com.android.trusty.rust.hwcryptohalserver.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.hwcryptohalserver.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.hwcryptohal_common.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.hwcryptohal_common.test"/>
<option name="test-command-line" key="com.android.trusty.rust.hwcryptokey_test.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.hwcryptokey_test.test"/>
- </test>
- <!-- disabling storage test as they are redundant with the VTS -->
- <!--test class="com.android.tradefed.testtype.binary.ExecutableTargetTest" >
- <option name="parse-gtest" value="true" />
- <option name="abort-if-device-lost" value="true" />
- <option name="abort-if-root-lost" value="true" />
- <option name="per-binary-timeout" value="40m" />
<option name="test-command-line" key="com.android.trusty.rust.storage_unittest_aidl.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.storage_unittest_aidl.test"/>
- <option name="test-command-line" key="com.android.trusty.rust.storage_unittest_aidl_ns.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.storage_unittest_aidl_ns.test"/>
- <option name="test-command-line" key="com.android.storage-unittest.tp" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.storage-unittest.tp"/>
- <option name="test-command-line" key="com.android.storage-unittest.tdea" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.storage-unittest.tdea"/>
- <option name="test-command-line" key="com.android.storage-unittest.nsp" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.storage-unittest.nsp"/>
- <option name="test-command-line" key="com.android.storage-unittest.td" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.storage-unittest.td"/>
- <option name="test-command-line" key="com.android.storage-unittest.tdp" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.storage-unittest.tdp"/>
- </test-->
- <test class="com.android.tradefed.testtype.binary.ExecutableTargetTest" >
- <option name="parse-gtest" value="true" />
- <!--option name="abort-if-device-lost" value="true" /-->
- <!--option name="abort-if-root-lost" value="true" /-->
- <option name="per-binary-timeout" value="40m" />
- <option name="test-command-line" key="com.android.trusty.rust.binder_rpc_test.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.rust.binder_rpc_test.test"/>
- <option name="test-command-line" key="com.android.trusty.binder.test" value="/data/local/tmp/trusty_test_vm/trusty-ut-ctrl.sh com.android.trusty.binder.test"/>
</test>
</configuration>
diff --git a/guest/trusty/test_vm/README.md b/guest/trusty/test_vm/README.md
index 1673844..71368b5 100644
--- a/guest/trusty/test_vm/README.md
+++ b/guest/trusty/test_vm/README.md
@@ -1,7 +1,13 @@
-## Trusty test_vm
+## test_vm
-The Trusty test_vm ought to include the test TAs for different test types:
-- Trusty kernel OS test
-- Trusty IPC tests
-- Trusty user-space tests for service TAs (DT tree for example)
-- and most importantly the VTS tests TA for the trusted HALs.
+The Trusty test_vm ought to include the test TAs for the Trusted HALs,
+defined under hardware/interfaces/security/see:
+
+- AuthMgr
+- Secure Storage
+- HWCrypto
+- HDCP
+
+The Trusty test_vm also includes the VINTF test which allows to check the vendor
+support of the Trusted HALs (version and API hash), against the expected
+compatibility matrix for a given Android Dessert Release.
diff --git a/guest/trusty/test_vm/trusty-test_vm-config-arm64.json b/guest/trusty/test_vm/trusty-test_vm-config-arm64.json
index 18b275e..ac95aab 100644
--- a/guest/trusty/test_vm/trusty-test_vm-config-arm64.json
+++ b/guest/trusty/test_vm/trusty-test_vm-config-arm64.json
@@ -1,7 +1,8 @@
{
"name": "trusty_test_vm",
- "kernel": "/data/local/tmp/trusty_test_vm/trusty_test_vm_.elf",
+ "kernel": "/data/local/tmp/trusty_test_vm/trusty_test_vm.elf",
"platform_version": "1.0",
+ "cpu_topology": "one_cpu",
"memory_mib": 112,
"protected": true
}
diff --git a/guest/trusty/test_vm/trusty-test_vm-config-x86_64.json b/guest/trusty/test_vm/trusty-test_vm-config-x86_64.json
index d491c3a..5ce65ba 100644
--- a/guest/trusty/test_vm/trusty-test_vm-config-x86_64.json
+++ b/guest/trusty/test_vm/trusty-test_vm-config-x86_64.json
@@ -2,5 +2,6 @@
"name": "trusty_test_vm",
"kernel": "/data/local/tmp/trusty_test_vm/trusty_test_vm.elf",
"platform_version": "1.0",
+ "cpu_topology": "one_cpu",
"memory_mib": 112
}
diff --git a/guest/trusty/test_vm/trusty-ut-ctrl.sh b/guest/trusty/test_vm/trusty-ut-ctrl.sh
index 77a9459..2317496 100644
--- a/guest/trusty/test_vm/trusty-ut-ctrl.sh
+++ b/guest/trusty/test_vm/trusty-ut-ctrl.sh
@@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-/system_ext/bin/trusty-ut-ctrl.system -D VSOCK:${2:-$(getprop trusty.test_vm.vm_cid)}:1 $1
+/data/local/tmp/trusty_test_vm/trusty-ut-ctrl -D VSOCK:${2:-$(getprop trusty.test_vm.vm_cid)}:1 $1
diff --git a/guest/trusty/test_vm/vm/Android.bp b/guest/trusty/test_vm/vm/Android.bp
index 4f696b1..f978c92 100644
--- a/guest/trusty/test_vm/vm/Android.bp
+++ b/guest/trusty/test_vm/vm/Android.bp
@@ -2,11 +2,6 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-soong_config_module_type_import {
- from: "packages/modules/Virtualization/guest/trusty/common/Android.bp",
- module_types: ["trusty_vm_avb_add_hash_footer"],
-}
-
prebuilt_etc {
name: "trusty_test_vm_elf",
system_ext_specific: true,
@@ -94,7 +89,7 @@
TRUSTY_TEST_VM_VERSION = 1
-trusty_vm_avb_add_hash_footer {
+avb_add_hash_footer {
name: "trusty_test_vm_signed_bin",
filename: "trusty_test_vm_signed.bin",
partition_name: "boot",
diff --git a/libs/devicemapper/Android.bp b/libs/devicemapper/Android.bp
index 6b7f680..8dc6c8d 100644
--- a/libs/devicemapper/Android.bp
+++ b/libs/devicemapper/Android.bp
@@ -29,7 +29,6 @@
name: "libdm_rust.test",
defaults: [
"libdm_rust.defaults",
- "rdroidtest.defaults",
],
test_suites: ["general-tests"],
rustlibs: [
diff --git a/libs/devicemapper/src/lib.rs b/libs/devicemapper/src/lib.rs
index a8c2833..bc8a762 100644
--- a/libs/devicemapper/src/lib.rs
+++ b/libs/devicemapper/src/lib.rs
@@ -230,14 +230,10 @@
}
#[cfg(test)]
-rdroidtest::test_main!();
-
-#[cfg(test)]
mod tests {
use super::*;
use crate::loopdevice::LoopConfigOptions;
use crypt::{CipherType, DmCryptTargetBuilder};
- use rdroidtest::{ignore_if, rdroidtest};
use rustutils::system_properties;
use std::fs::{read, File, OpenOptions};
use std::io::Write;
@@ -294,25 +290,29 @@
}
}
- #[rdroidtest]
+ #[test]
fn mapping_again_keeps_data_xts() {
mapping_again_keeps_data(&KEY_SET_XTS, "name1");
}
- #[rdroidtest]
- #[ignore_if(!is_hctr2_supported())]
+ #[test]
fn mapping_again_keeps_data_hctr2() {
+ if !is_hctr2_supported() {
+ return;
+ }
mapping_again_keeps_data(&KEY_SET_HCTR2, "name2");
}
- #[rdroidtest]
+ #[test]
fn data_inaccessible_with_diff_key_xts() {
data_inaccessible_with_diff_key(&KEY_SET_XTS, "name3");
}
- #[rdroidtest]
- #[ignore_if(!is_hctr2_supported())]
+ #[test]
fn data_inaccessible_with_diff_key_hctr2() {
+ if !is_hctr2_supported() {
+ return;
+ }
data_inaccessible_with_diff_key(&KEY_SET_HCTR2, "name4");
}
diff --git a/libs/devicemapper/src/loopdevice.rs b/libs/devicemapper/src/loopdevice.rs
index b830eda..e41b90c 100644
--- a/libs/devicemapper/src/loopdevice.rs
+++ b/libs/devicemapper/src/loopdevice.rs
@@ -179,7 +179,6 @@
#[cfg(test)]
mod tests {
use super::*;
- use rdroidtest::rdroidtest;
use std::fs;
use std::path::Path;
@@ -199,7 +198,13 @@
"0" == fs::read_to_string(ro).unwrap().trim()
}
- #[rdroidtest]
+ fn is_autoclear(dev: &Path) -> bool {
+ let autoclear =
+ Path::new("/sys/block").join(dev.file_name().unwrap()).join("loop/autoclear");
+ "1" == fs::read_to_string(autoclear).unwrap().trim()
+ }
+
+ #[test]
fn attach_loop_device_with_dio() {
let a_dir = tempfile::TempDir::new().unwrap();
let a_file = a_dir.path().join("test");
@@ -215,7 +220,7 @@
assert!(is_direct_io(&dev));
}
- #[rdroidtest]
+ #[test]
fn attach_loop_device_without_dio() {
let a_dir = tempfile::TempDir::new().unwrap();
let a_file = a_dir.path().join("test");
@@ -228,7 +233,7 @@
assert!(!is_direct_io(&dev));
}
- #[rdroidtest]
+ #[test]
fn attach_loop_device_with_dio_writable() {
let a_dir = tempfile::TempDir::new().unwrap();
let a_file = a_dir.path().join("test");
@@ -249,7 +254,7 @@
assert!(is_direct_io_writable(&dev));
}
- #[rdroidtest]
+ #[test]
fn attach_loop_device_autoclear() {
let a_dir = tempfile::TempDir::new().unwrap();
let a_file = a_dir.path().join("test");
@@ -258,10 +263,7 @@
let dev =
attach(a_file, 0, a_size, &LoopConfigOptions { autoclear: true, ..Default::default() })
.unwrap();
- drop(dev.file);
- let dev_size_path =
- Path::new("/sys/block").join(dev.path.file_name().unwrap()).join("size");
- assert_eq!("0", fs::read_to_string(dev_size_path).unwrap().trim());
+ assert!(is_autoclear(&dev.path));
}
}
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java
index af313a1..40050c0 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java
@@ -288,17 +288,7 @@
percent = 50;
}
- synchronized (mLock) {
- try {
- if (mVirtualMachine != null) {
- long bytes = mConfig.getMemoryBytes();
- mVirtualMachine.setMemoryBalloon(bytes * percent / 100);
- }
- } catch (Exception e) {
- /* Caller doesn't want our exceptions. Log them instead. */
- Log.w(TAG, "TrimMemory failed: ", e);
- }
- }
+ setMemoryBalloonByPercent(percent);
}
}
@@ -1392,6 +1382,24 @@
}
}
+ /** @hide */
+ public void setMemoryBalloonByPercent(int percent) {
+ if (percent < 0 || percent > 100) {
+ Log.e(TAG, String.format("Invalid percent value: %d", percent));
+ return;
+ }
+ synchronized (mLock) {
+ try {
+ if (mVirtualMachine != null && mVirtualMachine.isMemoryBalloonEnabled()) {
+ long bytes = mConfig.getMemoryBytes();
+ mVirtualMachine.setMemoryBalloon(bytes * percent / 100);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.w(TAG, "Cannot setMemoryBalloon", e);
+ }
+ }
+ }
+
private boolean writeEventsToSock(ParcelFileDescriptor sock, List<InputEvent> evtList) {
ByteBuffer byteBuffer =
ByteBuffer.allocate(8 /* (type: u16 + code: u16 + value: i32) */ * evtList.size());
@@ -1563,6 +1571,12 @@
? createVirtualMachineConfigForRawFrom(vmConfig)
: createVirtualMachineConfigForAppFrom(vmConfig, service);
+ if (vmConfig.isEncryptedStorageEnabled()) {
+ service.setEncryptedStorageSize(
+ ParcelFileDescriptor.open(mEncryptedStoreFilePath, MODE_READ_WRITE),
+ vmConfig.getEncryptedStorageBytes());
+ }
+
mVirtualMachine =
service.createVm(
vmConfigParcel, consoleOutFd, consoleInFd, mLogWriter, null);
@@ -1918,6 +1932,8 @@
* <p>The new config must be {@linkplain VirtualMachineConfig#isCompatibleWith compatible with}
* the existing config.
*
+ * <p>NOTE: Modification of the encrypted storage size is restricted to expansion only and is an
+ * irreversible operation.
* <p>NOTE: This method may block and should not be called on the main thread.
*
* @return the old config
@@ -1932,7 +1948,9 @@
throws VirtualMachineException {
synchronized (mLock) {
VirtualMachineConfig oldConfig = mConfig;
- if (!oldConfig.isCompatibleWith(newConfig)) {
+ if (!oldConfig.isCompatibleWith(newConfig)
+ || oldConfig.getEncryptedStorageBytes()
+ > newConfig.getEncryptedStorageBytes()) {
throw new VirtualMachineException("incompatible config");
}
checkStopped();
@@ -1948,8 +1966,43 @@
}
}
- @Nullable
- private static native IBinder nativeConnectToVsockServer(IBinder vmBinder, int port);
+ /**
+ * Abstracts away the task of creating a vsock connection. Normally, in the same process, you'll
+ * make the connection and then promote it to a binder as part of the same API call, but if you
+ * want to pass a connection to another process first, before establishing the RPC binder
+ * connection, you may implement this method by getting a vsock connection from another process.
+ *
+ * <p>It is recommended to convert other types of exceptions (e.g. remote exceptions) to
+ * VirtualMachineException, so that all connection failures will be visible under the same type
+ * of exception.
+ *
+ * @hide
+ */
+ public interface VsockConnectionProvider {
+ @NonNull
+ public ParcelFileDescriptor addConnection() throws VirtualMachineException;
+ }
+
+ /**
+ * Class to make it easy to use JNI, without needing PFD and other classes.
+ *
+ * @hide
+ */
+ private static class NativeProviderWrapper {
+ private VsockConnectionProvider mProvider = null;
+
+ // ensures last FD is owned until get is called again
+ private ParcelFileDescriptor mMoreLifetime = null;
+
+ public NativeProviderWrapper(VsockConnectionProvider provider) {
+ mProvider = provider;
+ }
+
+ int connect() throws VirtualMachineException {
+ mMoreLifetime = mProvider.addConnection();
+ return mMoreLifetime.getFileDescriptor().getInt$();
+ }
+ }
/**
* Connect to a VM's binder service via vsock and return the root IBinder object. Guest VMs are
@@ -1969,15 +2022,36 @@
public IBinder connectToVsockServer(
@IntRange(from = MIN_VSOCK_PORT, to = MAX_VSOCK_PORT) long port)
throws VirtualMachineException {
+ VsockConnectionProvider provider =
+ new VsockConnectionProvider() {
+ @Override
+ public ParcelFileDescriptor addConnection() throws VirtualMachineException {
+ return connectVsock(port);
+ }
+ };
+ return binderFromPreconnectedClient(provider);
+ }
- synchronized (mLock) {
- IBinder iBinder =
- nativeConnectToVsockServer(getRunningVm().asBinder(), validatePort(port));
- if (iBinder == null) {
- throw new VirtualMachineException("Failed to connect to vsock server");
- }
- return iBinder;
+ @Nullable
+ private static native IBinder nativeBinderFromPreconnectedClient(
+ NativeProviderWrapper provider);
+
+ /**
+ * Convert existing vsock connection to a binder connection.
+ *
+ * <p>connectToVsockServer = connectToVsock + binderFromPreconnectedClient
+ *
+ * @hide
+ */
+ @WorkerThread
+ @NonNull
+ public static IBinder binderFromPreconnectedClient(@NonNull VsockConnectionProvider provider)
+ throws VirtualMachineException {
+ IBinder binder = nativeBinderFromPreconnectedClient(new NativeProviderWrapper(provider));
+ if (binder == null) {
+ throw new VirtualMachineException("Failed to connect to vsock server");
}
+ return binder;
}
/**
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 2668ca2..ff1f5bf 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -635,7 +635,6 @@
}
return this.mDebugLevel == other.mDebugLevel
&& this.mProtectedVm == other.mProtectedVm
- && this.mEncryptedStorageBytes == other.mEncryptedStorageBytes
&& this.mVmOutputCaptured == other.mVmOutputCaptured
&& this.mVmConsoleInputSupported == other.mVmConsoleInputSupported
&& this.mConnectVmConsole == other.mConnectVmConsole
diff --git a/libs/libservice_vm_requests/src/client_vm.rs b/libs/libservice_vm_requests/src/client_vm.rs
index 4e54510..8ad10fd 100644
--- a/libs/libservice_vm_requests/src/client_vm.rs
+++ b/libs/libservice_vm_requests/src/client_vm.rs
@@ -25,7 +25,7 @@
use core::result;
use coset::{AsCborValue, CborSerializable, CoseSign, CoseSign1};
use der::{Decode, Encode};
-use diced_open_dice::{DiceArtifacts, HASH_SIZE};
+use diced_open_dice::DiceArtifacts;
use log::{debug, error, info};
use microdroid_kernel_hashes::{HASH_SIZE as KERNEL_HASH_SIZE, OS_HASHES};
use service_vm_comm::{ClientVmAttestationParams, Csr, CsrPayload, RequestProcessingError};
@@ -252,7 +252,7 @@
Ok(false)
}
-fn expected_kernel_authority_hash(service_vm_entry: &Value) -> Result<[u8; HASH_SIZE]> {
+fn expected_kernel_authority_hash(service_vm_entry: &Value) -> Result<Vec<u8>> {
let cose_sign1 = CoseSign1::from_cbor_value(service_vm_entry.clone())?;
let payload = cose_sign1.payload.ok_or_else(|| {
error!("No payload found in the service VM DICE chain entry");
diff --git a/libs/libservice_vm_requests/src/dice.rs b/libs/libservice_vm_requests/src/dice.rs
index ef9d894..ba67450 100644
--- a/libs/libservice_vm_requests/src/dice.rs
+++ b/libs/libservice_vm_requests/src/dice.rs
@@ -19,8 +19,8 @@
use alloc::vec::Vec;
use bssl_avf::{ed25519_verify, Digester, EcKey};
use cbor_util::{
- cbor_value_type, get_label_value, get_label_value_as_bytes, value_to_array,
- value_to_byte_array, value_to_bytes, value_to_map, value_to_num, value_to_text,
+ cbor_value_type, get_label_value, get_label_value_as_bytes, value_to_array, value_to_bytes,
+ value_to_map, value_to_num, value_to_text,
};
use ciborium::value::Value;
use core::cell::OnceCell;
@@ -31,7 +31,7 @@
Algorithm, AsCborValue, CborSerializable, CoseError, CoseKey, CoseSign1, KeyOperation, KeyType,
Label,
};
-use diced_open_dice::{DiceMode, HASH_SIZE};
+use diced_open_dice::DiceMode;
use log::{debug, error, info};
use service_vm_comm::RequestProcessingError;
@@ -288,8 +288,8 @@
pub(crate) struct DiceChainEntryPayload {
pub(crate) subject_public_key: PublicKey,
mode: DiceMode,
- pub(crate) code_hash: [u8; HASH_SIZE],
- pub(crate) authority_hash: [u8; HASH_SIZE],
+ pub(crate) code_hash: Vec<u8>,
+ pub(crate) authority_hash: Vec<u8>,
config_descriptor: ConfigDescriptor,
}
@@ -327,12 +327,12 @@
}
MODE => builder.mode(to_mode(value)?)?,
CODE_HASH => {
- let code_hash = value_to_byte_array(value, "DiceChainEntryPayload code_hash")?;
+ let code_hash = value_to_bytes(value, "DiceChainEntryPayload code_hash")?;
builder.code_hash(code_hash)?;
}
AUTHORITY_HASH => {
let authority_hash =
- value_to_byte_array(value, "DiceChainEntryPayload authority_hash")?;
+ value_to_bytes(value, "DiceChainEntryPayload authority_hash")?;
builder.authority_hash(authority_hash)?;
}
CONFIG_DESC => {
@@ -524,8 +524,8 @@
struct PayloadBuilder {
subject_public_key: OnceCell<PublicKey>,
mode: OnceCell<DiceMode>,
- code_hash: OnceCell<[u8; HASH_SIZE]>,
- authority_hash: OnceCell<[u8; HASH_SIZE]>,
+ code_hash: OnceCell<Vec<u8>>,
+ authority_hash: OnceCell<Vec<u8>>,
config_descriptor: OnceCell<ConfigDescriptor>,
}
@@ -552,11 +552,11 @@
set_once(&self.mode, mode, "mode")
}
- fn code_hash(&mut self, code_hash: [u8; HASH_SIZE]) -> Result<()> {
+ fn code_hash(&mut self, code_hash: Vec<u8>) -> Result<()> {
set_once(&self.code_hash, code_hash, "code_hash")
}
- fn authority_hash(&mut self, authority_hash: [u8; HASH_SIZE]) -> Result<()> {
+ fn authority_hash(&mut self, authority_hash: Vec<u8>) -> Result<()> {
set_once(&self.authority_hash, authority_hash, "authority_hash")
}
@@ -570,7 +570,9 @@
// the Open Profile for DICE spec.
let mode = self.mode.take().unwrap_or(DiceMode::kDiceModeNotInitialized);
let code_hash = take_value(&mut self.code_hash, "code_hash")?;
+ validate_hash_size(code_hash.len(), "code_hash")?;
let authority_hash = take_value(&mut self.authority_hash, "authority_hash")?;
+ validate_hash_size(authority_hash.len(), "authority_hash")?;
let config_descriptor = take_value(&mut self.config_descriptor, "config_descriptor")?;
Ok(DiceChainEntryPayload {
subject_public_key,
@@ -581,3 +583,18 @@
})
}
}
+
+fn validate_hash_size(len: usize, name: &str) -> Result<()> {
+ // According to the Android Profile for DICE specification, SHA-256, SHA-384, and SHA-512
+ // are all acceptable hash algorithms.
+ const ACCEPTABLE_HASH_SIZES: [usize; 3] = [32, 48, 64];
+ if ACCEPTABLE_HASH_SIZES.contains(&len) {
+ Ok(())
+ } else {
+ error!(
+ "Invalid hash size for {}: {}. Acceptable hash sizes are: {:?}",
+ name, len, ACCEPTABLE_HASH_SIZES
+ );
+ Err(RequestProcessingError::InvalidDiceChain)
+ }
+}
diff --git a/libs/libvirtualization_jni/android_system_virtualmachine_VirtualMachine.cpp b/libs/libvirtualization_jni/android_system_virtualmachine_VirtualMachine.cpp
index 3f1d8a0..8452344 100644
--- a/libs/libvirtualization_jni/android_system_virtualmachine_VirtualMachine.cpp
+++ b/libs/libvirtualization_jni/android_system_virtualmachine_VirtualMachine.cpp
@@ -48,41 +48,40 @@
} // namespace
extern "C" JNIEXPORT jobject JNICALL
-Java_android_system_virtualmachine_VirtualMachine_nativeConnectToVsockServer(
- JNIEnv *env, [[maybe_unused]] jclass clazz, jobject vmBinder, jint port) {
- using aidl::android::system::virtualizationservice::IVirtualMachine;
- using ndk::ScopedFileDescriptor;
- using ndk::SpAIBinder;
+Java_android_system_virtualmachine_VirtualMachine_nativeBinderFromPreconnectedClient(
+ [[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass clazz, jobject provider) {
+ ScopedLocalRef<jclass> callback_class(env, env->GetObjectClass(provider));
+ jmethodID mid = env->GetMethodID(callback_class.get(), "connect", "()I");
+ LOG_ALWAYS_FATAL_IF(mid == nullptr, "Could not find method");
- auto vm = IVirtualMachine::fromBinder(SpAIBinder{AIBinder_fromJavaBinder(env, vmBinder)});
-
- std::tuple args{env, vm.get(), port};
- using Args = decltype(args);
-
- auto requestFunc = [](void *param) {
- auto [env, vm, port] = *static_cast<Args *>(param);
-
- ScopedFileDescriptor fd;
- if (auto status = vm->connectVsock(port, &fd); !status.isOk()) {
- env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
- ("Failed to connect vsock: " + status.getDescription()).c_str());
- return -1;
- }
-
- // take ownership
- int ret = fd.get();
- *fd.getR() = -1;
-
- return ret;
+ // TODO(b/398890208): make this memory owned by the connection
+ struct State {
+ JNIEnv *mEnv;
+ jobject mProvider;
+ jmethodID mMid;
};
+ auto state = std::make_unique<State>(env, provider, mid);
+
+ using RequestFun = int (*)(void *);
+ RequestFun requestFunc = [](void *param) -> int {
+ State *state = static_cast<State *>(param);
+ int ownedFd = state->mEnv->CallIntMethod(state->mProvider, state->mMid);
+ // FD is owned by PFD in Java layer, need to dupe it so that
+ // ARpcSession_setupPreconnectedClient can take ownership when it calls unique_fd internally
+ return fcntl(ownedFd, F_DUPFD_CLOEXEC, 0);
+ };
+
+ auto paramDeleteFunc = [](void *param) { delete static_cast<State *>(param); };
+
RpcSessionHandle session;
// We need a thread pool to be able to support linkToDeath, or callbacks
// (b/268335700). These threads are currently created eagerly, so we don't
// want too many. The number 1 is chosen after some discussion, and to match
// the server-side default (mMaxThreads on RpcServer).
ARpcSession_setMaxIncomingThreads(session.get(), 1);
- auto client = ARpcSession_setupPreconnectedClient(session.get(), requestFunc, &args);
+ auto client = ARpcSession_setupPreconnectedClient(session.get(), requestFunc, state.release(),
+ paramDeleteFunc);
return AIBinder_toJavaBinder(env, client);
}
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index 4c824f0..5d92976 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -47,6 +47,9 @@
/* get the encrypted storage path. */
String getEncryptedStoragePath();
+ /* get the size of the encrypted storage in bytes. */
+ long getEncryptedStorageSize();
+
/* start a simple vsock server on ECHO_REVERSE_PORT that reads a line at a time and echoes
* each line reverse.
*/
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index 18ed7b6..4294df4 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -641,6 +641,7 @@
public String mExtraApkTestProp;
public String mApkContentsPath;
public String mEncryptedStoragePath;
+ public long mEncryptedStorageSize;
public String[] mEffectiveCapabilities;
public int mUid;
public String mFileContent;
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 639224d..9d08ed7 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -129,6 +129,7 @@
private static final String TEST_APP_PACKAGE_NAME = "com.android.microdroid.test";
private static final String VM_ATTESTATION_PAYLOAD_PATH = "libvm_attestation_test_payload.so";
private static final String VM_ATTESTATION_MESSAGE = "Hello RKP from AVF!";
+ private static final long TOLERANCE_BYTES = 400_000;
private static final int ENCRYPTED_STORAGE_BYTES = 4_000_000;
private static final String RELAXED_ROLLBACK_PROTECTION_SCHEME_TEST_PACKAGE_NAME =
@@ -741,11 +742,6 @@
// so in the API spec.
assertConfigCompatible(baseline, newBaselineBuilder().setApkPath("/different")).isTrue();
- // Changes that are currently incompatible for ease of implementation, but this might change
- // in the future.
- assertConfigCompatible(baseline, newBaselineBuilder().setEncryptedStorageBytes(100_000))
- .isFalse();
-
VirtualMachineConfig.Builder debuggableBuilder =
newBaselineBuilder().setDebugLevel(DEBUG_LEVEL_FULL);
VirtualMachineConfig debuggable = debuggableBuilder.build();
@@ -1866,6 +1862,169 @@
assertThat(testResults.mFileContent).isEqualTo(EXAMPLE_STRING);
}
+ @Test
+ @CddTest
+ public void encryptedStorageSupportsExpansion() throws Exception {
+ assumeSupportedDevice();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES)
+ .build();
+
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mEncryptedStorageSize = ts.getEncryptedStorageSize();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mEncryptedStorageSize)
+ .isWithin(TOLERANCE_BYTES)
+ .of(ENCRYPTED_STORAGE_BYTES);
+
+ // Re-run the VM with more storage size & verify the file persisted.
+ // Note, the previous `runVmTestService` stopped the VM
+ config = newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES * 2)
+ .build();
+ vm.setConfig(config);
+ assertThat(vm.getConfig().getEncryptedStorageBytes())
+ .isEqualTo(ENCRYPTED_STORAGE_BYTES * 2);
+
+ testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mEncryptedStorageSize = ts.getEncryptedStorageSize();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mEncryptedStorageSize)
+ .isWithin(TOLERANCE_BYTES)
+ .of(ENCRYPTED_STORAGE_BYTES * 2);
+ }
+
+ @Test
+ @CddTest
+ public void encryptedStorageExpansionIsPersistent() throws Exception {
+ assumeSupportedDevice();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES)
+ .build();
+
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ ts.writeToFile(
+ /* content= */ EXAMPLE_STRING,
+ /* path= */ "/mnt/encryptedstore/test_file");
+ });
+ testResults.assertNoException();
+
+ // Re-run the VM with more storage size & verify the file persisted.
+ // Note, the previous `runVmTestService` stopped the VM
+ config = newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES * 2)
+ .build();
+ vm.setConfig(config);
+
+ testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mFileContent = ts.readFromFile("/mnt/encryptedstore/test_file");
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mFileContent).isEqualTo(EXAMPLE_STRING);
+ }
+
+ @Test
+ @CddTest
+ public void encryptedStorageSizeUnchanged() throws Exception {
+ assumeSupportedDevice();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES)
+ .build();
+
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mEncryptedStorageSize = ts.getEncryptedStorageSize();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mEncryptedStorageSize)
+ .isWithin(TOLERANCE_BYTES)
+ .of(ENCRYPTED_STORAGE_BYTES);
+
+ // Re-run the VM with more storage size & verify the file persisted.
+ // Note, the previous `runVmTestService` stopped the VM
+ config = newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES)
+ .build();
+ vm.setConfig(config);
+ assertThat(vm.getConfig().getEncryptedStorageBytes())
+ .isEqualTo(ENCRYPTED_STORAGE_BYTES);
+
+ testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mEncryptedStorageSize = ts.getEncryptedStorageSize();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mEncryptedStorageSize)
+ .isWithin(TOLERANCE_BYTES)
+ .of(ENCRYPTED_STORAGE_BYTES);
+ }
+
+ @Test
+ @CddTest
+ public void encryptedStorageShrinkFails() throws Exception {
+ assumeSupportedDevice();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES)
+ .build();
+
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mEncryptedStorageSize = ts.getEncryptedStorageSize();
+ });
+ testResults.assertNoException();
+ assertThat(testResults.mEncryptedStorageSize)
+ .isWithin(TOLERANCE_BYTES)
+ .of(ENCRYPTED_STORAGE_BYTES);
+
+ // Re-run the VM with more storage size & verify the file persisted.
+ // Note, the previous `runVmTestService` stopped the VM
+ VirtualMachineConfig newConfig =
+ newVmConfigBuilderWithPayloadBinary("MicrodroidTestNativeLib.so")
+ .setEncryptedStorageBytes(ENCRYPTED_STORAGE_BYTES / 2)
+ .build();
+ assertThrowsVmExceptionContaining(
+ () -> vm.setConfig(newConfig), "incompatible config");
+ }
+
private boolean deviceCapableOfProtectedVm() {
int capabilities = getVirtualMachineManager().getCapabilities();
if ((capabilities & CAPABILITY_PROTECTED_VM) != 0) {
@@ -2007,11 +2166,6 @@
assumeFalse(
"Cuttlefish/Goldfish doesn't support device tree under /proc/device-tree",
isCuttlefish() || isGoldfish());
- if (!isUpdatableVmSupported()) {
- // TODO(b/389611249): Non protected VMs using legacy secret mechanisms do not reliably
- // implement `AVmPayload_isNewInstance`.
- assumeProtectedVM();
- }
VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_a", config);
TestResults testResults =
runVmTestService(
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 355cfb1..13eafce 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -29,6 +29,7 @@
#include <stdint.h>
#include <stdio.h>
#include <sys/capability.h>
+#include <sys/statvfs.h>
#include <sys/system_properties.h>
#ifdef __MICRODROID_TEST_PAYLOAD_USES_LIBICU__
#include <unicode/uchar.h>
@@ -232,6 +233,23 @@
return ScopedAStatus::ok();
}
+ ScopedAStatus getEncryptedStorageSize(int64_t *out) override {
+ const char* path_c = AVmPayload_getEncryptedStoragePath();
+ if (path_c == nullptr) {
+ *out = 0;
+ return ScopedAStatus::ok();
+ }
+ struct statvfs buffer;
+ if (statvfs(path_c, &buffer) != 0) {
+ std::string msg = "statvfs " + std::string(path_c) + " failed : " +
+ std::strerror(errno);
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ msg.c_str());
+ }
+ *out= buffer.f_blocks * buffer.f_frsize;
+ return ScopedAStatus::ok();
+ }
+
ScopedAStatus getEffectiveCapabilities(std::vector<std::string>* out) override {
if (out == nullptr) {
return ScopedAStatus::ok();
diff --git a/tests/testapk/src/native/testbinary.rs b/tests/testapk/src/native/testbinary.rs
index 3900cad..6a7d96e 100644
--- a/tests/testapk/src/native/testbinary.rs
+++ b/tests/testapk/src/native/testbinary.rs
@@ -87,6 +87,10 @@
// Everything below here is unimplemented. Implementations may be added as needed.
+ fn getEncryptedStorageSize(&self) -> BinderResult<i64> {
+ unimplemented()
+ }
+
fn readProperty(&self, _: &str) -> BinderResult<String> {
unimplemented()
}
diff --git a/tests/vm_accessor/test/Android.bp b/tests/vm_accessor/test/Android.bp
index 71746c7..16e9b1e 100644
--- a/tests/vm_accessor/test/Android.bp
+++ b/tests/vm_accessor/test/Android.bp
@@ -22,9 +22,6 @@
rust_test {
name: "vm_accessor_test",
srcs: ["src/test.rs"],
- defaults: [
- "rdroidtest.defaults",
- ],
test_suites: [
"general-tests",
],
diff --git a/tests/vm_accessor/test/src/test.rs b/tests/vm_accessor/test/src/test.rs
index d521acf..4d25fcd 100644
--- a/tests/vm_accessor/test/src/test.rs
+++ b/tests/vm_accessor/test/src/test.rs
@@ -18,7 +18,6 @@
use com_android_virt_accessor_demo_vm_service::aidl::com::android::virt::accessor_demo::vm_service::IAccessorVmService::IAccessorVmService;
use binder::{Strong, ProcessState};
-use rdroidtest::rdroidtest;
const VM_SERVICE: &str = "com.android.virt.accessor_demo.vm_service.IAccessorVmService/default";
@@ -39,7 +38,7 @@
binder::check_interface(VM_SERVICE).unwrap()
}
-#[rdroidtest]
+#[test]
fn test_wait_for_interface() {
init();
@@ -49,7 +48,7 @@
assert_eq!(sum, 23);
}
-#[rdroidtest]
+#[test]
fn test_wait_for_interface_twice() {
init();
@@ -60,7 +59,7 @@
assert_eq!(service2.add(11, 12).unwrap(), 23);
}
-#[rdroidtest]
+#[test]
fn test_wait_and_get_interface() {
init();
@@ -71,7 +70,7 @@
assert_eq!(service2.add(11, 12).unwrap(), 23);
}
-#[rdroidtest]
+#[test]
fn test_wait_and_check_interface() {
init();
@@ -81,5 +80,3 @@
assert_eq!(service1.add(11, 12).unwrap(), 23);
assert_eq!(service2.add(11, 12).unwrap(), 23);
}
-
-rdroidtest::test_main!();
diff --git a/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java b/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
index 7f44fa5..9489aed 100644
--- a/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
+++ b/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
@@ -223,6 +223,11 @@
}
@Override
+ public long getEncryptedStorageSize() throws RemoteException {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
public void runEchoReverseServer() throws RemoteException {
throw new UnsupportedOperationException("Not supported");
}
diff --git a/tests/vts/AndroidTest.xml b/tests/vts/AndroidTest.xml
index 6926f9f..a59f161 100644
--- a/tests/vts/AndroidTest.xml
+++ b/tests/vts/AndroidTest.xml
@@ -21,7 +21,7 @@
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="vts_libavf_test->/data/nativetest64/vendor/vts_libavf_test" />
- <option name="push" value="rialto.bin->/data/local/tmp/rialto.bin" />
+ <option name="push" value="rialto.bin->/data/nativetest64/vendor/rialto.bin" />
</target_preparer>
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.ArchModuleController">
diff --git a/tests/vts/src/vts_libavf_test.rs b/tests/vts/src/vts_libavf_test.rs
index dc37aad..c13b510 100644
--- a/tests/vts/src/vts_libavf_test.rs
+++ b/tests/vts/src/vts_libavf_test.rs
@@ -75,7 +75,7 @@
fn run_rialto(protected_vm: bool) -> Result<()> {
let kernel_file =
- File::open("/data/local/tmp/rialto.bin").context("Failed to open kernel file")?;
+ File::open("/data/nativetest64/vendor/rialto.bin").context("Failed to open kernel file")?;
let kernel_fd = kernel_file.into_raw_fd();
// SAFETY: AVirtualMachineRawConfig_create() isn't unsafe but rust_bindgen forces it to be seen