Merge "AVF: promote FD->IBinder to SystemApi." into main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index d47afc4..1c078ce 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -19,6 +19,3 @@
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
rustfmt = --config-path=rustfmt.toml
ktfmt = --kotlinlang-style
-
-[Hook Scripts]
-aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "."
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
index 887ae02..e035ad4 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
@@ -28,6 +28,7 @@
import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse
import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest
import com.android.virtualization.terminal.proto.ShutdownRequestItem
+import io.grpc.stub.ServerCallStreamObserver
import io.grpc.stub.StreamObserver
internal class DebianServiceImpl(context: Context) : DebianServiceImplBase() {
@@ -79,8 +80,15 @@
request: ShutdownQueueOpeningRequest?,
responseObserver: StreamObserver<ShutdownRequestItem?>,
) {
+ val serverCallStreamObserver = responseObserver as ServerCallStreamObserver<ShutdownRequestItem?>
+ serverCallStreamObserver.setOnCancelHandler {
+ shutdownRunnable = null
+ }
Log.d(TAG, "openShutdownRequestQueue")
shutdownRunnable = Runnable {
+ if (serverCallStreamObserver.isCancelled()) {
+ return@Runnable
+ }
responseObserver.onNext(ShutdownRequestItem.newBuilder().build())
responseObserver.onCompleted()
shutdownRunnable = null
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
index 017ff89..54754ff 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 {
@@ -138,8 +146,8 @@
companion object {
private const val DIR_IN_SDCARD = "linux"
private const val ARCHIVE_NAME = "images.tar.gz"
- private const val BUILD_TAG = "latest" // TODO: use actual tag name
- private const val HOST_URL = "https://dl.google.com/android/ferrochrome/$BUILD_TAG"
+ private val BUILD_TAG = Integer.toString(Build.VERSION.SDK_INT_FULL)
+ private val HOST_URL = "https://dl.google.com/android/ferrochrome/$BUILD_TAG"
fun getSdcardPathForTesting(): Path {
return Environment.getExternalStoragePublicDirectory(DIR_IN_SDCARD).toPath()
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/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/Logger.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
index 547f1a7..4162247 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
@@ -30,6 +30,7 @@
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
+import java.time.LocalDateTime
import java.util.concurrent.ExecutorService
import libcore.io.Streams
@@ -37,14 +38,20 @@
* Forwards VM's console output to a file on the Android side, and VM's log output to Android logd.
*/
internal object Logger {
- fun setup(vm: VirtualMachine, path: Path, executor: ExecutorService) {
+ fun setup(vm: VirtualMachine, dir: Path, executor: ExecutorService) {
+ val tag = vm.name
+
if (vm.config.debugLevel != VirtualMachineConfig.DEBUG_LEVEL_FULL) {
+ Log.i(tag, "Logs are not captured. Non-debuggable VM.")
return
}
try {
+ Files.createDirectories(dir)
+ deleteOldLogs(dir, 10)
+ val logPath = dir.resolve(LocalDateTime.now().toString() + ".txt")
val console = vm.getConsoleOutput()
- val file = Files.newOutputStream(path, StandardOpenOption.CREATE)
+ val file = Files.newOutputStream(logPath, StandardOpenOption.CREATE)
executor.submit<Int?> {
console.use { console ->
LineBufferedOutputStream(file).use { fileOutput ->
@@ -54,7 +61,7 @@
}
val log = vm.getLogOutput()
- executor.submit<Unit> { log.use { writeToLogd(it, vm.name) } }
+ executor.submit<Unit> { log.use { writeToLogd(it, tag) } }
} catch (e: VirtualMachineException) {
throw RuntimeException(e)
} catch (e: IOException) {
@@ -62,12 +69,32 @@
}
}
+ fun deleteOldLogs(dir: Path, numLogsToKeep: Long) {
+ Files.list(dir)
+ .filter { Files.isRegularFile(it) }
+ .sorted(
+ Comparator.comparingLong { f: Path ->
+ // for some reason, type inference didn't work here!
+ Files.getLastModifiedTime(f).toMillis()
+ }
+ .reversed()
+ )
+ .skip(numLogsToKeep)
+ .forEach {
+ try {
+ Files.delete(it)
+ } catch (e: IOException) {
+ // don't bother
+ }
+ }
+ }
+
@Throws(IOException::class)
- private fun writeToLogd(input: InputStream?, vmName: String?) {
+ private fun writeToLogd(input: InputStream?, tag: String?) {
val reader = BufferedReader(InputStreamReader(input))
reader
.useLines { lines -> lines.takeWhile { !Thread.interrupted() } }
- .forEach { Log.d(vmName, it) }
+ .forEach { Log.d(tag, it) }
}
private class LineBufferedOutputStream(out: OutputStream?) : BufferedOutputStream(out) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
index f6eeff9..35c5570 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -24,14 +24,11 @@
import android.graphics.drawable.Icon
import android.graphics.fonts.FontStyle
import android.net.Uri
-import android.net.nsd.NsdManager
-import android.net.nsd.NsdServiceInfo
import android.os.Build
import android.os.Bundle
import android.os.ConditionVariable
import android.os.Environment
import android.os.SystemProperties
-import android.os.Trace
import android.provider.Settings
import android.util.DisplayMetrics
import android.util.Log
@@ -62,6 +59,7 @@
import java.io.IOException
import java.net.MalformedURLException
import java.net.URL
+import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
@@ -78,12 +76,11 @@
private lateinit var image: InstalledImage
private lateinit var accessibilityManager: AccessibilityManager
private lateinit var manageExternalStorageActivityResultLauncher: ActivityResultLauncher<Intent>
- private var ipAddress: String? = null
- private var port: Int? = null
private lateinit var terminalViewModel: TerminalViewModel
private lateinit var viewPager: ViewPager2
private lateinit var tabLayout: TabLayout
private lateinit var terminalTabAdapter: TerminalTabAdapter
+ private val terminalInfo = CompletableFuture<TerminalInfo>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -243,40 +240,12 @@
}
fun connectToTerminalService(terminalView: TerminalView) {
- if (ipAddress != null && port != null) {
- val url = getTerminalServiceUrl(ipAddress, port!!)
- terminalView.loadUrl(url.toString())
- return
- }
- // TODO: refactor this block as a method
- val nsdManager = getSystemService<NsdManager>(NsdManager::class.java)
- val info = NsdServiceInfo()
- info.serviceType = "_http._tcp"
- info.serviceName = "ttyd"
- nsdManager.registerServiceInfoCallback(
- info,
- executorService,
- object : NsdManager.ServiceInfoCallback {
- var loaded: Boolean = false
-
- override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
-
- override fun onServiceInfoCallbackUnregistered() {}
-
- override fun onServiceLost() {}
-
- override fun onServiceUpdated(info: NsdServiceInfo) {
- Log.i(TAG, "Service found: $info")
- if (!loaded) {
- ipAddress = info.hostAddresses[0].hostAddress
- port = info.port
- val url = getTerminalServiceUrl(ipAddress, port!!)
- loaded = true
- nsdManager.unregisterServiceInfoCallback(this)
- runOnUiThread(Runnable { terminalView.loadUrl(url.toString()) })
- }
- }
+ terminalInfo.thenAcceptAsync(
+ { info ->
+ val url = getTerminalServiceUrl(info.ipAddress, info.port)
+ runOnUiThread({ terminalView.loadUrl(url.toString()) })
},
+ executorService,
)
}
@@ -292,6 +261,10 @@
Log.i(TAG, "onVmStart()")
}
+ override fun onTerminalAvailable(info: TerminalInfo) {
+ terminalInfo.complete(info)
+ }
+
override fun onVmStop() {
Log.i(TAG, "onVmStop()")
finish()
@@ -354,7 +327,7 @@
val stopIntent = Intent()
stopIntent.setClass(this, VmLauncherService::class.java)
- stopIntent.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE)
+ stopIntent.setAction(VmLauncherService.ACTION_SHUTDOWN_VM)
val stopPendingIntent =
PendingIntent.getService(
this,
@@ -389,7 +362,6 @@
)
.build()
- Trace.beginAsyncSection("executeTerminal", 0)
run(this, this, notification, getDisplayInfo())
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt
new file mode 100644
index 0000000..7647d9b
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MemBalloonController.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.system.virtualmachine.VirtualMachine
+import android.util.Log
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.ProcessLifecycleOwner
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.util.concurrent.Executors
+import java.util.concurrent.ScheduledFuture
+import java.util.concurrent.TimeUnit
+
+/**
+ * MemBalloonController is responsible for adjusting the memory ballon size of a VM depending on
+ * whether the app is visible or running in the background
+ */
+class MemBalloonController(val context: Context, val vm: VirtualMachine) {
+ companion object {
+ private const val INITIAL_PERCENT = 10
+ private const val MAX_PERCENT = 50
+ private const val INFLATION_STEP_PERCENT = 5
+ private const val INFLATION_PERIOD_SEC = 60L
+
+ private val mainHandler = Handler(Looper.getMainLooper())
+
+ private fun runOnMainThread(runnable: Runnable) {
+ mainHandler.post(runnable)
+ }
+ }
+
+ private val executor =
+ Executors.newSingleThreadScheduledExecutor(
+ TerminalThreadFactory(context.getApplicationContext())
+ )
+
+ private val observer =
+ object : DefaultLifecycleObserver {
+
+ // If the app is started or resumed, give deflate the balloon to 0 to give maximum
+ // available memory to the virtual machine
+ override fun onResume(owner: LifecycleOwner) {
+ ongoingInflation?.cancel(false)
+ executor.submit({
+ Log.v(TAG, "app resumed. deflating mem balloon to the minimum")
+ vm.setMemoryBalloonByPercent(0)
+ })
+ }
+
+ // If the app goes into background, progressively inflate the balloon from
+ // INITIAL_PERCENT until it reaches MAX_PERCENT
+ override fun onStop(owner: LifecycleOwner) {
+ ongoingInflation?.cancel(false)
+ balloonPercent = INITIAL_PERCENT
+ ongoingInflation =
+ executor.scheduleAtFixedRate(
+ {
+ if (balloonPercent <= MAX_PERCENT) {
+ Log.v(TAG, "inflating mem balloon to ${balloonPercent} %")
+ vm.setMemoryBalloonByPercent(balloonPercent)
+ balloonPercent += INFLATION_STEP_PERCENT
+ } else {
+ Log.v(TAG, "mem balloon is inflated to its max (${MAX_PERCENT} %)")
+ ongoingInflation!!.cancel(false)
+ }
+ },
+ 0 /* initialDelay */,
+ INFLATION_PERIOD_SEC,
+ TimeUnit.SECONDS,
+ )
+ }
+ }
+
+ private var balloonPercent = 0
+ private var ongoingInflation: ScheduledFuture<*>? = null
+
+ fun start() {
+ // addObserver is @MainThread
+ runOnMainThread({ ProcessLifecycleOwner.get().lifecycle.addObserver(observer) })
+ }
+
+ fun stop() {
+ // removeObserver is @MainThread
+ runOnMainThread({
+ ProcessLifecycleOwner.get().lifecycle.removeObserver(observer)
+ executor.shutdown()
+ })
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt
index ed340d2..7c3eb69 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt
@@ -115,10 +115,12 @@
activeTerminalView!!.hasFocus() &&
!(activity.resources.configuration.keyboard == Configuration.KEYBOARD_QWERTY)
- // If terminal's height is less than 30% of the screen height, we need to show modifier keys in
- // a single line to save the vertical space
- private fun needsKeysInSingleLine(): Boolean =
- activeTerminalView!!.height.div(activity.window.decorView.height.toFloat()) < 0.3f
+ // If terminal's height including height of modifier keys is less than 40% of the screen
+ // height, we need to show modifier keys in a single line to save the vertical space
+ private fun needsKeysInSingleLine(): Boolean {
+ val keys = if (keysInSingleLine) keysSingleLine else keysDoubleLine
+ return activeTerminalView!!.height + keys.height < 0.4f * activity.window.decorView.height
+ }
companion object {
private val BTN_KEY_CODE_MAP =
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt
index 5c01ead..7e78235 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalTabFragment.kt
@@ -19,7 +19,6 @@
import android.graphics.Bitmap
import android.net.http.SslError
import android.os.Bundle
-import android.os.Trace
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@@ -145,7 +144,6 @@
object : WebView.VisualStateCallback() {
override fun onComplete(completedRequestId: Long) {
if (completedRequestId == requestId) {
- Trace.endAsyncSection("executeTerminal", 0)
bootProgressView.visibility = View.GONE
terminalView.visibility = View.VISIBLE
terminalView.mapTouchToMouseEvent()
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 6301da4..1857175 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -31,7 +31,7 @@
import android.os.Parcel
import android.os.Parcelable
import android.os.ResultReceiver
-import android.os.Trace
+import android.os.SystemProperties
import android.system.virtualmachine.VirtualMachine
import android.system.virtualmachine.VirtualMachineCustomImageConfig
import android.system.virtualmachine.VirtualMachineCustomImageConfig.AudioConfig
@@ -58,12 +58,15 @@
import java.net.InetSocketAddress
import java.net.SocketAddress
import java.nio.file.Files
+import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
class VmLauncherService : Service() {
+ private lateinit var executorService: ExecutorService
+
// TODO: using lateinit for some fields to avoid null
- private var executorService: ExecutorService? = null
private var virtualMachine: VirtualMachine? = null
private var resultReceiver: ResultReceiver? = null
private var server: Server? = null
@@ -73,6 +76,8 @@
interface VmLauncherServiceCallback {
fun onVmStart()
+ fun onTerminalAvailable(info: TerminalInfo)
+
fun onVmStop()
fun onVmError()
@@ -82,8 +87,13 @@
return null
}
+ override fun onCreate() {
+ super.onCreate()
+ executorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
+ }
+
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- if (intent.action == ACTION_STOP_VM_LAUNCHER_SERVICE) {
+ if (intent.action == ACTION_SHUTDOWN_VM) {
if (debianService != null && debianService!!.shutdownDebian()) {
// During shutdown, change the notification content to indicate that it's closing
val notification = createNotificationForTerminalClose()
@@ -99,7 +109,6 @@
Log.d(TAG, "VM instance is already started")
return START_NOT_STICKY
}
- executorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
val image = InstalledImage.getDefault(this)
val json = ConfigJson.from(this, image.configPath)
@@ -108,25 +117,19 @@
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())
}
val config = configBuilder.build()
- Trace.beginSection("vmCreate")
val runner: Runner =
try {
create(this, config)
} catch (e: VirtualMachineException) {
throw RuntimeException("cannot create runner", e)
}
- Trace.endSection()
- Trace.beginAsyncSection("debianBoot", 0)
virtualMachine = runner.vm
resultReceiver =
@@ -135,12 +138,16 @@
ResultReceiver::class.java,
)
+ val mbc = MemBalloonController(this, virtualMachine!!)
+ mbc.start()
+
runner.exitStatus.thenAcceptAsync { success: Boolean ->
+ mbc.stop()
resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
stopSelf()
}
- val logPath = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
- Logger.setup(virtualMachine!!, logPath, executorService!!)
+ val logDir = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
+ Logger.setup(virtualMachine!!, logDir, executorService)
val notification =
intent.getParcelableExtra<Notification?>(EXTRA_NOTIFICATION, Notification::class.java)
@@ -151,41 +158,73 @@
portNotifier = PortNotifier(this)
- // TODO: dedup this part
+ getTerminalServiceInfo()
+ .thenAcceptAsync(
+ { info ->
+ val ipAddress = info.hostAddresses[0].hostAddress
+ val port = info.port
+ val bundle = Bundle()
+ bundle.putString(KEY_TERMINAL_IPADDRESS, ipAddress)
+ bundle.putInt(KEY_TERMINAL_PORT, port)
+ resultReceiver!!.send(RESULT_TERMINAL_AVAIL, bundle)
+ startDebianServer(ipAddress)
+ },
+ executorService,
+ )
+ .exceptionallyAsync(
+ { e ->
+ Log.e(TAG, "Failed to start VM", e)
+ resultReceiver!!.send(RESULT_ERROR, null)
+ stopSelf()
+ null
+ },
+ executorService,
+ )
+
+ return START_NOT_STICKY
+ }
+
+ private fun getTerminalServiceInfo(): CompletableFuture<NsdServiceInfo> {
+ val executor = Executors.newSingleThreadExecutor(TerminalThreadFactory(applicationContext))
val nsdManager = getSystemService<NsdManager?>(NsdManager::class.java)
- val info = NsdServiceInfo()
- info.serviceType = "_http._tcp"
- info.serviceName = "ttyd"
+ val queryInfo = NsdServiceInfo()
+ queryInfo.serviceType = "_http._tcp"
+ queryInfo.serviceName = "ttyd"
+ var resolvedInfo = CompletableFuture<NsdServiceInfo>()
+
nsdManager.registerServiceInfoCallback(
- info,
- executorService!!,
+ queryInfo,
+ executor,
object : NsdManager.ServiceInfoCallback {
- var started: Boolean = false
+ var found: Boolean = false
override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
- override fun onServiceInfoCallbackUnregistered() {}
+ override fun onServiceInfoCallbackUnregistered() {
+ executor.shutdown()
+ }
override fun onServiceLost() {}
override fun onServiceUpdated(info: NsdServiceInfo) {
Log.i(TAG, "Service found: $info")
- if (!started) {
- started = true
+ if (!found) {
+ found = true
nsdManager.unregisterServiceInfoCallback(this)
- startDebianServer(info.hostAddresses[0].hostAddress)
+ resolvedInfo.complete(info)
}
}
},
)
- return START_NOT_STICKY
+ resolvedInfo.orTimeout(VM_BOOT_TIMEOUT_SECONDS.toLong(), TimeUnit.SECONDS)
+ return resolvedInfo
}
private fun createNotificationForTerminalClose(): Notification {
val stopIntent = Intent()
stopIntent.setClass(this, VmLauncherService::class.java)
- stopIntent.setAction(ACTION_STOP_VM_LAUNCHER_SERVICE)
+ stopIntent.setAction(ACTION_SHUTDOWN_VM)
val stopPendingIntent =
PendingIntent.getService(
this,
@@ -227,6 +266,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
@@ -293,7 +347,7 @@
return
}
- executorService!!.execute(
+ executorService.execute(
Runnable {
// TODO(b/373533555): we can use mDNS for that.
val debianServicePortFile = File(filesDir, "debian_service_port")
@@ -321,10 +375,9 @@
Log.e(TAG, "failed to stop a VM instance", e)
}
}
- executorService?.shutdownNow()
- executorService = null
virtualMachine = null
}
+ executorService.shutdownNow()
super.onDestroy()
}
@@ -338,12 +391,28 @@
private const val ACTION_START_VM_LAUNCHER_SERVICE =
"android.virtualization.START_VM_LAUNCHER_SERVICE"
const val EXTRA_DISPLAY_INFO = "EXTRA_DISPLAY_INFO"
- const val ACTION_STOP_VM_LAUNCHER_SERVICE: String =
- "android.virtualization.STOP_VM_LAUNCHER_SERVICE"
+ const val ACTION_SHUTDOWN_VM: String = "android.virtualization.ACTION_SHUTDOWN_VM"
private const val RESULT_START = 0
private const val RESULT_STOP = 1
private const val RESULT_ERROR = 2
+ private const val RESULT_TERMINAL_AVAIL = 3
+
+ private const val KEY_TERMINAL_IPADDRESS = "address"
+ private const val KEY_TERMINAL_PORT = "port"
+
+ private val VM_BOOT_TIMEOUT_SECONDS: Int =
+ {
+ val deviceName = SystemProperties.get("ro.product.vendor.device", "")
+ val cuttlefish = deviceName.startsWith("vsoc_")
+ val goldfish = deviceName.startsWith("emu64")
+
+ if (cuttlefish || goldfish) {
+ 3 * 60
+ } else {
+ 30
+ }
+ }()
private fun getMyIntent(context: Context): Intent {
return Intent(context.getApplicationContext(), VmLauncherService::class.java)
@@ -364,6 +433,11 @@
}
when (resultCode) {
RESULT_START -> callback.onVmStart()
+ RESULT_TERMINAL_AVAIL -> {
+ val ipAddress = resultData!!.getString(KEY_TERMINAL_IPADDRESS)
+ val port = resultData!!.getInt(KEY_TERMINAL_PORT)
+ callback.onTerminalAvailable(TerminalInfo(ipAddress!!, port))
+ }
RESULT_STOP -> callback.onVmStop()
RESULT_ERROR -> callback.onVmError()
}
@@ -384,12 +458,14 @@
fun stop(context: Context) {
val i = getMyIntent(context)
- i.setAction(ACTION_STOP_VM_LAUNCHER_SERVICE)
+ i.setAction(ACTION_SHUTDOWN_VM)
context.startService(i)
}
}
}
+data class TerminalInfo(val ipAddress: String, val port: Int)
+
data class DisplayInfo(val width: Int, val height: Int, val dpi: Int, val refreshRate: Int) :
Parcelable {
constructor(
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-gl/strings.xml b/android/TerminalApp/res/values-gl/strings.xml
index ad1cda8..504e687 100644
--- a/android/TerminalApp/res/values-gl/strings.xml
+++ b/android/TerminalApp/res/values-gl/strings.xml
@@ -90,5 +90,5 @@
<string name="virgl_enabled" msgid="5242525588039698086">"Activouse <xliff:g id="ID_1">VirGL</xliff:g>"</string>
<string name="notification_channel_long_running_name" msgid="7916541360369402952">"Tarefas de longa duración"</string>
<string name="notification_channel_system_events_name" msgid="1004951444029742137">"Eventos do sistema"</string>
- <string name="tab_default_title" msgid="2300417689389397930">"Tabulador"</string>
+ <string name="tab_default_title" msgid="2300417689389397930">"Pestana"</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 e98ab5c..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,
@@ -487,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 {
@@ -710,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)?;
@@ -891,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,
@@ -930,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,
@@ -1402,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")
@@ -1410,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;
@@ -1586,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),
}
}
@@ -1687,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
@@ -2794,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..15a4199 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)
@@ -673,6 +677,10 @@
}
}
+ fn is_vm_running(&self) -> bool {
+ matches!(&*self.vm_state.lock().unwrap(), VmState::Running { .. })
+ }
+
/// Returns the last reported state of the VM payload.
pub fn payload_state(&self) -> PayloadState {
*self.payload_state.lock().unwrap()
@@ -722,6 +730,12 @@
/// Returns current virtio-balloon size.
pub fn get_memory_balloon(&self) -> Result<u64, Error> {
+ if !self.is_vm_running() {
+ bail!("get_memory_balloon when VM is not running");
+ }
+ 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 +755,12 @@
/// 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.is_vm_running() {
+ bail!("set_memory_balloon when VM is not running");
+ }
+ 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 +1058,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/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 8385fb4..1033164 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -87,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)?;
@@ -100,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 {
@@ -254,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)
}
diff --git a/android/vm/vm_shell.sh b/android/vm/vm_shell.sh
index 60d9329..cac5781 100755
--- a/android/vm/vm_shell.sh
+++ b/android/vm/vm_shell.sh
@@ -50,15 +50,13 @@
}
function list_cids() {
- local selected_cid=$1
- local available_cids=$(adb shell /apex/com.android.virt/bin/vm list | awk 'BEGIN { FS="[:,]" } /cid/ { print $2; }')
- echo "${available_cids}"
+ adb shell /apex/com.android.virt/bin/vm list | awk 'BEGIN { FS="[:,]" } /cid/ { print $2; }'
}
function handle_connect_cmd() {
selected_cid=$1
- available_cids=$(list_cids)
+ available_cids=($(list_cids))
if [ -z "${available_cids}" ]; then
echo No VM is available
@@ -66,11 +64,11 @@
fi
if [ ! -n "${selected_cid}" ]; then
- if [ ${#selected_cid[@]} -eq 1 ]; then
+ if [ ${#available_cids[@]} -eq 1 ]; then
selected_cid=${available_cids[0]}
else
PS3="Select CID of VM to adb-shell into: "
- select cid in ${available_cids}
+ select cid in ${available_cids[@]}
do
selected_cid=${cid}
break
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 5323296..8934de0 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -259,11 +259,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.
@@ -332,11 +327,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 5aa3f28..9c4d4b1 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -318,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
@@ -329,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}"
@@ -342,9 +338,6 @@
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
popd > /dev/null
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 463583f..0000000
--- a/build/debian/vm_config.json.x86_64
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "name": "debian",
- "disks": [
- {
- "partitions": [
- {
- "label": "ROOT",
- "path": "$PAYLOAD_DIR/root_part",
- "writable": true,
- "guid": "{root_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"
- }
- ],
- "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/guest/forwarder_guest_launcher/debian/service b/guest/forwarder_guest_launcher/debian/service
index 6824c70..7812d67 100644
--- a/guest/forwarder_guest_launcher/debian/service
+++ b/guest/forwarder_guest_launcher/debian/service
@@ -5,12 +5,14 @@
After=virtiofs_internal.service
[Service]
-ExecStart=/usr/bin/bash -c '/usr/bin/forwarder_guest_launcher --grpc_port $(cat /mnt/internal/debian_service_port)'
+ExecStart=/usr/bin/bash -c '/usr/bin/forwarder_guest_launcher --grpc-port-file /mnt/internal/debian_service_port'
Type=simple
Restart=on-failure
RestartSec=1
User=root
Group=root
+StandardOutput=journal
+StandardError=journal
[Install]
WantedBy=multi-user.target
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
index f4c8ca9..3cb557a 100644
--- a/guest/forwarder_guest_launcher/src/main.rs
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -52,10 +52,9 @@
#[derive(Parser)]
/// Flags for running command
pub struct Args {
- /// grpc port number
+ /// path to a file where grpc port number is written
#[arg(long)]
- #[arg(alias = "grpc_port")]
- grpc_port: String,
+ grpc_port_file: String,
}
async fn process_forwarding_request_queue(
@@ -163,11 +162,23 @@
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
- env_logger::init();
+ env_logger::builder().filter_level(log::LevelFilter::Debug).init();
debug!("Starting forwarder_guest_launcher");
let args = Args::parse();
let gateway_ip_addr = netdev::get_default_gateway()?.ipv4[0];
- let addr = format!("https://{}:{}", gateway_ip_addr.to_string(), args.grpc_port);
+
+ // Wait for `grpc_port_file` becomes available.
+ const GRPC_PORT_MAX_RETRY_COUNT: u32 = 10;
+ for _ in 0..GRPC_PORT_MAX_RETRY_COUNT {
+ if std::path::Path::new(&args.grpc_port_file).exists() {
+ break;
+ }
+ debug!("{} does not exist. Wait 1 second", args.grpc_port_file);
+ tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+ }
+ let grpc_port = std::fs::read_to_string(&args.grpc_port_file)?.trim().to_string();
+
+ let addr = format!("https://{}:{}", gateway_ip_addr.to_string(), grpc_port);
let channel = Endpoint::from_shared(addr)?.connect().await?;
let client = DebianServiceClient::new(channel);
diff --git a/guest/microdroid_manager/src/main.rs b/guest/microdroid_manager/src/main.rs
index d665c87..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");
}
};
@@ -519,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 f031859..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).
@@ -118,15 +123,19 @@
.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,
@@ -283,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>,
@@ -366,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/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index 9afbcc3..30624cd 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -41,7 +41,6 @@
use alloc::boxed::Box;
use bssl_avf::Digester;
use diced_open_dice::{bcc_handover_parse, DiceArtifacts, DiceContext, Hidden, VM_KEY_ALGORITHM};
-use hypervisor_backends::get_mem_sharer;
use libfdt::Fdt;
use log::{debug, error, info, trace, warn};
use pvmfw_avb::verify_payload;
@@ -99,15 +98,7 @@
}
let guest_page_size = verified_boot_data.page_size.unwrap_or(SIZE_4KB);
- // TODO(ptosi): Cache the (single?) granule once, in vmbase.
- let hyp_page_size = if let Some(mem_sharer) = get_mem_sharer() {
- Some(mem_sharer.granule().map_err(|e| {
- error!("Failed to get granule size: {e}");
- RebootReason::InternalError
- })?)
- } else {
- None
- };
+ let hyp_page_size = hypervisor_backends::get_granule_size();
let _ =
sanitize_device_tree(untrusted_fdt, vm_dtbo, vm_ref_dt, guest_page_size, hyp_page_size)?;
let fdt = untrusted_fdt; // DT has now been sanitized.
diff --git a/guest/shutdown_runner/Cargo.toml b/guest/shutdown_runner/Cargo.toml
index 0b44baa..92f8762 100644
--- a/guest/shutdown_runner/Cargo.toml
+++ b/guest/shutdown_runner/Cargo.toml
@@ -7,6 +7,7 @@
[dependencies]
anyhow = "1.0.94"
clap = { version = "4.5.20", features = ["derive"] }
+env_logger = "0.11.5"
log = "0.4.22"
netdev = "0.31.0"
prost = "0.13.3"
diff --git a/guest/shutdown_runner/debian/service b/guest/shutdown_runner/debian/service
index 7188d36..a5249d0 100644
--- a/guest/shutdown_runner/debian/service
+++ b/guest/shutdown_runner/debian/service
@@ -4,12 +4,14 @@
After=virtiofs_internal.service
[Service]
-ExecStart=/usr/bin/bash -c '/usr/bin/shutdown_runner --grpc_port $(cat /mnt/internal/debian_service_port)'
+ExecStart=/usr/bin/bash -c '/usr/bin/shutdown_runner --grpc-port-file /mnt/internal/debian_service_port'
Type=simple
Restart=on-failure
RestartSec=1
User=root
Group=root
+StandardOutput=journal
+StandardError=journal
[Install]
WantedBy=multi-user.target
diff --git a/guest/shutdown_runner/src/main.rs b/guest/shutdown_runner/src/main.rs
index 19e9883..4043002 100644
--- a/guest/shutdown_runner/src/main.rs
+++ b/guest/shutdown_runner/src/main.rs
@@ -1,3 +1,17 @@
+// Copyright 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
use api::debian_service_client::DebianServiceClient;
use api::ShutdownQueueOpeningRequest;
use std::process::Command;
@@ -12,18 +26,28 @@
#[derive(Parser)]
/// Flags for running command
pub struct Args {
- /// grpc port number
+ /// Path to a file where grpc port number is written
#[arg(long)]
- #[arg(alias = "grpc_port")]
- grpc_port: String,
+ grpc_port_file: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ env_logger::builder().filter_level(log::LevelFilter::Debug).init();
let args = Args::parse();
let gateway_ip_addr = netdev::get_default_gateway()?.ipv4[0];
- let server_addr = format!("http://{}:{}", gateway_ip_addr.to_string(), args.grpc_port);
+ // Wait for `grpc_port_file` becomes available.
+ const GRPC_PORT_MAX_RETRY_COUNT: u32 = 10;
+ for _ in 0..GRPC_PORT_MAX_RETRY_COUNT {
+ if std::path::Path::new(&args.grpc_port_file).exists() {
+ break;
+ }
+ debug!("{} does not exist. Wait 1 second", args.grpc_port_file);
+ tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+ }
+ let grpc_port = std::fs::read_to_string(&args.grpc_port_file)?.trim().to_string();
+ let server_addr = format!("http://{}:{}", gateway_ip_addr.to_string(), grpc_port);
debug!("connect to grpc server {}", server_addr);
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..6fa0c32 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)
@@ -34,6 +29,7 @@
],
visibility: [
"//packages/modules/Virtualization/guest/trusty/test_vm/vm",
+ "//packages/modules/Virtualization/guest/trusty/test_vm_os/vm",
"//vendor:__subpackages__",
],
}
@@ -115,7 +111,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..676e231 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",
@@ -40,9 +41,6 @@
arm64: {
enabled: true,
},
- x86_64: {
- enabled: true,
- },
},
src: "trusty-vm-launcher.sh",
filename: "trusty-vm-launcher.sh",
@@ -55,16 +53,15 @@
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 +78,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/guest/trusty/test_vm_os/Android.bp b/guest/trusty/test_vm_os/Android.bp
new file mode 100644
index 0000000..ab0d5d8
--- /dev/null
+++ b/guest/trusty/test_vm_os/Android.bp
@@ -0,0 +1,63 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+ default_team: "trendy_team_trusty",
+}
+
+prebuilt_etc {
+ name: "test_vm_os.trusty_test_vm_config",
+ enabled: false,
+ installable: false,
+ arch: {
+ arm64: {
+ src: "trusty-test_vm-config-arm64.json",
+ enabled: true,
+ },
+ x86_64: {
+ src: "trusty-test_vm-config-x86_64.json",
+ enabled: true,
+ },
+ },
+ filename: "trusty-test_vm-config.json",
+}
+
+sh_test {
+ name: "TrustyVmUnitTests",
+ src: "trusty-ut-ctrl.sh",
+ enabled: false,
+ arch: {
+ arm64: {
+ enabled: true,
+ },
+ x86_64: {
+ enabled: true,
+ },
+ },
+ filename_from_src: true,
+ data: [
+ ":trusty_test_vm_os_elf",
+ ":test_vm_os.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_os/AndroidTest.xml b/guest/trusty/test_vm_os/AndroidTest.xml
new file mode 100644
index 0000000..be5c467
--- /dev/null
+++ b/guest/trusty/test_vm_os/AndroidTest.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+ <configuration description="Runs {MODULE}">
+ <!-- object type="module_controller" class="com.android.tradefed.testtype.suite.module.CommandSuccessModuleController" -->
+ <!--Skip the test when trusty VM is not enabled. -->
+ <!--option name="run-command" value="getprop trusty.test_vm.nonsecure_vm_ready | grep 1" /-->
+ <!--/object-->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <!-- 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_os/trusty-ut-ctrl" />
+ <option name="push-file" key="trusty-ut-ctrl.sh" value="/data/local/tmp/trusty_test_vm_os/trusty-ut-ctrl.sh" />
+ <option name="push-file" key="trusty-vm-launcher.sh" value="/data/local/tmp/trusty_test_vm_os/trusty-vm-launcher.sh" />
+ <option name="push-file" key="trusty-wait-ready.sh" value="/data/local/tmp/trusty_test_vm_os/trusty-wait-ready.sh" />
+ <option name="push-file" key="trusty-test_vm-config.json" value="/data/local/tmp/trusty_test_vm_os/trusty-test_vm-config.json" />
+ <option name="push-file" key="trusty_test_vm_os.elf" value="/data/local/tmp/trusty_test_vm_os/trusty_test_vm_os.elf" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="throw-if-cmd-fail" value="true" />
+ <!--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_os/trusty-vm-launcher.sh" />
+ <option name="run-command" value="sh /data/local/tmp/trusty_test_vm_os/trusty-wait-ready.sh" />
+ <option name="run-command" value="start storageproxyd_test_vm_os" />
+ <option name="teardown-command" value="stop storageproxyd_test_vm_os" />
+ <option name="teardown-command" value="killall storageproxyd_test_vm_os || 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_os/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_os/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_os/trusty-ut-ctrl.sh com.android.kernel.iovectest"/>
+ <!--TODO(b/400064847) enable kernel.timertest when Trusty VM supports more than 2 VCPU"/-->
+ <!--option name="test-command-line" key="com.android.kernel.timertest" value="/data/local/tmp/trusty_test_vm_os/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_os/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_os/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_os/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_os/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_os/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_os/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_os/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_os/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_os/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_os/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_os/trusty-ut-ctrl.sh com.android.kernel.userscstest"/>
+ <option name="test-command-line" key="com.android.manifesttest" value="/data/local/tmp/trusty_test_vm_os/trusty-ut-ctrl.sh com.android.manifesttest"/>
+ <option name="test-command-line" key="com.android.memref.test" value="/data/local/tmp/trusty_test_vm_os/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_os/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_os/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_os/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_os/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_os/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_os/trusty-ut-ctrl.sh com.android.trusty.dlmalloctest"/>
+ <option name="test-command-line" key="com.android.trusty.rust.tipc.test" value="/data/local/tmp/trusty_test_vm_os/trusty-ut-ctrl.sh com.android.trusty.rust.tipc.test"/>
+ <option name="test-command-line" key="com.android.uirq-unittest" value="/data/local/tmp/trusty_test_vm_os/trusty-ut-ctrl.sh com.android.uirq-unittest"/>
+ </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_os/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_os/trusty-ut-ctrl.sh com.android.trusty.binder.test"/>
+ </test>
+ </configuration>
diff --git a/guest/trusty/test_vm_os/README.md b/guest/trusty/test_vm_os/README.md
new file mode 100644
index 0000000..4d65d9f
--- /dev/null
+++ b/guest/trusty/test_vm_os/README.md
@@ -0,0 +1,7 @@
+## test_vm_os
+
+The Trusty test_vm_os is meant to test the Trusty OS as a VM,
+its payload ought to include the test TAs for different test types:
+- Trusty kernel OS test
+- Trusty/Binder IPC tests
+- Trusty user-space tests for service TAs (DT tree for example)
diff --git a/guest/trusty/test_vm_os/TEST_MAPPING b/guest/trusty/test_vm_os/TEST_MAPPING
new file mode 100644
index 0000000..1506720
--- /dev/null
+++ b/guest/trusty/test_vm_os/TEST_MAPPING
@@ -0,0 +1,9 @@
+{
+ "trusty_test_vm_presubmit": [
+ ],
+ "trusty_test_vm_postsubmit": [
+ {
+ "name": "TrustyVMOS_UnitTests"
+ }
+ ]
+}
diff --git a/guest/trusty/test_vm_os/trusty-test_vm-config-arm64.json b/guest/trusty/test_vm_os/trusty-test_vm-config-arm64.json
new file mode 100644
index 0000000..9d60892
--- /dev/null
+++ b/guest/trusty/test_vm_os/trusty-test_vm-config-arm64.json
@@ -0,0 +1,8 @@
+{
+ "name": "trusty_test_vm",
+ "kernel": "/data/local/tmp/trusty_test_vm_os/trusty_test_vm_os.elf",
+ "platform_version": "1.0",
+ "cpu_topology": "one_cpu",
+ "memory_mib": 112,
+ "protected": true
+}
diff --git a/guest/trusty/test_vm_os/trusty-test_vm-config-x86_64.json b/guest/trusty/test_vm_os/trusty-test_vm-config-x86_64.json
new file mode 100644
index 0000000..5270ac7
--- /dev/null
+++ b/guest/trusty/test_vm_os/trusty-test_vm-config-x86_64.json
@@ -0,0 +1,7 @@
+{
+ "name": "trusty_test_vm",
+ "kernel": "/data/local/tmp/trusty_test_vm_os/trusty_test_vm_os.elf",
+ "platform_version": "1.0",
+ "cpu_topology": "one_cpu",
+ "memory_mib": 112
+}
diff --git a/guest/trusty/test_vm_os/trusty-ut-ctrl.sh b/guest/trusty/test_vm_os/trusty-ut-ctrl.sh
new file mode 100644
index 0000000..860236b
--- /dev/null
+++ b/guest/trusty/test_vm_os/trusty-ut-ctrl.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+/data/local/tmp/trusty_test_vm_os/trusty-ut-ctrl -D VSOCK:${2:-$(getprop trusty.test_vm_os.vm_cid)}:1 $1
diff --git a/guest/trusty/test_vm_os/trusty-vm-launcher.sh b/guest/trusty/test_vm_os/trusty-vm-launcher.sh
new file mode 100755
index 0000000..497b188
--- /dev/null
+++ b/guest/trusty/test_vm_os/trusty-vm-launcher.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Copyright 2024 Google Inc. All rights reserved.
+#
+# 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.
+
+/apex/com.android.virt/bin/vm run /data/local/tmp/trusty_test_vm_os/trusty-test_vm-config.json
diff --git a/guest/trusty/test_vm_os/trusty-wait-ready.sh b/guest/trusty/test_vm_os/trusty-wait-ready.sh
new file mode 100755
index 0000000..0aed284
--- /dev/null
+++ b/guest/trusty/test_vm_os/trusty-wait-ready.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+set -euo pipefail
+
+function get_cid {
+ local max_cid
+ max_cid=$(/apex/com.android.virt/bin/vm list | awk 'BEGIN { FS="[:,]" } /cid/ { print $2; }' | sort -n | tail -1)
+
+ # return the value trimmed from whitespaces
+ echo "${max_cid}" | xargs
+}
+
+function wait_for_cid {
+ TIMES=${1:-20}
+ X=0
+ local init_cid
+ init_cid=$(get_cid)
+ while [ "$TIMES" -eq 0 ] || [ "$TIMES" -gt "$X" ]
+ do
+ local cid
+ cid=$(get_cid)
+ echo "wait_for_cid: retry $(( X++ )) / $TIMES : init_cid=$init_cid cid=$cid";
+ if [ "$cid" -gt "$init_cid" ]
+ then
+ break
+ else
+ sleep 2
+ fi
+ done
+ setprop trusty.test_vm_os.vm_cid "$cid"
+}
+
+# This script is expected to be started before the trusty_test_vm is started
+# wait_for_cid gets the max cid and wait for it to be updated as an indication
+# that the trusty_test_vm has properly started.
+# wait_for_cid polls for the CID change at 2 seconds intervals
+# the input argument is the max number of retries (20 by default)
+wait_for_cid "$@"
+
+echo trusty.test_vm_os.vm_cid="$(getprop trusty.test_vm_os.vm_cid)"
diff --git a/guest/trusty/test_vm_os/vm/Android.bp b/guest/trusty/test_vm_os/vm/Android.bp
new file mode 100644
index 0000000..2e81828
--- /dev/null
+++ b/guest/trusty/test_vm_os/vm/Android.bp
@@ -0,0 +1,114 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+prebuilt_etc {
+ name: "trusty_test_vm_os_elf",
+ system_ext_specific: true,
+ filename: "trusty_test_vm_os.elf",
+ src: select((os(), arch()), {
+ ("android", "arm64"): ":trusty_test_vm_os_signed",
+ ("android", "x86_64"): ":trusty_test_vm_os_unsigned",
+ (default, default): ":empty_file",
+ }),
+}
+
+cc_binary {
+ name: "trusty_test_vm_os_signed",
+ srcs: [
+ ":trusty_test_vm_os_signed_bin_obj",
+ ],
+ // reuse the common trusty_vm_sections linker script
+ linker_scripts: [
+ ":trusty_vm_sections.ld",
+ ],
+ ldflags: [
+ // Prevent the `trusty_test_vm_os_signed_bin_obj` segment from being garbage collected.
+ "-Wl,--no-gc-sections",
+ // Prevent the build ID segments from being added, as it would corrupt the integrity
+ // of the original signed image.
+ "-Wl,--build-id=none",
+ // Use a standard page size of 4096, smaller than the default 16384, to avoid padding
+ // with extra bytes.
+ "-Wl,-z,max-page-size=4096",
+ ],
+ nocrt: true,
+ no_libcrt: true,
+ static_executable: true,
+ system_shared_libs: [],
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+ strip: {
+ none: true,
+ },
+}
+
+cc_genrule {
+ name: "test_vm_os.S",
+ enabled: false,
+ arch: {
+ arm64: {
+ srcs: [":trusty_test_vm_os_signed_bin"],
+ enabled: true,
+ },
+ },
+ out: ["test_vm_os.S"],
+ cmd: "(" +
+ " echo '.section .vm_payload_signed.bin';" +
+ " echo '.globl vm_payload_signed';" +
+ " echo 'vm_payload_signed:';" +
+ " echo '.incbin \"'$(in)'\"';" +
+ ") > $(out)",
+ visibility: ["//visibility:private"],
+}
+
+cc_object {
+ name: "trusty_test_vm_os_signed_bin_obj",
+ srcs: [
+ ":test_vm_os.S",
+ ],
+ crt: false,
+ static_libs: ["trusty_test_vm_os_signed_bin"],
+ system_shared_libs: [],
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+ visibility: ["//visibility:private"],
+}
+
+// python -c "import hashlib; print(hashlib.sha256(b'trusty_test_vm_os_salt').hexdigest())"
+trusty_test_vm_os_salt = "74706b35d927b14539a73e14e6e91a2d3be5d46a12c02cf4084bcef5ffee6e4a"
+
+TRUSTY_TEST_VM_OS_VERSION = 1
+
+avb_add_hash_footer {
+ name: "trusty_test_vm_os_signed_bin",
+ filename: "trusty_test_vm_os_signed.bin",
+ partition_name: "boot",
+ private_key: ":trusty_vm_sign_key",
+ salt: trusty_test_vm_os_salt,
+ rollback_index: TRUSTY_TEST_VM_OS_VERSION,
+ props: [
+ {
+ name: "com.android.virt.cap",
+ value: "trusty_security_vm",
+ },
+ ],
+ src: ":trusty_test_vm_os_unsigned",
+ enabled: false,
+ arch: {
+ arm64: {
+ enabled: true,
+ },
+ x86_64: {
+ enabled: true,
+ },
+ },
+}
diff --git a/libs/dice/TEST_MAPPING b/libs/dice/TEST_MAPPING
index a43d7a2..d2d89e4 100644
--- a/libs/dice/TEST_MAPPING
+++ b/libs/dice/TEST_MAPPING
@@ -12,6 +12,9 @@
"name": "libdiced_open_dice.integration_test"
},
{
+ "name": "libdiced_open_dice_multialg.integration_test"
+ },
+ {
"name": "libdiced_open_dice_nostd.integration_test"
},
{
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index 986f496..739f245 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -63,6 +63,33 @@
],
}
+rust_library {
+ name: "libdiced_open_dice_multialg",
+ defaults: ["libdiced_open_dice_defaults"],
+ host_supported: true,
+ vendor_available: true,
+ rustlibs: [
+ "libcoset",
+ "libopen_dice_android_bindgen_multialg",
+ "libopen_dice_cbor_bindgen_multialg",
+ "libzeroize",
+ ],
+ features: [
+ "std",
+ "multialg",
+ ],
+ shared_libs: [
+ "libcrypto",
+ ],
+ visibility: [
+ "//system/software_defined_vehicle:__subpackages__",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
+}
+
rust_defaults {
name: "libdiced_open_dice_test_defaults",
crate_name: "diced_open_dice_test",
@@ -80,6 +107,18 @@
}
rust_test {
+ name: "libdiced_open_dice_multialg.integration_test",
+ defaults: ["libdiced_open_dice_test_defaults"],
+ rustlibs: [
+ "libdiced_open_dice_multialg",
+ "libcoset",
+ ],
+ features: [
+ "multialg",
+ ],
+}
+
+rust_test {
name: "libdiced_open_dice_nostd.integration_test",
defaults: ["libdiced_open_dice_test_defaults"],
rustlibs: [
@@ -174,6 +213,20 @@
}
rust_bindgen {
+ name: "libopen_dice_cbor_bindgen_multialg",
+ defaults: [
+ "libopen_dice.rust_defaults",
+ "libopen_dice_cbor_bindgen.rust_defaults",
+ ],
+ bindgen_flags: [
+ "--rustified-enum DiceKeyAlgorithm",
+ "--allowlist-type=DiceContext",
+ ],
+ whole_static_libs: ["libopen_dice_cbor_multialg"],
+ shared_libs: ["libcrypto"],
+}
+
+rust_bindgen {
name: "libopen_dice_cbor_bindgen_nostd",
defaults: [
"libopen_dice_cbor_bindgen.rust_defaults",
@@ -231,6 +284,18 @@
}
rust_bindgen {
+ name: "libopen_dice_android_bindgen_multialg",
+ defaults: [
+ "libopen_dice.rust_defaults",
+ "libopen_dice_android_bindgen.rust_defaults",
+ ],
+ rustlibs: [
+ "libopen_dice_cbor_bindgen_multialg",
+ ],
+ whole_static_libs: ["libopen_dice_android_multialg"],
+}
+
+rust_bindgen {
name: "libopen_dice_android_bindgen_nostd",
defaults: [
"libopen_dice_android_bindgen.rust_defaults",
diff --git a/libs/dice/open_dice/src/lib.rs b/libs/dice/open_dice/src/lib.rs
index 33fb65c..9268b03 100644
--- a/libs/dice/open_dice/src/lib.rs
+++ b/libs/dice/open_dice/src/lib.rs
@@ -43,11 +43,19 @@
};
pub use error::{DiceError, Result};
pub use ops::{
- derive_cdi_leaf_priv, generate_certificate, hash, kdf, keypair_from_seed, sign,
- sign_cose_sign1, sign_cose_sign1_with_cdi_leaf_priv, verify,
+ derive_cdi_leaf_priv, generate_certificate, hash, kdf, keypair_from_seed, sign, verify,
+};
+#[cfg(feature = "multialg")]
+pub use ops::{
+ derive_cdi_leaf_priv_multialg, keypair_from_seed_multialg, sign_cose_sign1_multialg,
+ sign_cose_sign1_with_cdi_leaf_priv_multialg, verify_multialg,
};
pub use retry::{
retry_bcc_format_config_descriptor, retry_bcc_main_flow, retry_dice_main_flow,
retry_generate_certificate, retry_sign_cose_sign1, retry_sign_cose_sign1_with_cdi_leaf_priv,
OwnedDiceArtifacts,
};
+#[cfg(feature = "multialg")]
+pub use retry::{
+ retry_sign_cose_sign1_multialg, retry_sign_cose_sign1_with_cdi_leaf_priv_multialg,
+};
diff --git a/libs/dice/open_dice/src/ops.rs b/libs/dice/open_dice/src/ops.rs
index 2014118..b22b113 100644
--- a/libs/dice/open_dice/src/ops.rs
+++ b/libs/dice/open_dice/src/ops.rs
@@ -21,11 +21,17 @@
PRIVATE_KEY_SEED_SIZE, PRIVATE_KEY_SIZE, VM_KEY_ALGORITHM,
};
use crate::error::{check_result, DiceError, Result};
+#[cfg(feature = "multialg")]
+use crate::KeyAlgorithm;
use alloc::{vec, vec::Vec};
+#[cfg(feature = "multialg")]
+use open_dice_cbor_bindgen::DiceContext_;
use open_dice_cbor_bindgen::{
DiceCoseSignAndEncodeSign1, DiceGenerateCertificate, DiceHash, DiceKdf, DiceKeypairFromSeed,
DicePrincipal, DiceSign, DiceVerify,
};
+#[cfg(feature = "multialg")]
+use std::ffi::c_void;
use std::ptr;
/// Hashes the provided input using DICE's hash function `DiceHash`.
@@ -100,6 +106,44 @@
Ok((public_key, private_key))
}
+/// Deterministically generates a public and private key pair from `seed` and `key_algorithm`.
+/// Since this is deterministic, `seed` is as sensitive as a private key and can
+/// be used directly as the private key.
+#[cfg(feature = "multialg")]
+pub fn keypair_from_seed_multialg(
+ seed: &[u8; PRIVATE_KEY_SEED_SIZE],
+ key_algorithm: KeyAlgorithm,
+) -> Result<(Vec<u8>, PrivateKey)> {
+ let mut public_key = vec![0u8; key_algorithm.public_key_size()];
+ let mut private_key = PrivateKey::default();
+ // This function is used with an open-dice config that uses the same algorithms for the
+ // subject and authority. Therefore, the principal is irrelevant in this context as this
+ // function only derives the key pair cryptographically without caring about which
+ // principal it is for. Hence, we arbitrarily set it to `DicePrincipal::kDicePrincipalSubject`.
+ let principal = DicePrincipal::kDicePrincipalSubject;
+ let context = DiceContext_ {
+ authority_algorithm: key_algorithm.into(),
+ subject_algorithm: key_algorithm.into(),
+ };
+ check_result(
+ // SAFETY: The function writes to the `public_key` and `private_key` within the given
+ // bounds, and only reads the `seed`.
+ // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
+ // open-dice.
+ unsafe {
+ DiceKeypairFromSeed(
+ &context as *const DiceContext_ as *mut c_void,
+ principal,
+ seed.as_ptr(),
+ public_key.as_mut_ptr(),
+ private_key.as_mut_ptr(),
+ )
+ },
+ public_key.len(),
+ )?;
+ Ok((public_key, private_key))
+}
+
/// Derives the CDI_Leaf_Priv from the provided `dice_artifacts`.
///
/// The corresponding public key is included in the leaf certificate of the DICE chain
@@ -114,6 +158,17 @@
Ok(private_key)
}
+/// Multialg variant of `derive_cdi_leaf_priv`.
+#[cfg(feature = "multialg")]
+pub fn derive_cdi_leaf_priv_multialg(
+ dice_artifacts: &dyn DiceArtifacts,
+ key_algorithm: KeyAlgorithm,
+) -> Result<PrivateKey> {
+ let cdi_priv_key_seed = derive_cdi_private_key_seed(dice_artifacts.cdi_attest())?;
+ let (_, private_key) = keypair_from_seed_multialg(cdi_priv_key_seed.as_array(), key_algorithm)?;
+ Ok(private_key)
+}
+
/// Signs the `message` with the given `private_key` using `DiceSign`.
pub fn sign(message: &[u8], private_key: &[u8; PRIVATE_KEY_SIZE]) -> Result<Vec<u8>> {
let mut signature = vec![0u8; VM_KEY_ALGORITHM.signature_size()];
@@ -173,6 +228,45 @@
Ok(encoded_signature_actual_size)
}
+/// Multialg variant of `sign_cose_sign1`.
+#[cfg(feature = "multialg")]
+pub fn sign_cose_sign1_multialg(
+ message: &[u8],
+ aad: &[u8],
+ private_key: &[u8; PRIVATE_KEY_SIZE],
+ encoded_signature: &mut [u8],
+ key_algorithm: KeyAlgorithm,
+) -> Result<usize> {
+ let mut encoded_signature_actual_size = 0;
+ let context = DiceContext_ {
+ authority_algorithm: key_algorithm.into(),
+ subject_algorithm: key_algorithm.into(),
+ };
+ check_result(
+ // SAFETY: The function writes to `encoded_signature` and `encoded_signature_actual_size`
+ // within the given bounds. It only reads `message`, `aad`, and `private_key` within their
+ // given bounds.
+ //
+ // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
+ // open-dice.
+ unsafe {
+ DiceCoseSignAndEncodeSign1(
+ &context as *const DiceContext_ as *mut c_void,
+ message.as_ptr(),
+ message.len(),
+ aad.as_ptr(),
+ aad.len(),
+ private_key.as_ptr(),
+ encoded_signature.len(),
+ encoded_signature.as_mut_ptr(),
+ &mut encoded_signature_actual_size,
+ )
+ },
+ encoded_signature_actual_size,
+ )?;
+ Ok(encoded_signature_actual_size)
+}
+
/// Signs the `message` with a private key derived from the given `dice_artifacts`
/// CDI Attest. On success, places a `CoseSign1` encoded object in `encoded_signature`.
/// Uses `DiceCoseSignAndEncodeSign1`.
@@ -188,6 +282,19 @@
sign_cose_sign1(message, aad, private_key.as_array(), encoded_signature)
}
+/// Multialg variant of `sign_cose_sign1_with_cdi_leaf_priv`.
+#[cfg(feature = "multialg")]
+pub fn sign_cose_sign1_with_cdi_leaf_priv_multialg(
+ message: &[u8],
+ aad: &[u8],
+ dice_artifacts: &dyn DiceArtifacts,
+ encoded_signature: &mut [u8],
+ key_algorithm: KeyAlgorithm,
+) -> Result<usize> {
+ let private_key = derive_cdi_leaf_priv_multialg(dice_artifacts, key_algorithm)?;
+ sign_cose_sign1_multialg(message, aad, private_key.as_array(), encoded_signature, key_algorithm)
+}
+
/// Verifies the `signature` of the `message` with the given `public_key` using `DiceVerify`.
pub fn verify(message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<()> {
if signature.len() != VM_KEY_ALGORITHM.signature_size()
@@ -212,6 +319,40 @@
)
}
+/// Multialg variant of `verify`.
+#[cfg(feature = "multialg")]
+pub fn verify_multialg(
+ message: &[u8],
+ signature: &[u8],
+ public_key: &[u8],
+ key_algorithm: KeyAlgorithm,
+) -> Result<()> {
+ if signature.len() != key_algorithm.signature_size()
+ || public_key.len() != key_algorithm.public_key_size()
+ {
+ return Err(DiceError::InvalidInput);
+ }
+ let context = DiceContext_ {
+ authority_algorithm: key_algorithm.into(),
+ subject_algorithm: key_algorithm.into(),
+ };
+ check_result(
+ // SAFETY: only reads the messages, signature and public key as constant values.
+ // The first argument is a pointer to a valid |DiceContext_| object for multi-alg
+ // open-dice.
+ unsafe {
+ DiceVerify(
+ &context as *const DiceContext_ as *mut c_void,
+ message.as_ptr(),
+ message.len(),
+ signature.as_ptr(),
+ public_key.as_ptr(),
+ )
+ },
+ 0,
+ )
+}
+
/// Generates an X.509 certificate from the given `subject_private_key_seed` and
/// `input_values`, and signed by `authority_private_key_seed`.
/// The subject private key seed is supplied here so the implementation can choose
diff --git a/libs/dice/open_dice/src/retry.rs b/libs/dice/open_dice/src/retry.rs
index cf36bc0..d793218 100644
--- a/libs/dice/open_dice/src/retry.rs
+++ b/libs/dice/open_dice/src/retry.rs
@@ -24,6 +24,11 @@
};
use crate::error::{DiceError, Result};
use crate::ops::{generate_certificate, sign_cose_sign1, sign_cose_sign1_with_cdi_leaf_priv};
+#[cfg(feature = "multialg")]
+use crate::{
+ ops::{sign_cose_sign1_multialg, sign_cose_sign1_with_cdi_leaf_priv_multialg},
+ KeyAlgorithm,
+};
use alloc::vec::Vec;
#[cfg(feature = "serde_derive")]
use serde_derive::{Deserialize, Serialize};
@@ -158,6 +163,19 @@
})
}
+/// Multialg variant of `retry_sign_cose_sign1`.
+#[cfg(feature = "multialg")]
+pub fn retry_sign_cose_sign1_multialg(
+ message: &[u8],
+ aad: &[u8],
+ private_key: &[u8; PRIVATE_KEY_SIZE],
+ key_algorithm: KeyAlgorithm,
+) -> Result<Vec<u8>> {
+ retry_with_measured_buffer(|encoded_signature| {
+ sign_cose_sign1_multialg(message, aad, private_key, encoded_signature, key_algorithm)
+ })
+}
+
/// Signs a message with the given the private key derived from the
/// CDI Attest of the given `dice_artifacts` and returns the signature
/// as an encoded CoseSign1 object.
@@ -170,3 +188,22 @@
sign_cose_sign1_with_cdi_leaf_priv(message, aad, dice_artifacts, encoded_signature)
})
}
+
+/// Multialg variant of `retry_sign_cose_sign1_with_cdi_leaf_priv`.
+#[cfg(feature = "multialg")]
+pub fn retry_sign_cose_sign1_with_cdi_leaf_priv_multialg(
+ message: &[u8],
+ aad: &[u8],
+ dice_artifacts: &dyn DiceArtifacts,
+ key_algorithm: KeyAlgorithm,
+) -> Result<Vec<u8>> {
+ retry_with_measured_buffer(|encoded_signature| {
+ sign_cose_sign1_with_cdi_leaf_priv_multialg(
+ message,
+ aad,
+ dice_artifacts,
+ encoded_signature,
+ key_algorithm,
+ )
+ })
+}
diff --git a/libs/dice/open_dice/tests/api_test.rs b/libs/dice/open_dice/tests/api_test.rs
index b0c2ca7..0f8af10 100644
--- a/libs/dice/open_dice/tests/api_test.rs
+++ b/libs/dice/open_dice/tests/api_test.rs
@@ -21,6 +21,11 @@
retry_sign_cose_sign1, retry_sign_cose_sign1_with_cdi_leaf_priv, sign, verify,
DiceArtifacts, PrivateKey, CDI_SIZE, HASH_SIZE, ID_SIZE, PRIVATE_KEY_SEED_SIZE,
};
+ #[cfg(feature = "multialg")]
+ use diced_open_dice::{
+ keypair_from_seed_multialg, retry_sign_cose_sign1_multialg,
+ retry_sign_cose_sign1_with_cdi_leaf_priv_multialg, verify_multialg, KeyAlgorithm,
+ };
use coset::{CborSerializable, CoseSign1};
@@ -93,7 +98,21 @@
0xfc, 0x23, 0xc9, 0x21, 0x5c, 0x48, 0x21, 0x47, 0xee, 0x5b, 0xfa, 0xaf, 0x88, 0x9a, 0x52,
0xf1, 0x61, 0x06, 0x37,
];
-
+ #[cfg(feature = "multialg")]
+ const EXPECTED_EC_P256_PUB_KEY: &[u8] = &[
+ 0xa7, 0x93, 0x70, 0x16, 0xff, 0xe8, 0x3c, 0x23, 0x5f, 0x6b, 0xf9, 0x38, 0x7e, 0x9c, 0xe5,
+ 0x21, 0xb5, 0x8a, 0x9b, 0x68, 0x5a, 0x2f, 0x62, 0xf4, 0x15, 0x94, 0x1c, 0x61, 0xb3, 0xbb,
+ 0xe1, 0x26, 0x61, 0x47, 0x97, 0xbf, 0x3a, 0x1f, 0x6b, 0x87, 0x86, 0x47, 0x5e, 0xc3, 0xa6,
+ 0x8b, 0x95, 0x89, 0x9e, 0x29, 0xd5, 0x55, 0x2a, 0xdd, 0x2a, 0x3f, 0xe5, 0xf0, 0x7a, 0xd6,
+ 0xc4, 0x7b, 0x64, 0xe0,
+ ];
+ #[cfg(feature = "multialg")]
+ const EXPECTED_EC_P256_PRIV_KEY: &[u8] = &[
+ 0x62, 0x32, 0x1b, 0xb, 0x5c, 0xac, 0x8f, 0x20, 0x61, 0xb7, 0xa3, 0xbb, 0x46, 0x2b, 0x4e,
+ 0xb3, 0x3f, 0xa7, 0xf6, 0x9b, 0x2f, 0x5b, 0x80, 0xa8, 0x55, 0x5e, 0x80, 0x26, 0xbb, 0x72,
+ 0xbe, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ ];
const EXPECTED_SIGNATURE: &[u8] = &[
0x44, 0xae, 0xcc, 0xe2, 0xb9, 0x96, 0x18, 0x39, 0x0e, 0x61, 0x0f, 0x53, 0x07, 0xbf, 0xf2,
0x32, 0x3d, 0x44, 0xd4, 0xf2, 0x07, 0x23, 0x30, 0x85, 0x32, 0x18, 0xd2, 0x69, 0xb8, 0x29,
@@ -140,6 +159,41 @@
assert!(verify_result.is_err());
}
+ #[cfg(feature = "multialg")]
+ #[test]
+ fn sign_cose_sign1_verify_multialg() {
+ let (pub_key, priv_key) = get_test_key_pair_ec_p256();
+
+ let signature_res = retry_sign_cose_sign1_multialg(
+ b"MyMessage",
+ b"MyAad",
+ priv_key.as_array(),
+ KeyAlgorithm::EcdsaP256,
+ );
+ assert!(signature_res.is_ok());
+ let signature = signature_res.unwrap();
+ let cose_sign1_res = CoseSign1::from_slice(&signature);
+ assert!(cose_sign1_res.is_ok());
+ let mut cose_sign1 = cose_sign1_res.unwrap();
+
+ let mut verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+ verify_multialg(data, sign, &pub_key, KeyAlgorithm::EcdsaP256)
+ });
+ assert!(verify_result.is_ok());
+
+ verify_result = cose_sign1.verify_signature(b"BadAad", |sign, data| {
+ verify_multialg(data, sign, &pub_key, KeyAlgorithm::EcdsaP256)
+ });
+ assert!(verify_result.is_err());
+
+ // if we modify the signature, the payload should no longer verify
+ cose_sign1.signature.push(0xAA);
+ verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+ verify_multialg(data, sign, &pub_key, KeyAlgorithm::EcdsaP256)
+ });
+ assert!(verify_result.is_err());
+ }
+
struct TestArtifactsForSigning {}
impl DiceArtifacts for TestArtifactsForSigning {
@@ -182,6 +236,41 @@
assert!(verify_result.is_err());
}
+ #[cfg(feature = "multialg")]
+ #[test]
+ fn sign_cose_sign1_with_cdi_leaf_priv_verify_multialg() {
+ let dice = TestArtifactsForSigning {};
+
+ let signature_res = retry_sign_cose_sign1_with_cdi_leaf_priv_multialg(
+ b"MyMessage",
+ b"MyAad",
+ &dice,
+ KeyAlgorithm::EcdsaP256,
+ );
+ assert!(signature_res.is_ok());
+ let signature = signature_res.unwrap();
+ let cose_sign1_res = CoseSign1::from_slice(&signature);
+ assert!(cose_sign1_res.is_ok());
+ let mut cose_sign1 = cose_sign1_res.unwrap();
+
+ let mut verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+ verify_multialg(data, sign, EXPECTED_EC_P256_PUB_KEY, KeyAlgorithm::EcdsaP256)
+ });
+ assert!(verify_result.is_ok());
+
+ verify_result = cose_sign1.verify_signature(b"BadAad", |sign, data| {
+ verify_multialg(data, sign, EXPECTED_EC_P256_PUB_KEY, KeyAlgorithm::EcdsaP256)
+ });
+ assert!(verify_result.is_err());
+
+ // if we modify the signature, the payload should no longer verify
+ cose_sign1.signature.push(0xAA);
+ verify_result = cose_sign1.verify_signature(b"MyAad", |sign, data| {
+ verify_multialg(data, sign, EXPECTED_EC_P256_PUB_KEY, KeyAlgorithm::EcdsaP256)
+ });
+ assert!(verify_result.is_err());
+ }
+
fn get_test_key_pair() -> (Vec<u8>, PrivateKey) {
let seed = hash(b"MySeedString").unwrap();
assert_eq!(seed, EXPECTED_SEED);
@@ -196,4 +285,23 @@
(pub_key, priv_key)
}
+
+ #[cfg(feature = "multialg")]
+ fn get_test_key_pair_ec_p256() -> (Vec<u8>, PrivateKey) {
+ let seed = hash(b"MySeedString").unwrap();
+ assert_eq!(seed, EXPECTED_SEED);
+ let cdi_attest = &seed[..CDI_SIZE];
+ assert_eq!(cdi_attest, EXPECTED_CDI_ATTEST);
+ let cdi_private_key_seed =
+ derive_cdi_private_key_seed(cdi_attest.try_into().unwrap()).unwrap();
+ assert_eq!(cdi_private_key_seed.as_array(), EXPECTED_CDI_PRIVATE_KEY_SEED);
+ let (pub_key, priv_key) =
+ keypair_from_seed_multialg(cdi_private_key_seed.as_array(), KeyAlgorithm::EcdsaP256)
+ .unwrap();
+
+ assert_eq!(&pub_key, EXPECTED_EC_P256_PUB_KEY);
+ assert_eq!(priv_key.as_array(), EXPECTED_EC_P256_PRIV_KEY);
+
+ (pub_key, priv_key)
+ }
}
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java
index 5fcb975..b8b4ace 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());
@@ -1799,7 +1807,7 @@
* {@linkplain #connectToVsockServer binder request}, and wait for {@link
* VirtualMachineCallback#onPayloadFinished} to be called.
*
- * <p>A stopped virtual machine can be re-started by calling {@link #run()}.
+ * <p>A stopped virtual machine cannot be re-started.
*
* <p>NOTE: This method may block and should not be called on the main thread.
*
diff --git a/libs/libhypervisor_backends/src/hypervisor.rs b/libs/libhypervisor_backends/src/hypervisor.rs
index aa65133..7c274f5 100644
--- a/libs/libhypervisor_backends/src/hypervisor.rs
+++ b/libs/libhypervisor_backends/src/hypervisor.rs
@@ -152,3 +152,8 @@
pub fn get_device_assigner() -> Option<&'static dyn DeviceAssigningHypervisor> {
get_hypervisor().as_device_assigner()
}
+
+/// Gets the unique hypervisor granule size, if any.
+pub fn get_granule_size() -> Option<usize> {
+ get_hypervisor().get_granule_size()
+}
diff --git a/libs/libhypervisor_backends/src/hypervisor/common.rs b/libs/libhypervisor_backends/src/hypervisor/common.rs
index bfe638f..f229e14 100644
--- a/libs/libhypervisor_backends/src/hypervisor/common.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/common.rs
@@ -32,6 +32,13 @@
fn as_device_assigner(&self) -> Option<&dyn DeviceAssigningHypervisor> {
None
}
+
+ /// Returns the granule used by all APIs (MEM_SHARE, MMIO_GUARD, device assignment, ...).
+ ///
+ /// If no such API is supported or if they support different granule sizes, returns None.
+ fn get_granule_size(&self) -> Option<usize> {
+ None
+ }
}
pub trait MmioGuardedHypervisor {
diff --git a/libs/libhypervisor_backends/src/hypervisor/geniezone.rs b/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
index 76e010b..0913ff3 100644
--- a/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/geniezone.rs
@@ -84,6 +84,10 @@
fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
Some(self)
}
+
+ fn get_granule_size(&self) -> Option<usize> {
+ <Self as MemSharingHypervisor>::granule(self).ok()
+ }
}
impl MmioGuardedHypervisor for GeniezoneHypervisor {
diff --git a/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs b/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
index 233097b..f183107 100644
--- a/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/kvm_aarch64.rs
@@ -90,6 +90,10 @@
fn as_device_assigner(&self) -> Option<&dyn DeviceAssigningHypervisor> {
Some(self)
}
+
+ fn get_granule_size(&self) -> Option<usize> {
+ <Self as MemSharingHypervisor>::granule(self).ok()
+ }
}
impl MmioGuardedHypervisor for ProtectedKvmHypervisor {
diff --git a/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs b/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
index 7f9ea4d..d72f788 100644
--- a/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
+++ b/libs/libhypervisor_backends/src/hypervisor/kvm_x86.rs
@@ -84,6 +84,10 @@
fn as_mem_sharer(&self) -> Option<&dyn MemSharingHypervisor> {
Some(self)
}
+
+ fn get_granule_size(&self) -> Option<usize> {
+ <Self as MemSharingHypervisor>::granule(self).ok()
+ }
}
macro_rules! vmcall {
diff --git a/libs/libhypervisor_backends/src/lib.rs b/libs/libhypervisor_backends/src/lib.rs
index 33dc5ad..3c81ac8 100644
--- a/libs/libhypervisor_backends/src/lib.rs
+++ b/libs/libhypervisor_backends/src/lib.rs
@@ -24,5 +24,6 @@
pub use error::{Error, Result};
pub use hypervisor::{
- get_device_assigner, get_mem_sharer, get_mmio_guard, DeviceAssigningHypervisor, KvmError,
+ get_device_assigner, get_granule_size, get_mem_sharer, get_mmio_guard,
+ DeviceAssigningHypervisor, KvmError,
};
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 67a4716..8452344 100644
--- a/libs/libvirtualization_jni/android_system_virtualmachine_VirtualMachine.cpp
+++ b/libs/libvirtualization_jni/android_system_virtualmachine_VirtualMachine.cpp
@@ -59,28 +59,29 @@
JNIEnv *mEnv;
jobject mProvider;
jmethodID mMid;
- } state;
+ };
- state.mEnv = env;
- state.mProvider = provider;
- state.mMid = mid;
+ auto state = std::make_unique<State>(env, provider, mid);
using RequestFun = int (*)(void *);
RequestFun requestFunc = [](void *param) -> int {
- State *state = reinterpret_cast<State *>(param);
+ 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, &state);
+ auto client = ARpcSession_setupPreconnectedClient(session.get(), requestFunc, state.release(),
+ paramDeleteFunc);
return AIBinder_toJavaBinder(env, client);
}
diff --git a/tests/backcompat_test/Android.bp b/tests/backcompat_test/Android.bp
index aa1e089..d47487a 100644
--- a/tests/backcompat_test/Android.bp
+++ b/tests/backcompat_test/Android.bp
@@ -14,6 +14,7 @@
"libanyhow",
"liblibc",
"libnix",
+ "librustutils",
"libvmclient",
"liblog_rust",
],
diff --git a/tests/backcompat_test/src/main.rs b/tests/backcompat_test/src/main.rs
index b92049d..9518c38 100644
--- a/tests/backcompat_test/src/main.rs
+++ b/tests/backcompat_test/src/main.rs
@@ -25,6 +25,7 @@
use anyhow::anyhow;
use anyhow::Context;
use anyhow::Error;
+use anyhow::Result;
use log::info;
use std::fs::read_to_string;
use std::fs::File;
@@ -46,11 +47,11 @@
/// Runs a protected VM and validates it against a golden device tree.
#[test]
-fn test_device_tree_protected_compat() -> Result<(), Error> {
+fn test_device_tree_protected_compat() -> Result<()> {
run_test(true, GOLDEN_DEVICE_TREE_PROTECTED)
}
-fn run_test(protected: bool, golden_dt: &str) -> Result<(), Error> {
+fn run_test(protected: bool, golden_dt: &str) -> Result<()> {
let kernel = Some(open_payload(VMBASE_EXAMPLE_KERNEL_PATH)?);
android_logger::init_once(
android_logger::Config::default()
@@ -110,6 +111,7 @@
.truncate(true)
.open("dump_dt.dtb")
.with_context(|| "Failed to open device tree dump file dump_dt.dtb")?;
+ let is_updatable = service.isUpdatableVmSupported()?;
let vm = VmInstance::create(
service.as_ref(),
&config,
@@ -142,7 +144,8 @@
{
return Err(anyhow!("failed to execute dtc"));
}
- let dtcompare_res = Command::new("./dtcompare")
+ let mut dtcompare_cmd = Command::new("./dtcompare");
+ dtcompare_cmd
.arg("--dt1")
.arg("dump_dt_golden.dtb")
.arg("--dt2")
@@ -162,12 +165,23 @@
.arg("/chosen/linux,initrd-start")
.arg("--ignore-path-value")
.arg("/chosen/linux,initrd-end")
- .arg("--ignore-path-value")
- .arg("/avf/secretkeeper_public_key")
.arg("--ignore-path")
- .arg("/avf/name")
- .output()
- .context("failed to execute dtcompare")?;
+ .arg("/avf/name");
+ // Check if Secretkeeper is advertised. If not, check the vendor API level. Secretkeeper is
+ // required as of 202504, and if missing, the test should fail.
+ // Otherwise, ignore the fields, as they are not required.
+ if is_updatable {
+ dtcompare_cmd.arg("--ignore-path-value").arg("/avf/secretkeeper_public_key");
+ } else if vsr_api_level()? >= 202504 {
+ return Err(anyhow!("Secretkeeper support missing on vendor API >= 202504. Secretkeeper needs to be implemented."));
+ } else {
+ dtcompare_cmd
+ .arg("--ignore-path")
+ .arg("/avf/secretkeeper_public_key")
+ .arg("--ignore-path")
+ .arg("/avf/untrusted/defer-rollback-protection");
+ }
+ let dtcompare_res = dtcompare_cmd.output().context("failed to execute dtcompare")?;
if !dtcompare_res.status.success() {
if !Command::new("./dtc_static")
.arg("-I")
@@ -202,7 +216,18 @@
Ok(())
}
-fn open_payload(path: &str) -> Result<ParcelFileDescriptor, Error> {
+fn open_payload(path: &str) -> Result<ParcelFileDescriptor> {
let file = File::open(path).with_context(|| format!("Failed to open VM image {path}"))?;
Ok(ParcelFileDescriptor::new(file))
}
+
+fn vsr_api_level() -> Result<i32> {
+ get_sysprop_i32("ro.vendor.api_level")
+}
+
+fn get_sysprop_i32(prop: &str) -> Result<i32> {
+ let Some(val) = rustutils::system_properties::read(prop)? else {
+ return Ok(-1);
+ };
+ val.parse::<i32>().with_context(|| format!("Failed to read {prop}"))
+}
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 59a57f1..2434ed0 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -101,7 +101,7 @@
private static final String INSTANCE_IMG = TEST_ROOT + "instance.img";
private static final String INSTANCE_ID_FILE = TEST_ROOT + "instance_id";
- private static final String DEBUG_LEVEL_FULL = "full --enable-earlycon";
+ private static final String DEBUG_LEVEL_FULL = "full";
private static final String DEBUG_LEVEL_NONE = "none";
private static final int MIN_MEM_ARM64 = 170;
@@ -555,6 +555,7 @@
throws Exception {
// Preconditions
assumeKernelSupported(os);
+ assumeVmTypeSupported(os, false);
File key = findTestFile("test.com.android.virt.pem");
Map<String, File> keyOverrides = Map.of();
@@ -582,6 +583,7 @@
public void testBootFailsWhenVbMetaDigestDoesNotMatchBootconfig(String os) throws Exception {
// protectedVmWithImageSignedWithDifferentKeyRunsPvmfw() is the protected case.
assumeKernelSupported(os);
+ assumeVmTypeSupported(os, false);
// Sign everything with key1 except vbmeta
File key = findTestFile("test.com.android.virt.pem");
@@ -1155,6 +1157,8 @@
@Test
@CddTest
public void testRunEmptyPayload() throws Exception {
+ assumeVmTypeSupported("microdroid", false);
+
CommandRunner android = new CommandRunner(getDevice());
// Create the idsig file for the APK
@@ -1463,7 +1467,7 @@
}
private void ensureUpdatableVmSupported() throws DeviceNotAvailableException {
- if (PropertyUtil.isVendorApiLevelAtLeast(getAndroidDevice(), 202504)) {
+ if (PropertyUtil.getVsrApiLevel(getAndroidDevice()) >= 202504) {
assertTrue(
"Missing Updatable VM support, have you declared Secretkeeper interface?",
isUpdatableVmSupported());
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 418a88e..9d08ed7 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -2166,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/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