Merge "guest: debian: Implement storage_balloon_agent" into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
index 35c5570..390ae00 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -56,7 +56,6 @@
import com.android.virtualization.terminal.VmLauncherService.VmLauncherServiceCallback
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
-import java.io.IOException
import java.net.MalformedURLException
import java.net.URL
import java.util.concurrent.CompletableFuture
@@ -253,7 +252,7 @@
executorService.shutdown()
getSystemService<AccessibilityManager>(AccessibilityManager::class.java)
.removeAccessibilityStateChangeListener(this)
- stop(this)
+ stop(this, this)
super.onDestroy()
}
@@ -313,8 +312,6 @@
return
}
- resizeDiskIfNecessary(image)
-
val tapIntent = Intent(this, MainActivity::class.java)
tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
val tapPendingIntent =
@@ -362,7 +359,11 @@
)
.build()
- run(this, this, notification, getDisplayInfo())
+ val diskSize = intent.getLongExtra(KEY_DISK_SIZE, image.getSize())
+ run(this, this, notification, getDisplayInfo(), diskSize).onFailure {
+ Log.e(TAG, "Failed to start VM.", it)
+ finish()
+ }
}
@VisibleForTesting
@@ -370,16 +371,6 @@
return bootCompleted.block(timeoutMillis)
}
- private fun resizeDiskIfNecessary(image: InstalledImage) {
- try {
- // TODO(b/382190982): Show snackbar message instead when it's recoverable.
- image.resize(intent.getLongExtra(KEY_DISK_SIZE, image.getSize()))
- } catch (e: IOException) {
- start(this, Exception("Failed to resize disk", e))
- return
- }
- }
-
companion object {
const val TAG: String = "VmTerminalApp"
const val KEY_DISK_SIZE: String = "disk_size"
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
index 8ea4b25..68da45f 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
@@ -31,6 +31,7 @@
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
+import com.android.virtualization.terminal.VmLauncherService.VmLauncherServiceCallback
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.util.Locale
import java.util.regex.Pattern
@@ -140,12 +141,32 @@
diskSizeMb = progressToMb(diskSizeSlider.progress)
buttons.isVisible = false
- // Restart terminal
- val intent = baseContext.packageManager.getLaunchIntentForPackage(baseContext.packageName)
- intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
- intent?.putExtra(MainActivity.KEY_DISK_SIZE, mbToBytes(diskSizeMb))
- finish()
- startActivity(intent)
+ // Note: we first stop the VM, and wait for it to fully stop. Then we (re) start the Main
+ // Activity with an extra argument specifying the new size. The actual resizing will be done
+ // there.
+ // TODO: show progress until the stop is confirmed
+ VmLauncherService.stop(
+ this,
+ object : VmLauncherServiceCallback {
+ override fun onVmStart() {}
+
+ override fun onTerminalAvailable(info: TerminalInfo) {}
+
+ override fun onVmStop() {
+ finish()
+
+ val intent =
+ baseContext.packageManager.getLaunchIntentForPackage(
+ baseContext.packageName
+ )!!
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ intent.putExtra(MainActivity.KEY_DISK_SIZE, mbToBytes(diskSizeMb))
+ startActivity(intent)
+ }
+
+ override fun onVmError() {}
+ },
+ )
}
fun updateSliderText(sizeMb: Long) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 0a1f0ee..01528bb 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -15,6 +15,7 @@
*/
package com.android.virtualization.terminal
+import android.app.ForegroundServiceStartNotAllowedException
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
@@ -66,10 +67,10 @@
// TODO: using lateinit for some fields to avoid null
private var virtualMachine: VirtualMachine? = null
- private var resultReceiver: ResultReceiver? = null
private var server: Server? = null
private var debianService: DebianServiceImpl? = null
private var portNotifier: PortNotifier? = null
+ private var runner: Runner? = null
interface VmLauncherServiceCallback {
fun onVmStart()
@@ -91,12 +92,22 @@
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ val resultReceiver =
+ intent.getParcelableExtra<ResultReceiver?>(
+ Intent.EXTRA_RESULT_RECEIVER,
+ ResultReceiver::class.java,
+ )
+
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()
getSystemService<NotificationManager?>(NotificationManager::class.java)
.notify(this.hashCode(), notification)
+ runner?.exitStatus?.thenAcceptAsync { success: Boolean ->
+ resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
+ stopSelf()
+ }
} else {
// If there is no Debian service or it fails to shutdown, just stop the service.
stopSelf()
@@ -114,6 +125,11 @@
val customImageConfigBuilder = json.toCustomImageConfigBuilder(this)
val displaySize = intent.getParcelableExtra(EXTRA_DISPLAY_INFO, DisplayInfo::class.java)
+ // Note: this doesn't always do the resizing. If the current image size is the same as the
+ // requested size which is rounded up to the page alignment, resizing is not done.
+ val diskSize = intent.getLongExtra(EXTRA_DISK_SIZE, image.getSize())
+ image.resize(diskSize)
+
customImageConfigBuilder.setAudioConfig(
AudioConfig.Builder().setUseSpeaker(true).setUseMicrophone(true).build()
)
@@ -122,24 +138,18 @@
}
val config = configBuilder.build()
- val runner: Runner =
+ runner =
try {
create(this, config)
} catch (e: VirtualMachineException) {
throw RuntimeException("cannot create runner", e)
}
- virtualMachine = runner.vm
- resultReceiver =
- intent.getParcelableExtra<ResultReceiver?>(
- Intent.EXTRA_RESULT_RECEIVER,
- ResultReceiver::class.java,
- )
-
+ virtualMachine = runner!!.vm
val mbc = MemBalloonController(this, virtualMachine!!)
mbc.start()
- runner.exitStatus.thenAcceptAsync { success: Boolean ->
+ runner!!.exitStatus.thenAcceptAsync { success: Boolean ->
mbc.stop()
resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
stopSelf()
@@ -394,6 +404,7 @@
private const val ACTION_START_VM_LAUNCHER_SERVICE =
"android.virtualization.START_VM_LAUNCHER_SERVICE"
const val EXTRA_DISPLAY_INFO = "EXTRA_DISPLAY_INFO"
+ const val EXTRA_DISK_SIZE = "EXTRA_DISK_SIZE"
const val ACTION_SHUTDOWN_VM: String = "android.virtualization.ACTION_SHUTDOWN_VM"
private const val RESULT_START = 0
@@ -426,7 +437,8 @@
callback: VmLauncherServiceCallback?,
notification: Notification?,
displayInfo: DisplayInfo,
- ) {
+ diskSize: Long?,
+ ): Result<Unit> {
val i = getMyIntent(context)
val resultReceiver: ResultReceiver =
object : ResultReceiver(Handler(Looper.myLooper()!!)) {
@@ -449,7 +461,15 @@
i.putExtra(Intent.EXTRA_RESULT_RECEIVER, getResultReceiverForIntent(resultReceiver))
i.putExtra(EXTRA_NOTIFICATION, notification)
i.putExtra(EXTRA_DISPLAY_INFO, displayInfo)
- context.startForegroundService(i)
+ if (diskSize != null) {
+ i.putExtra(EXTRA_DISK_SIZE, diskSize)
+ }
+ return try {
+ context.startForegroundService(i)
+ Result.success(Unit)
+ } catch (e: ForegroundServiceStartNotAllowedException) {
+ Result.failure<Unit>(e)
+ }
}
private fun getResultReceiverForIntent(r: ResultReceiver): ResultReceiver {
@@ -459,9 +479,21 @@
return ResultReceiver.CREATOR.createFromParcel(parcel).also { parcel.recycle() }
}
- fun stop(context: Context) {
+ fun stop(context: Context, callback: VmLauncherServiceCallback?) {
val i = getMyIntent(context)
i.setAction(ACTION_SHUTDOWN_VM)
+ val resultReceiver: ResultReceiver =
+ object : ResultReceiver(Handler(Looper.myLooper()!!)) {
+ override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
+ if (callback == null) {
+ return
+ }
+ when (resultCode) {
+ RESULT_STOP -> callback.onVmStop()
+ }
+ }
+ }
+ i.putExtra(Intent.EXTRA_RESULT_RECEIVER, getResultReceiverForIntent(resultReceiver))
context.startService(i)
}
}
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index 4294df4..4523572 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -625,7 +625,7 @@
stdout.transferTo(out);
stderr.transferTo(out);
String output = out.toString("UTF-8");
- Log.i(tag, "Got output : " + stdout);
+ Log.i(tag, "Got stdout + stderr : " + output);
return output;
} catch (IOException e) {
Log.e(tag, "Error executing: " + command, e);