Merge "[refactoring] Move the Trusty kernel building to a new directory" into main
diff --git a/android/TerminalApp/Android.bp b/android/TerminalApp/Android.bp
index 59f18df..545ba0f 100644
--- a/android/TerminalApp/Android.bp
+++ b/android/TerminalApp/Android.bp
@@ -11,12 +11,16 @@
asset_dirs: ["assets"],
resource_dirs: ["res"],
static_libs: [
+ // TODO(b/330257000): will be removed when binder RPC is used
+ "android.system.virtualizationservice_internal-java",
"androidx-constraintlayout_constraintlayout",
"androidx.window_window",
"apache-commons-compress",
"com.google.android.material_material",
"debian-service-grpclib-lite",
"gson",
+ // TODO(b/331708504): will be removed when AVF framework handles surface
+ "libcrosvm_android_display_service-java",
"VmTerminalApp.aidl-java",
"MicrodroidTestHelper", // for DeviceProperties class
],
diff --git a/android/TerminalApp/AndroidManifest.xml b/android/TerminalApp/AndroidManifest.xml
index 726004c..53fdafc 100644
--- a/android/TerminalApp/AndroidManifest.xml
+++ b/android/TerminalApp/AndroidManifest.xml
@@ -35,7 +35,8 @@
android:theme="@style/VmTerminalAppTheme"
android:usesCleartextTraffic="true"
android:supportsRtl="true"
- android:enabled="false">
+ android:enabled="false"
+ android:name=".Application">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden|navigation|uiMode|screenLayout|smallestScreenSize"
android:exported="true">
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
new file mode 100644
index 0000000..efe651e
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Application.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Application as AndroidApplication
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Context
+
+public class Application : AndroidApplication() {
+ override fun onCreate() {
+ super.onCreate()
+ setupNotificationChannels()
+ }
+
+ private fun setupNotificationChannels() {
+ val nm = getSystemService<NotificationManager>(NotificationManager::class.java)
+
+ nm.createNotificationChannel(
+ NotificationChannel(
+ CHANNEL_LONG_RUNNING_ID,
+ getString(R.string.notification_channel_long_running_name),
+ NotificationManager.IMPORTANCE_DEFAULT,
+ )
+ )
+
+ nm.createNotificationChannel(
+ NotificationChannel(
+ CHANNEL_SYSTEM_EVENTS_ID,
+ getString(R.string.notification_channel_system_events_name),
+ NotificationManager.IMPORTANCE_HIGH,
+ )
+ )
+ }
+
+ companion object {
+ const val CHANNEL_LONG_RUNNING_ID = "long_running"
+ const val CHANNEL_SYSTEM_EVENTS_ID = "system_events"
+
+ fun getInstance(c: Context): Application = c.getApplicationContext() as Application
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt
index e7ac8d9..70bc5e4 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt
@@ -16,8 +16,6 @@
package com.android.virtualization.terminal
import android.Manifest
-import android.app.NotificationChannel
-import android.app.NotificationManager
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
@@ -25,18 +23,6 @@
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val notificationManager =
- getSystemService<NotificationManager>(NotificationManager::class.java)
- if (notificationManager.getNotificationChannel(this.packageName) == null) {
- val channel =
- NotificationChannel(
- this.packageName,
- getString(R.string.app_name),
- NotificationManager.IMPORTANCE_HIGH,
- )
- notificationManager.createNotificationChannel(channel)
- }
-
if (this !is ErrorActivity) {
val currentThread = Thread.currentThread()
if (currentThread.uncaughtExceptionHandler !is TerminalExceptionHandler) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DisplayProvider.kt b/android/TerminalApp/java/com/android/virtualization/terminal/DisplayProvider.kt
new file mode 100644
index 0000000..fed8e5a
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/DisplayProvider.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.crosvm.ICrosvmAndroidDisplayService
+import android.graphics.PixelFormat
+import android.os.ParcelFileDescriptor
+import android.os.RemoteException
+import android.os.ServiceManager
+import android.system.virtualizationservice_internal.IVirtualizationServiceInternal
+import android.util.Log
+import android.view.SurfaceControl
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import com.android.virtualization.terminal.DisplayProvider.CursorHandler
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.io.IOException
+import java.lang.Exception
+import java.lang.RuntimeException
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+import libcore.io.IoBridge
+
+/** Provides Android-side surface from given SurfaceView to a VM instance as a display for that */
+internal class DisplayProvider(
+ private val mainView: SurfaceView,
+ private val cursorView: SurfaceView,
+) {
+ private val virtService: IVirtualizationServiceInternal
+ private var cursorHandler: CursorHandler? = null
+
+ init {
+ mainView.setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT)
+ mainView.holder.addCallback(Callback(SurfaceKind.MAIN))
+ cursorView.setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_FOLLOWS_ATTACHMENT)
+ cursorView.holder.addCallback(Callback(SurfaceKind.CURSOR))
+ cursorView.holder.setFormat(PixelFormat.RGBA_8888)
+ // TODO: do we need this z-order?
+ cursorView.setZOrderMediaOverlay(true)
+ val b = ServiceManager.waitForService("android.system.virtualizationservice")
+ virtService = IVirtualizationServiceInternal.Stub.asInterface(b)
+ try {
+ // To ensure that the previous display service is removed.
+ virtService.clearDisplayService()
+ } catch (e: RemoteException) {
+ throw RuntimeException("Failed to clear prior display service", e)
+ }
+ }
+
+ fun notifyDisplayIsGoingToInvisible() {
+ // When the display is going to be invisible (by putting in the background), save the frame
+ // of the main surface so that we can re-draw it next time the display becomes visible. This
+ // is to save the duration of time where nothing is drawn by VM.
+ try {
+ getDisplayService().saveFrameForSurface(false /* forCursor */)
+ } catch (e: RemoteException) {
+ throw RuntimeException("Failed to save frame for the main surface", e)
+ }
+ }
+
+ @Synchronized
+ private fun getDisplayService(): ICrosvmAndroidDisplayService {
+ try {
+ val b = virtService.waitDisplayService()
+ return ICrosvmAndroidDisplayService.Stub.asInterface(b)
+ } catch (e: Exception) {
+ throw RuntimeException("Error while getting display service", e)
+ }
+ }
+
+ enum class SurfaceKind {
+ MAIN,
+ CURSOR,
+ }
+
+ inner class Callback(private val surfaceKind: SurfaceKind) : SurfaceHolder.Callback {
+ fun isForCursor(): Boolean {
+ return surfaceKind == SurfaceKind.CURSOR
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ try {
+ getDisplayService().setSurface(holder.getSurface(), isForCursor())
+ } catch (e: Exception) {
+ // TODO: don't consume this exception silently. For some unknown reason, setSurface
+ // call above throws IllegalArgumentException and that fails the surface
+ // configuration.
+ Log.e(TAG, "Failed to present surface $surfaceKind to VM", e)
+ }
+ try {
+ when (surfaceKind) {
+ SurfaceKind.MAIN -> getDisplayService().drawSavedFrameForSurface(isForCursor())
+ SurfaceKind.CURSOR -> {
+ val stream = createNewCursorStream()
+ getDisplayService().setCursorStream(stream)
+ }
+ }
+ } catch (e: Exception) {
+ // TODO: don't consume exceptions here too
+ Log.e(TAG, "Failed to configure surface $surfaceKind", e)
+ }
+ }
+
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+ // TODO: support resizeable display. We could actually change the display size that the
+ // VM sees, or keep the size and render it by fitting it in the new surface.
+ }
+
+ override fun surfaceDestroyed(holder: SurfaceHolder) {
+ try {
+ getDisplayService().removeSurface(isForCursor())
+ } catch (e: RemoteException) {
+ throw RuntimeException("Error while destroying surface for $surfaceKind", e)
+ }
+ }
+ }
+
+ private fun createNewCursorStream(): ParcelFileDescriptor? {
+ cursorHandler?.interrupt()
+ var pfds: Array<ParcelFileDescriptor> =
+ try {
+ ParcelFileDescriptor.createSocketPair()
+ } catch (e: IOException) {
+ throw RuntimeException("Failed to create socketpair for cursor stream", e)
+ }
+ cursorHandler = CursorHandler(pfds[0]).also { it.start() }
+ return pfds[1]
+ }
+
+ /**
+ * Thread reading cursor coordinate from a stream, and updating the position of the cursor
+ * surface accordingly.
+ */
+ private inner class CursorHandler(private val stream: ParcelFileDescriptor) : Thread() {
+ private val cursor: SurfaceControl = this@DisplayProvider.cursorView.surfaceControl
+ private val transaction: SurfaceControl.Transaction = SurfaceControl.Transaction()
+
+ init {
+ val main = this@DisplayProvider.mainView.surfaceControl
+ transaction.reparent(cursor, main).apply()
+ }
+
+ override fun run() {
+ try {
+ val byteBuffer = ByteBuffer.allocate(8 /* (x: u32, y: u32) */)
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
+ while (true) {
+ if (interrupted()) {
+ Log.d(TAG, "CursorHandler thread interrupted!")
+ return
+ }
+ byteBuffer.clear()
+ val bytes =
+ IoBridge.read(
+ stream.fileDescriptor,
+ byteBuffer.array(),
+ 0,
+ byteBuffer.array().size,
+ )
+ if (bytes == -1) {
+ Log.e(TAG, "cannot read from cursor stream, stop the handler")
+ return
+ }
+ val x = (byteBuffer.getInt() and -0x1).toFloat()
+ val y = (byteBuffer.getInt() and -0x1).toFloat()
+ transaction.setPosition(cursor, x, y).apply()
+ }
+ } catch (e: IOException) {
+ Log.e(TAG, "failed to run CursorHandler", e)
+ }
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InputForwarder.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InputForwarder.kt
new file mode 100644
index 0000000..117ce94
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InputForwarder.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.hardware.input.InputManager
+import android.os.Handler
+import android.system.virtualmachine.VirtualMachine
+import android.util.Log
+import android.view.InputDevice
+import android.view.KeyEvent
+import android.view.MotionEvent
+import android.view.View
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+
+/** Forwards input events (touch, mouse, ...) from Android to VM */
+internal class InputForwarder(
+ private val context: Context,
+ vm: VirtualMachine,
+ touchReceiver: View,
+ mouseReceiver: View,
+ keyReceiver: View,
+) {
+ private val virtualMachine: VirtualMachine = vm
+ private var inputDeviceListener: InputManager.InputDeviceListener? = null
+ private var isTabletMode = false
+
+ init {
+ val config = vm.config.customImageConfig
+
+ checkNotNull(config)
+
+ if (config.useTouch() == true) {
+ setupTouchReceiver(touchReceiver)
+ }
+ if (config.useMouse() || config.useTrackpad()) {
+ setupMouseReceiver(mouseReceiver)
+ }
+ if (config.useKeyboard()) {
+ setupKeyReceiver(keyReceiver)
+ }
+ if (config.useSwitches()) {
+ // Any view's handler is fine.
+ setupTabletModeHandler(touchReceiver.getHandler())
+ }
+ }
+
+ fun cleanUp() {
+ if (inputDeviceListener != null) {
+ val im = context.getSystemService<InputManager>(InputManager::class.java)
+ im.unregisterInputDeviceListener(inputDeviceListener)
+ inputDeviceListener = null
+ }
+ }
+
+ private fun setupTouchReceiver(receiver: View) {
+ receiver.setOnTouchListener(
+ View.OnTouchListener { v: View?, event: MotionEvent? ->
+ virtualMachine.sendMultiTouchEvent(event)
+ }
+ )
+ }
+
+ private fun setupMouseReceiver(receiver: View) {
+ receiver.requestUnbufferedDispatch(InputDevice.SOURCE_ANY)
+ receiver.setOnCapturedPointerListener { v: View?, event: MotionEvent? ->
+ val eventSource = event!!.source
+ if ((eventSource and InputDevice.SOURCE_CLASS_POSITION) != 0) {
+ return@setOnCapturedPointerListener virtualMachine.sendTrackpadEvent(event)
+ }
+ virtualMachine.sendMouseEvent(event)
+ }
+ }
+
+ private fun setupKeyReceiver(receiver: View) {
+ receiver.setOnKeyListener { v: View?, code: Int, event: KeyEvent? ->
+ // TODO: this is guest-os specific. It shouldn't be handled here.
+ if (isVolumeKey(code)) {
+ return@setOnKeyListener false
+ }
+ virtualMachine.sendKeyEvent(event)
+ }
+ }
+
+ private fun setupTabletModeHandler(handler: Handler?) {
+ val im = context.getSystemService<InputManager?>(InputManager::class.java)
+ inputDeviceListener =
+ object : InputManager.InputDeviceListener {
+ override fun onInputDeviceAdded(deviceId: Int) {
+ setTabletModeConditionally()
+ }
+
+ override fun onInputDeviceRemoved(deviceId: Int) {
+ setTabletModeConditionally()
+ }
+
+ override fun onInputDeviceChanged(deviceId: Int) {
+ setTabletModeConditionally()
+ }
+ }
+ im!!.registerInputDeviceListener(inputDeviceListener, handler)
+ }
+
+ fun setTabletModeConditionally() {
+ val tabletModeNeeded = !hasPhysicalKeyboard()
+ if (tabletModeNeeded != isTabletMode) {
+ val mode = if (tabletModeNeeded) "tablet mode" else "desktop mode"
+ Log.d(TAG, "switching to $mode")
+ isTabletMode = tabletModeNeeded
+ virtualMachine.sendTabletModeEvent(tabletModeNeeded)
+ }
+ }
+
+ companion object {
+ private fun isVolumeKey(keyCode: Int): Boolean {
+ return keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
+ keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
+ keyCode == KeyEvent.KEYCODE_VOLUME_MUTE
+ }
+
+ private fun hasPhysicalKeyboard(): Boolean {
+ for (id in InputDevice.getDeviceIds()) {
+ val d = InputDevice.getDevice(id)
+ if (!d!!.isVirtual && d.isEnabled && d.isFullKeyboard) {
+ return true
+ }
+ }
+ return false
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
index 423d66b..7180e87 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
@@ -71,7 +71,7 @@
PendingIntent.FLAG_IMMUTABLE,
)
notification =
- Notification.Builder(this, this.packageName)
+ Notification.Builder(this, Application.CHANNEL_LONG_RUNNING_ID)
.setSilent(true)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(getString(R.string.installer_notif_title_text))
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
index bf2f573..1ae6ec5 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -209,7 +209,10 @@
view: WebView?,
request: WebResourceRequest?,
): Boolean {
- return false
+ val intent = Intent(Intent.ACTION_VIEW, request?.url)
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ startActivity(intent)
+ return true
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
@@ -293,6 +296,8 @@
info,
executorService,
object : NsdManager.ServiceInfoCallback {
+ var loaded: Boolean = false
+
override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
override fun onServiceInfoCallbackUnregistered() {}
@@ -300,13 +305,15 @@
override fun onServiceLost() {}
override fun onServiceUpdated(info: NsdServiceInfo) {
- nsdManager.unregisterServiceInfoCallback(this)
-
Log.i(TAG, "Service found: $info")
val ipAddress = info.hostAddresses[0].hostAddress
val port = info.port
val url = getTerminalServiceUrl(ipAddress, port)
- runOnUiThread(Runnable { terminalView.loadUrl(url.toString()) })
+ if (!loaded) {
+ loaded = true
+ nsdManager.unregisterServiceInfoCallback(this)
+ runOnUiThread(Runnable { terminalView.loadUrl(url.toString()) })
+ }
}
},
)
@@ -409,7 +416,7 @@
)
val icon = Icon.createWithResource(resources, R.drawable.ic_launcher_foreground)
val notification: Notification =
- Notification.Builder(this, this.packageName)
+ Notification.Builder(this, Application.CHANNEL_LONG_RUNNING_ID)
.setSilent(true)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(resources.getString(R.string.service_notification_title))
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
index 7c48303..7e58b36 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
@@ -100,7 +100,7 @@
)
.build()
val notification: Notification =
- Notification.Builder(context, context.getPackageName())
+ Notification.Builder(context, Application.CHANNEL_SYSTEM_EVENTS_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title)
.setContentText(content)
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 8c0368d..f8b1b45 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -149,6 +149,8 @@
info,
executorService!!,
object : NsdManager.ServiceInfoCallback {
+ var started: Boolean = false
+
override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
override fun onServiceInfoCallbackUnregistered() {}
@@ -156,9 +158,12 @@
override fun onServiceLost() {}
override fun onServiceUpdated(info: NsdServiceInfo) {
- nsdManager.unregisterServiceInfoCallback(this)
Log.i(TAG, "Service found: $info")
- startDebianServer(info.hostAddresses[0].hostAddress)
+ if (!started) {
+ started = true
+ nsdManager.unregisterServiceInfoCallback(this)
+ startDebianServer(info.hostAddresses[0].hostAddress)
+ }
}
},
)
@@ -182,7 +187,7 @@
resources.getString(R.string.service_notification_force_quit_action)
val stopNotificationTitle: String? =
resources.getString(R.string.service_notification_close_title)
- return Notification.Builder(this, this.packageName)
+ return Notification.Builder(this, Application.CHANNEL_SYSTEM_EVENTS_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(stopNotificationTitle)
.setOngoing(true)
diff --git a/android/TerminalApp/res/values-iw/strings.xml b/android/TerminalApp/res/values-iw/strings.xml
index 8859e5f..729b22b 100644
--- a/android/TerminalApp/res/values-iw/strings.xml
+++ b/android/TerminalApp/res/values-iw/strings.xml
@@ -20,7 +20,7 @@
<string name="terminal_display" msgid="4810127497644015237">"תצוגת טרמינל"</string>
<string name="terminal_input" msgid="4602512831433433551">"סמן"</string>
<string name="empty_line" msgid="5012067143408427178">"שורה ריקה"</string>
- <string name="double_tap_to_edit_text" msgid="2344363097580051316">"כדי להקליד טקסט צריך להקיש הקשה כפולה"</string>
+ <string name="double_tap_to_edit_text" msgid="2344363097580051316">"כדי להקליד טקסט צריך ללחוץ לחיצה כפולה"</string>
<string name="installer_title_text" msgid="500663060973466805">"התקנה של טרמינל Linux"</string>
<string name="installer_desc_text_format" msgid="5935117404303982823">"כדי להפעיל את טרמינל Linux, צריך להוריד נתונים בנפח של בערך <xliff:g id="EXPECTED_SIZE">%1$s</xliff:g> דרך הרשת.\nלהמשיך?"</string>
<string name="installer_wait_for_wifi_checkbox_text" msgid="5812378362605046639">"הורדה רק באמצעות Wi-Fi"</string>
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index d3440d3..bdebb83 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -172,4 +172,10 @@
<!-- This string is for toast message to notify that VirGL is enabled. [CHAR LIMIT=40] -->
<string name="virgl_enabled"><xliff:g>VirGL</xliff:g> is enabled</string>
+
+ <!-- This is the name of the notification channel for long-runnint tasks [CHAR LIMIT=none] -->
+ <string name="notification_channel_long_running_name">Long running tasks</string>
+
+ <!-- This is the name of the notification channel for system events [CHAR LIMIT=none] -->
+ <string name="notification_channel_system_events_name">System events</string>
</resources>
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 57779bf..33f3be1 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -2033,7 +2033,7 @@
Owned(T),
}
-impl<'a, T> AsRef<T> for BorrowedOrOwned<'a, T> {
+impl<T> AsRef<T> for BorrowedOrOwned<'_, T> {
fn as_ref(&self) -> &T {
match self {
Self::Borrowed(b) => b,
diff --git a/build/debian/fai_config/files/etc/avahi/services/ttyd.service/AVF b/build/debian/fai_config/files/etc/avahi/services/ttyd.service/AVF
deleted file mode 100644
index 64f9d0a..0000000
--- a/build/debian/fai_config/files/etc/avahi/services/ttyd.service/AVF
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
-<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
-
-<service-group>
-
- <name>ttyd</name>
-
- <service protocol="ipv4">
- <type>_http._tcp</type>
- <port>7681</port>
- </service>
-
-</service-group>
diff --git a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
index 4a32f2b..d86bab0 100644
--- a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
+++ b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
@@ -3,11 +3,14 @@
After=syslog.target
After=network.target
After=virtiofs_internal.service
+
[Service]
ExecStart=/usr/local/bin/ttyd --ssl --ssl-cert /etc/ttyd/server.crt --ssl-key /etc/ttyd/server.key --ssl-ca /mnt/internal/ca.crt -t disableLeaveAlert=true -W login -f droid
+ExecStartPost=/usr/bin/avahi-publish-service ttyd _http._tcp 7681
Type=simple
Restart=always
User=root
Group=root
+
[Install]
WantedBy=multi-user.target
diff --git a/guest/authfs/src/common.rs b/guest/authfs/src/common.rs
index 6556fde..fc5af89 100644
--- a/guest/authfs/src/common.rs
+++ b/guest/authfs/src/common.rs
@@ -18,7 +18,7 @@
pub const CHUNK_SIZE: u64 = 4096;
pub fn divide_roundup(dividend: u64, divisor: u64) -> u64 {
- (dividend + divisor - 1) / divisor
+ dividend.div_ceil(divisor)
}
/// Given `offset` and `length`, generates (offset, size) tuples that together form the same length,
diff --git a/guest/authfs/src/fsverity/metadata/metadata.rs b/guest/authfs/src/fsverity/metadata/metadata.rs
index 54d0145..2e78190 100644
--- a/guest/authfs/src/fsverity/metadata/metadata.rs
+++ b/guest/authfs/src/fsverity/metadata/metadata.rs
@@ -131,8 +131,7 @@
};
// merkle tree is at the next 4K boundary
- let merkle_tree_offset =
- (metadata_file.stream_position()? + CHUNK_SIZE - 1) / CHUNK_SIZE * CHUNK_SIZE;
+ let merkle_tree_offset = (metadata_file.stream_position()?).div_ceil(CHUNK_SIZE) * CHUNK_SIZE;
Ok(Box::new(FSVerityMetadata { header, digest, signature, metadata_file, merkle_tree_offset }))
}
diff --git a/guest/authfs/src/fusefs.rs b/guest/authfs/src/fusefs.rs
index fa4076d..9e49046 100644
--- a/guest/authfs/src/fusefs.rs
+++ b/guest/authfs/src/fusefs.rs
@@ -816,7 +816,7 @@
// FUSE ioctl is limited, thus we can't implement fs-verity ioctls without a
// kernel change (see b/196635431). Until it's possible, use
// xattr to expose what we need as an authfs specific API.
- if name != CStr::from_bytes_with_nul(b"authfs.fsverity.digest\0").unwrap() {
+ if name != c"authfs.fsverity.digest" {
return Err(io::Error::from_raw_os_error(libc::ENODATA));
}
diff --git a/guest/pvmfw/Android.bp b/guest/pvmfw/Android.bp
index da056d6..4ef57a6 100644
--- a/guest/pvmfw/Android.bp
+++ b/guest/pvmfw/Android.bp
@@ -113,6 +113,7 @@
"libcbor_util",
"libciborium",
"libdiced_open_dice_nostd",
+ "libhwtrust",
"libpvmfw_avb_nostd",
"libdiced_sample_inputs_nostd",
"libzerocopy_nostd",
diff --git a/guest/pvmfw/avb/tests/api_test.rs b/guest/pvmfw/avb/tests/api_test.rs
index 23e05d4..29a6277 100644
--- a/guest/pvmfw/avb/tests/api_test.rs
+++ b/guest/pvmfw/avb/tests/api_test.rs
@@ -23,7 +23,6 @@
use std::{
fs,
mem::{offset_of, size_of},
- ptr,
};
use utils::*;
@@ -414,9 +413,9 @@
// vbmeta_header is unaligned; copy flags to local variable
let vbmeta_header_flags = vbmeta_header.flags;
assert_eq!(0, vbmeta_header_flags, "The disable flag should not be set in the latest kernel.");
- let flags_addr = ptr::addr_of!(vbmeta_header.flags) as *const u8;
+ let flags_addr = (&raw const vbmeta_header.flags).cast::<u8>();
// SAFETY: It is safe as both raw pointers `flags_addr` and `vbmeta_header` are not null.
- let flags_offset = unsafe { flags_addr.offset_from(ptr::addr_of!(vbmeta_header) as *const u8) };
+ let flags_offset = unsafe { flags_addr.offset_from((&raw const vbmeta_header).cast::<u8>()) };
let flags_offset = usize::try_from(footer.vbmeta_offset)? + usize::try_from(flags_offset)?;
// Act.
diff --git a/guest/pvmfw/src/dice.rs b/guest/pvmfw/src/dice.rs
index a72c1fc..78bd6b8 100644
--- a/guest/pvmfw/src/dice.rs
+++ b/guest/pvmfw/src/dice.rs
@@ -185,6 +185,7 @@
use diced_open_dice::KeyAlgorithm;
use diced_open_dice::HIDDEN_SIZE;
use diced_sample_inputs::make_sample_bcc_and_cdis;
+ use hwtrust::{dice, session::Session};
use pvmfw_avb::Capability;
use pvmfw_avb::DebugLevel;
use pvmfw_avb::Digest;
@@ -426,14 +427,11 @@
},
)
.expect("Failed to derive EcdsaP384 -> Ed25519 BCC");
- let _bcc_handover3 = diced_open_dice::bcc_handover_parse(&buffer).unwrap();
+ let bcc_handover3 = diced_open_dice::bcc_handover_parse(&buffer).unwrap();
- // TODO(b/378813154): Check the DICE chain with `hwtrust` once the profile version
- // is updated.
- // The check cannot be done now because parsing the chain causes the following error:
- // Invalid payload at index 3. Caused by:
- // 0: opendice.example.p256
- // 1: unknown profile version
+ let mut session = Session::default();
+ session.set_allow_any_mode(true);
+ let _chain = dice::Chain::from_cbor(&session, bcc_handover3.bcc().unwrap()).unwrap();
}
fn to_bcc_handover(dice_artifacts: &dyn DiceArtifacts) -> Vec<u8> {
diff --git a/guest/vmbase_example/Android.bp b/guest/vmbase_example/Android.bp
index ab21191..e5dfc2a 100644
--- a/guest/vmbase_example/Android.bp
+++ b/guest/vmbase_example/Android.bp
@@ -12,6 +12,7 @@
"libdiced_open_dice_nostd",
"liblibfdt_nostd",
"liblog_rust_nostd",
+ "libspin_nostd",
"libvirtio_drivers",
"libvmbase",
],
diff --git a/guest/vmbase_example/src/main.rs b/guest/vmbase_example/src/main.rs
index f5b41bd..b7d2f95 100644
--- a/guest/vmbase_example/src/main.rs
+++ b/guest/vmbase_example/src/main.rs
@@ -26,9 +26,9 @@
use crate::layout::print_addresses;
use crate::pci::check_pci;
use alloc::{vec, vec::Vec};
-use core::ptr::addr_of_mut;
use libfdt::Fdt;
use log::{debug, error, info, trace, warn, LevelFilter};
+use spin::mutex::SpinMutex;
use vmbase::{
bionic, configure_heap,
fdt::pci::PciInfo,
@@ -39,8 +39,8 @@
};
static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
-static mut ZEROED_DATA: [u32; 10] = [0; 10];
-static mut MUTABLE_DATA: [u32; 4] = [1, 2, 3, 4];
+static ZEROED_DATA: SpinMutex<[u32; 10]> = SpinMutex::new([0; 10]);
+static MUTABLE_DATA: SpinMutex<[u32; 4]> = SpinMutex::new([1, 2, 3, 4]);
generate_image_header!();
main!(main);
@@ -103,22 +103,16 @@
fn check_data() {
info!("INITIALISED_DATA: {:?}", INITIALISED_DATA.as_ptr());
- // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
- info!("ZEROED_DATA: {:?}", unsafe { ZEROED_DATA.as_ptr() });
- // SAFETY: We only print the addresses of the static mutable variable, not actually access it.
- info!("MUTABLE_DATA: {:?}", unsafe { MUTABLE_DATA.as_ptr() });
assert_eq!(INITIALISED_DATA[0], 1);
assert_eq!(INITIALISED_DATA[1], 2);
assert_eq!(INITIALISED_DATA[2], 3);
assert_eq!(INITIALISED_DATA[3], 4);
- // SAFETY: Nowhere else in the program accesses this static mutable variable, so there is no
- // chance of concurrent access.
- let zeroed_data = unsafe { &mut *addr_of_mut!(ZEROED_DATA) };
- // SAFETY: Nowhere else in the program accesses this static mutable variable, so there is no
- // chance of concurrent access.
- let mutable_data = unsafe { &mut *addr_of_mut!(MUTABLE_DATA) };
+ let zeroed_data = &mut *ZEROED_DATA.lock();
+ let mutable_data = &mut *MUTABLE_DATA.lock();
+ info!("ZEROED_DATA: {:?}", zeroed_data.as_ptr());
+ info!("MUTABLE_DATA: {:?}", mutable_data.as_ptr());
for element in zeroed_data.iter() {
assert_eq!(*element, 0);
diff --git a/libs/apkverify/src/hashtree.rs b/libs/apkverify/src/hashtree.rs
index 00d8292..54e879b 100644
--- a/libs/apkverify/src/hashtree.rs
+++ b/libs/apkverify/src/hashtree.rs
@@ -84,7 +84,7 @@
let mut level0 = Cursor::new(&mut hash_tree[cur.start..cur.end]);
let mut a_block = vec![0; block_size];
- let mut num_blocks = (input_size + block_size - 1) / block_size;
+ let mut num_blocks = input_size.div_ceil(block_size);
while num_blocks > 0 {
input.read_exact(&mut a_block)?;
let h = hash_one_block(&a_block, salt, block_size, algorithm)?;
@@ -138,7 +138,7 @@
if input_size <= block_size {
break;
}
- let num_blocks = (input_size + block_size - 1) / block_size;
+ let num_blocks = input_size.div_ceil(block_size);
let hashes_size = round_to_multiple(num_blocks * digest_size, block_size);
level_sizes.push(hashes_size);
}
diff --git a/libs/bssl/src/cbb.rs b/libs/bssl/src/cbb.rs
index a48c714..282a77d 100644
--- a/libs/bssl/src/cbb.rs
+++ b/libs/bssl/src/cbb.rs
@@ -40,13 +40,13 @@
}
}
-impl<'a> AsRef<CBB> for CbbFixed<'a> {
+impl AsRef<CBB> for CbbFixed<'_> {
fn as_ref(&self) -> &CBB {
&self.cbb
}
}
-impl<'a> AsMut<CBB> for CbbFixed<'a> {
+impl AsMut<CBB> for CbbFixed<'_> {
fn as_mut(&mut self) -> &mut CBB {
&mut self.cbb
}
diff --git a/libs/bssl/src/cbs.rs b/libs/bssl/src/cbs.rs
index 12671cf..166484c 100644
--- a/libs/bssl/src/cbs.rs
+++ b/libs/bssl/src/cbs.rs
@@ -42,13 +42,13 @@
}
}
-impl<'a> AsRef<CBS> for Cbs<'a> {
+impl AsRef<CBS> for Cbs<'_> {
fn as_ref(&self) -> &CBS {
&self.cbs
}
}
-impl<'a> AsMut<CBS> for Cbs<'a> {
+impl AsMut<CBS> for Cbs<'_> {
fn as_mut(&mut self) -> &mut CBS {
&mut self.cbs
}
diff --git a/libs/bssl/src/ec_key.rs b/libs/bssl/src/ec_key.rs
index 3e2e382..da9eb77 100644
--- a/libs/bssl/src/ec_key.rs
+++ b/libs/bssl/src/ec_key.rs
@@ -471,7 +471,7 @@
/// Wrapper of an `EC_GROUP` reference.
struct EcGroup<'a>(&'a EC_GROUP);
-impl<'a> EcGroup<'a> {
+impl EcGroup<'_> {
/// Returns the NID that identifies the EC group of the key.
fn curve_nid(&self) -> i32 {
// SAFETY: It is safe since the inner pointer is valid and points to an initialized
@@ -518,7 +518,7 @@
}
}
-impl<'a> AsRef<EC_GROUP> for EcGroup<'a> {
+impl AsRef<EC_GROUP> for EcGroup<'_> {
fn as_ref(&self) -> &EC_GROUP {
self.0
}
diff --git a/libs/devicemapper/src/crypt.rs b/libs/devicemapper/src/crypt.rs
index 75417ed..1326caf 100644
--- a/libs/devicemapper/src/crypt.rs
+++ b/libs/devicemapper/src/crypt.rs
@@ -87,7 +87,7 @@
opt_params: Vec<&'a str>,
}
-impl<'a> Default for DmCryptTargetBuilder<'a> {
+impl Default for DmCryptTargetBuilder<'_> {
fn default() -> Self {
DmCryptTargetBuilder {
cipher: CipherType::AES256HCTR2,
diff --git a/libs/devicemapper/src/verity.rs b/libs/devicemapper/src/verity.rs
index 09087da..100320b 100644
--- a/libs/devicemapper/src/verity.rs
+++ b/libs/devicemapper/src/verity.rs
@@ -66,7 +66,7 @@
}
}
-impl<'a> Default for DmVerityTargetBuilder<'a> {
+impl Default for DmVerityTargetBuilder<'_> {
fn default() -> Self {
DmVerityTargetBuilder {
version: DmVerityVersion::V1,
diff --git a/libs/dice/driver/src/lib.rs b/libs/dice/driver/src/lib.rs
index b5c1f12..245bf11 100644
--- a/libs/dice/driver/src/lib.rs
+++ b/libs/dice/driver/src/lib.rs
@@ -185,7 +185,6 @@
#[cfg(test)]
mod tests {
use super::*;
- use core::ffi::CStr;
use diced_open_dice::{
hash, retry_bcc_format_config_descriptor, DiceConfigValues, HIDDEN_SIZE,
};
@@ -233,10 +232,7 @@
let dice = DiceDriver::from_file(&file_path)?;
- let values = DiceConfigValues {
- component_name: Some(CStr::from_bytes_with_nul(b"test\0")?),
- ..Default::default()
- };
+ let values = DiceConfigValues { component_name: Some(c"test"), ..Default::default() };
let desc = retry_bcc_format_config_descriptor(&values)?;
let code_hash = hash(&String::from("test code hash").into_bytes())?;
let authority_hash = hash(&String::from("test authority hash").into_bytes())?;
diff --git a/libs/dice/open_dice/src/bcc.rs b/libs/dice/open_dice/src/bcc.rs
index a3ddd76..1d9039d 100644
--- a/libs/dice/open_dice/src/bcc.rs
+++ b/libs/dice/open_dice/src/bcc.rs
@@ -172,7 +172,7 @@
bcc: Option<&'a [u8]>,
}
-impl<'a> DiceArtifacts for BccHandover<'a> {
+impl DiceArtifacts for BccHandover<'_> {
fn cdi_attest(&self) -> &[u8; CDI_SIZE] {
self.cdi_attest
}
diff --git a/libs/dice/open_dice/src/error.rs b/libs/dice/open_dice/src/error.rs
index 9089432..c9eb5cc 100644
--- a/libs/dice/open_dice/src/error.rs
+++ b/libs/dice/open_dice/src/error.rs
@@ -31,6 +31,8 @@
PlatformError,
/// Unsupported key algorithm.
UnsupportedKeyAlgorithm(coset::iana::Algorithm),
+ /// A failed fallible allocation. Used in no_std environments.
+ MemoryAllocationError,
}
/// This makes `DiceError` accepted by anyhow.
@@ -48,6 +50,7 @@
Self::UnsupportedKeyAlgorithm(algorithm) => {
write!(f, "Unsupported key algorithm: {algorithm:?}")
}
+ Self::MemoryAllocationError => write!(f, "Memory allocation failed"),
}
}
}
diff --git a/libs/dice/open_dice/src/retry.rs b/libs/dice/open_dice/src/retry.rs
index 6e75e91..803673d 100644
--- a/libs/dice/open_dice/src/retry.rs
+++ b/libs/dice/open_dice/src/retry.rs
@@ -13,9 +13,9 @@
// limitations under the License.
//! This module implements a retry version for multiple DICE functions that
-//! require preallocated output buffer. As the retry functions require
-//! memory allocation on heap, currently we only expose these functions in
-//! std environment.
+//! require preallocated output buffer. When running without std the allocation
+//! of this buffer may fail and callers will see Error::MemoryAllocationError.
+//! When running with std, allocation may fail.
use crate::bcc::{bcc_format_config_descriptor, bcc_main_flow, DiceConfigValues};
use crate::dice::{
@@ -62,6 +62,9 @@
let mut buffer = Vec::new();
match f(&mut buffer) {
Err(DiceError::BufferTooSmall(actual_size)) => {
+ #[cfg(not(feature = "std"))]
+ buffer.try_reserve_exact(actual_size).map_err(|_| DiceError::MemoryAllocationError)?;
+
buffer.resize(actual_size, 0);
f(&mut buffer)?;
}
diff --git a/libs/dice/sample_inputs/src/sample_inputs.rs b/libs/dice/sample_inputs/src/sample_inputs.rs
index c323bc4..adca46b 100644
--- a/libs/dice/sample_inputs/src/sample_inputs.rs
+++ b/libs/dice/sample_inputs/src/sample_inputs.rs
@@ -18,7 +18,6 @@
use alloc::vec;
use alloc::vec::Vec;
use ciborium::{de, ser, value::Value};
-use core::ffi::CStr;
use coset::{iana, Algorithm, AsCborValue, CoseKey, KeyOperation, KeyType, Label};
use diced_open_dice::{
derive_cdi_private_key_seed, keypair_from_seed, retry_bcc_format_config_descriptor,
@@ -115,7 +114,7 @@
// Gets the ABL certificate to as the root certificate of DICE chain.
let config_values = DiceConfigValues {
- component_name: Some(CStr::from_bytes_with_nul(b"ABL\0").unwrap()),
+ component_name: Some(c"ABL"),
component_version: Some(1),
resettable: true,
security_version: Some(10),
@@ -148,7 +147,7 @@
// Appends AVB certificate to DICE chain.
let config_values = DiceConfigValues {
- component_name: Some(CStr::from_bytes_with_nul(b"AVB\0").unwrap()),
+ component_name: Some(c"AVB"),
component_version: Some(1),
resettable: true,
security_version: Some(11),
@@ -173,7 +172,7 @@
// Appends Android certificate to DICE chain.
let config_values = DiceConfigValues {
- component_name: Some(CStr::from_bytes_with_nul(b"Android\0").unwrap()),
+ component_name: Some(c"Android"),
component_version: Some(12),
resettable: true,
security_version: Some(12),
diff --git a/libs/libfdt/src/iterators.rs b/libs/libfdt/src/iterators.rs
index 743c52b..1c66e4d 100644
--- a/libs/libfdt/src/iterators.rs
+++ b/libs/libfdt/src/iterators.rs
@@ -66,7 +66,7 @@
}
}
-impl<'a> Iterator for CellIterator<'a> {
+impl Iterator for CellIterator<'_> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
@@ -118,7 +118,7 @@
}
}
-impl<'a> Iterator for RegIterator<'a> {
+impl Iterator for RegIterator<'_> {
type Item = Reg<u64>;
fn next(&mut self) -> Option<Self::Item> {
@@ -161,7 +161,7 @@
}
}
-impl<'a> Iterator for MemRegIterator<'a> {
+impl Iterator for MemRegIterator<'_> {
type Item = Range<usize>;
fn next(&mut self) -> Option<Self::Item> {
@@ -215,8 +215,8 @@
}
}
-impl<'a, A: FromAddrCells, P: FromAddrCells, S: FromSizeCells> Iterator
- for RangesIterator<'a, A, P, S>
+impl<A: FromAddrCells, P: FromAddrCells, S: FromSizeCells> Iterator
+ for RangesIterator<'_, A, P, S>
{
type Item = AddressRange<A, P, S>;
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 0dcd31a..47f4817 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -344,7 +344,7 @@
}
}
-impl<'a> PartialEq for FdtNode<'a> {
+impl PartialEq for FdtNode<'_> {
fn eq(&self, other: &Self) -> bool {
self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
}
diff --git a/libs/libservice_vm_requests/src/cert.rs b/libs/libservice_vm_requests/src/cert.rs
index e31d870..de5ae1a 100644
--- a/libs/libservice_vm_requests/src/cert.rs
+++ b/libs/libservice_vm_requests/src/cert.rs
@@ -58,7 +58,7 @@
vm_components: Vec<VmComponent<'a>>,
}
-impl<'a> AssociatedOid for AttestationExtension<'a> {
+impl AssociatedOid for AttestationExtension<'_> {
const OID: ObjectIdentifier = AVF_ATTESTATION_EXTENSION_V1;
}
diff --git a/libs/libvm_payload/src/lib.rs b/libs/libvm_payload/src/lib.rs
index cbadec2..14aff99 100644
--- a/libs/libvm_payload/src/lib.rs
+++ b/libs/libvm_payload/src/lib.rs
@@ -27,7 +27,7 @@
use rpcbinder::{RpcServer, RpcSession};
use openssl::{ec::EcKey, sha::sha256, ecdsa::EcdsaSig};
use std::convert::Infallible;
-use std::ffi::{CString, CStr};
+use std::ffi::CString;
use std::fmt::Debug;
use std::os::raw::{c_char, c_void};
use std::path::Path;
@@ -376,20 +376,16 @@
#[no_mangle]
pub extern "C" fn AVmAttestationStatus_toString(status: AVmAttestationStatus) -> *const c_char {
let message = match status {
- AVmAttestationStatus::ATTESTATION_OK => {
- CStr::from_bytes_with_nul(b"The remote attestation completes successfully.\0").unwrap()
- }
+ AVmAttestationStatus::ATTESTATION_OK => c"The remote attestation completes successfully.",
AVmAttestationStatus::ATTESTATION_ERROR_INVALID_CHALLENGE => {
- CStr::from_bytes_with_nul(b"The challenge size is not between 0 and 64.\0").unwrap()
+ c"The challenge size is not between 0 and 64."
}
AVmAttestationStatus::ATTESTATION_ERROR_ATTESTATION_FAILED => {
- CStr::from_bytes_with_nul(b"Failed to attest the VM. Please retry at a later time.\0")
- .unwrap()
+ c"Failed to attest the VM. Please retry at a later time."
}
- AVmAttestationStatus::ATTESTATION_ERROR_UNSUPPORTED => CStr::from_bytes_with_nul(
- b"Remote attestation is not supported in the current environment.\0",
- )
- .unwrap(),
+ AVmAttestationStatus::ATTESTATION_ERROR_UNSUPPORTED => {
+ c"Remote attestation is not supported in the current environment."
+ }
};
message.as_ptr()
}
diff --git a/libs/libvm_payload/wrapper/attestation.rs b/libs/libvm_payload/wrapper/attestation.rs
index e0055d5..69fef4f 100644
--- a/libs/libvm_payload/wrapper/attestation.rs
+++ b/libs/libvm_payload/wrapper/attestation.rs
@@ -265,7 +265,7 @@
current: usize, // Invariant: current <= count
}
-impl<'a> Iterator for CertIterator<'a> {
+impl Iterator for CertIterator<'_> {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Self::Item> {
@@ -284,5 +284,5 @@
}
}
-impl<'a> ExactSizeIterator for CertIterator<'a> {}
-impl<'a> FusedIterator for CertIterator<'a> {}
+impl ExactSizeIterator for CertIterator<'_> {}
+impl FusedIterator for CertIterator<'_> {}
diff --git a/libs/libvmbase/src/bionic.rs b/libs/libvmbase/src/bionic.rs
index 37b6e45..ac9f80f 100644
--- a/libs/libvmbase/src/bionic.rs
+++ b/libs/libvmbase/src/bionic.rs
@@ -20,7 +20,6 @@
use core::ffi::c_int;
use core::ffi::c_void;
use core::ffi::CStr;
-use core::ptr::addr_of_mut;
use core::slice;
use core::str;
@@ -71,11 +70,10 @@
pub static mut ERRNO: c_int = 0;
#[no_mangle]
-#[allow(unused_unsafe)]
+// SAFETY: C functions which call this are only called from the main thread, not from exception
+// handlers.
unsafe extern "C" fn __errno() -> *mut c_int {
- // SAFETY: C functions which call this are only called from the main thread, not from exception
- // handlers.
- unsafe { addr_of_mut!(ERRNO) as *mut _ }
+ (&raw mut ERRNO).cast()
}
fn set_errno(value: c_int) {
diff --git a/libs/libvmbase/src/layout.rs b/libs/libvmbase/src/layout.rs
index cf3a8fc..4c45eb2 100644
--- a/libs/libvmbase/src/layout.rs
+++ b/libs/libvmbase/src/layout.rs
@@ -22,7 +22,6 @@
use crate::memory::{max_stack_size, page_4kb_of, PAGE_SIZE};
use aarch64_paging::paging::VirtualAddress;
use core::ops::Range;
-use core::ptr::addr_of;
use static_assertions::const_assert_eq;
/// First address that can't be translated by a level 1 TTBR0_EL1.
@@ -44,9 +43,7 @@
#[macro_export]
macro_rules! linker_addr {
($symbol:ident) => {{
- // SAFETY: We're just getting the address of an extern static symbol provided by the linker,
- // not dereferencing it.
- let addr = unsafe { addr_of!($crate::linker::$symbol) as usize };
+ let addr = (&raw const $crate::linker::$symbol) as usize;
VirtualAddress(addr)
}};
}
@@ -132,5 +129,5 @@
// SAFETY: __stack_chk_guard shouldn't have any mutable aliases unless the stack overflows. If
// it does, then there could be undefined behaviour all over the program, but we want to at
// least have a chance at catching it.
- unsafe { addr_of!(__stack_chk_guard).read_volatile() }
+ unsafe { (&raw const __stack_chk_guard).read_volatile() }
}
diff --git a/libs/statslog_virtualization/Android.bp b/libs/statslog_virtualization/Android.bp
index 2860e6c..f33a147 100644
--- a/libs/statslog_virtualization/Android.bp
+++ b/libs/statslog_virtualization/Android.bp
@@ -72,4 +72,7 @@
rustlibs: [
"libstatslog_virtualization_rust_header",
],
+ flags: [
+ "-A clippy::needless-lifetimes",
+ ],
}
diff --git a/tests/aidl/Android.bp b/tests/aidl/Android.bp
index ed4e8ff..63db488 100644
--- a/tests/aidl/Android.bp
+++ b/tests/aidl/Android.bp
@@ -17,5 +17,8 @@
cpp: {
enabled: true,
},
+ ndk: {
+ min_sdk_version: "UpsideDownCake",
+ },
},
}
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 4f9806a..e8673ce 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -101,6 +101,9 @@
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_NONE = "none";
+
private static final int MIN_MEM_ARM64 = 170;
private static final int MIN_MEM_X86_64 = 196;
@@ -465,7 +468,7 @@
try {
microdroid =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(true)
@@ -495,7 +498,7 @@
// Act
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(true)
@@ -644,7 +647,7 @@
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -751,7 +754,7 @@
VIRT_APEX + "bin/vm",
"run-app",
"--debug",
- debuggable ? "full" : "none",
+ debuggable ? DEBUG_LEVEL_FULL : DEBUG_LEVEL_NONE,
apkPath,
idsigPath,
instanceImgPath));
@@ -871,7 +874,7 @@
final String configPath = "assets/vm_config_apex.json"; // path inside the APK
ITestDevice microdroid =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1023,7 +1026,7 @@
final String configPath = "assets/vm_config.json"; // path inside the APK
testMicrodroidBootsWithBuilder(
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1061,7 +1064,7 @@
final String configPath = "assets/vm_config.json";
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1175,7 +1178,7 @@
"shell",
VIRT_APEX + "bin/vm",
"run-app",
- "--debug full",
+ "--debug " + DEBUG_LEVEL_FULL,
"--console " + CONSOLE_PATH,
"--payload-binary-name",
"MicrodroidEmptyPayloadJniLib.so",
@@ -1357,7 +1360,7 @@
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1403,7 +1406,7 @@
final String configPath = "assets/vm_config.json";
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(minMemorySize())
.cpuTopology("match_host")
.protectedVm(protectedVm)
@@ -1434,7 +1437,7 @@
// Start the VM with the dump DT option.
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(mem_size)
.cpuTopology("one_cpu")
.protectedVm(false)
@@ -1464,7 +1467,7 @@
// Start the VM with the dump DT option.
mMicrodroidDevice =
MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
- .debugLevel("full")
+ .debugLevel(DEBUG_LEVEL_FULL)
.memoryMib(mem_size)
.cpuTopology("one_cpu")
.protectedVm(true)
diff --git a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_golden.dts b/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_golden.dts
index 095eb54..de9f7c5 100644
--- a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_golden.dts
+++ b/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_golden.dts
@@ -49,7 +49,7 @@
};
chosen {
- bootargs = "panic=-1 crashkernel=17M";
+ bootargs = "panic=-1 crashkernel=17M earlycon=uart8250,mmio,0x3f8 keep_bootcon";
kaslr-seed = <>;
linux,initrd-end = <0x81200360>;
linux,initrd-start = <0x81000000>;
diff --git a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_protected_golden.dts b/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_protected_golden.dts
index f2ebdf9..f09e4ff 100644
--- a/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_protected_golden.dts
+++ b/tests/hostside/java/com/android/microdroid/test/goldens/dt_dump_protected_golden.dts
@@ -49,7 +49,7 @@
};
chosen {
- bootargs = "panic=-1 crashkernel=31M";
+ bootargs = "panic=-1 crashkernel=31M earlycon=uart8250,mmio,0x3f8 keep_bootcon";
kaslr-seed = <>;
linux,initrd-end = <0x81202104>;
linux,initrd-start = <0x81000000>;
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index d0e045b..99300e2 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -173,6 +173,8 @@
"liblog",
"libprotobuf-cpp-lite-ndk",
],
+ // We've added support for updatable payloads in Android U.
+ min_sdk_version: "UpsideDownCake",
}
cc_library_shared {
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 a50ce98..a2b4747 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -1874,22 +1874,13 @@
return false;
}
- private void ensureUpdatableVmSupported() throws Exception {
- if (getVendorApiLevel() >= 202504 && deviceCapableOfProtectedVm()) {
- assertTrue(
- "Missing Updatable VM support, have you declared Secretkeeper interface?",
- isUpdatableVmSupported());
- } else {
- assumeTrue("Device does not support Updatable VM", isUpdatableVmSupported());
- }
- }
-
@Test
public void rollbackProtectedDataOfPayload() throws Exception {
assumeSupportedDevice();
// Rollback protected data is only possible if Updatable VMs is supported -
// which implies Secretkeeper support.
- ensureUpdatableVmSupported();
+ assumeTrue("Missing Updatable VM support", isUpdatableVmSupported());
+
byte[] value1 = new byte[32];
Arrays.fill(value1, (byte) 0xcc);
byte[] value2 = new byte[32];
@@ -1954,6 +1945,11 @@
assumeFalse(
"Cuttlefish/Goldfish doesn't support device tree under /proc/device-tree",
isCuttlefish() || isGoldfish());
+ if (!isUpdatableVmSupported()) {
+ // TODO(b/389611249): Non protected VMs using legacy secret mechanisms do not reliably
+ // implement `AVmPayload_isNewInstance`.
+ assumeProtectedVM();
+ }
VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_a", config);
TestResults testResults =
runVmTestService(
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 06c7e9d..2ab73a4 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -348,25 +348,40 @@
}
ScopedAStatus insecurelyReadPayloadRpData(std::array<uint8_t, 32>* out) override {
- int32_t ret = AVmPayload_readRollbackProtectedSecret(out->data(), 32);
- if (ret != 32) {
- return ScopedAStatus::fromServiceSpecificError(ret);
+ if (__builtin_available(android 36, *)) {
+ int32_t ret = AVmPayload_readRollbackProtectedSecret(out->data(), 32);
+ if (ret != 32) {
+ return ScopedAStatus::fromServiceSpecificError(ret);
+ }
+ return ScopedAStatus::ok();
+ } else {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ "not available before SDK 36");
}
- return ScopedAStatus::ok();
}
ScopedAStatus insecurelyWritePayloadRpData(
const std::array<uint8_t, 32>& inputData) override {
- int32_t ret = AVmPayload_writeRollbackProtectedSecret(inputData.data(), 32);
- if (ret != 32) {
- return ScopedAStatus::fromServiceSpecificError(ret);
+ if (__builtin_available(android 36, *)) {
+ int32_t ret = AVmPayload_writeRollbackProtectedSecret(inputData.data(), 32);
+ if (ret != 32) {
+ return ScopedAStatus::fromServiceSpecificError(ret);
+ }
+ return ScopedAStatus::ok();
+ } else {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ "not available before SDK 36");
}
- return ScopedAStatus::ok();
}
ScopedAStatus isNewInstance(bool* is_new_instance_out) override {
- *is_new_instance_out = AVmPayload_isNewInstance();
- return ScopedAStatus::ok();
+ if (__builtin_available(android 36, *)) {
+ *is_new_instance_out = AVmPayload_isNewInstance();
+ return ScopedAStatus::ok();
+ } else {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ "not available before SDK 36");
+ }
}
ScopedAStatus quit() override { exit(0); }
diff --git a/tests/vmshareapp/Android.bp b/tests/vmshareapp/Android.bp
index 5f6dc57..86c48f6 100644
--- a/tests/vmshareapp/Android.bp
+++ b/tests/vmshareapp/Android.bp
@@ -13,4 +13,8 @@
"MicrodroidPayloadInOtherAppNativeLib",
],
min_sdk_version: "34",
+ sdk_version: "system_current",
+ // Ideally we should set something "latest finalized sdk version" here.
+ // However, soong doesn't seem to provide such functionality.
+ target_sdk_version: "VanillaIceCream",
}
diff --git a/tests/vts/src/vts_libavf_test.rs b/tests/vts/src/vts_libavf_test.rs
index e30c175..dc37aad 100644
--- a/tests/vts/src/vts_libavf_test.rs
+++ b/tests/vts/src/vts_libavf_test.rs
@@ -16,7 +16,6 @@
use anyhow::{bail, ensure, Context, Result};
use log::info;
-use std::ffi::CStr;
use std::fs::File;
use std::io::{self, BufWriter, Write};
use std::os::fd::IntoRawFd;
@@ -87,10 +86,7 @@
// SAFETY: config is the only reference to a valid object
unsafe {
- AVirtualMachineRawConfig_setName(
- config,
- CStr::from_bytes_with_nul(b"vts_libavf_test_rialto\0").unwrap().as_ptr(),
- );
+ AVirtualMachineRawConfig_setName(config, c"vts_libavf_test_rialto".as_ptr());
AVirtualMachineRawConfig_setKernel(config, kernel_fd);
AVirtualMachineRawConfig_setProtectedVm(config, protected_vm);
AVirtualMachineRawConfig_setMemoryMiB(config, VM_MEMORY_MB);