Merge "virtmgr: Remove writeback=true and CachePolicy options" into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index 1212525..416f4c9 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.content.SharedPreferences;
import android.graphics.drawable.Icon;
import android.graphics.fonts.FontStyle;
import android.net.http.SslError;
@@ -85,15 +86,6 @@
super.onCreate(savedInstanceState);
boolean launchInstaller = installIfNecessary();
- try {
- // No resize for now.
- long newSizeInBytes = 0;
- diskResize(this, newSizeInBytes);
- } catch (IOException e) {
- Log.e(TAG, "Failed to resize disk", e);
- Toast.makeText(this, "Error resizing disk: " + e.getMessage(), Toast.LENGTH_LONG)
- .show();
- }
NotificationManager notificationManager = getSystemService(NotificationManager.class);
if (notificationManager.getNotificationChannel(TAG) == null) {
@@ -247,12 +239,11 @@
.start();
}
- private void diskResize(Context context, long sizeInBytes) throws IOException {
+ private void diskResize(File file, long sizeInBytes) throws IOException {
try {
if (sizeInBytes == 0) {
return;
}
- File file = getPartitionFile(context, "root_part");
String filePath = file.getAbsolutePath();
Log.d(TAG, "Disk-resize in progress for partition: " + filePath);
@@ -276,7 +267,7 @@
throws FileNotFoundException {
File file = new File(context.getFilesDir(), fileName);
if (!file.exists()) {
- Log.d(TAG, fileName + " - file not found");
+ Log.d(TAG, file.getAbsolutePath() + " - file not found");
throw new FileNotFoundException("File not found: " + fileName);
}
return file;
@@ -321,10 +312,11 @@
}
}
- private static void runCommand(String... command) throws IOException {
+ private static String runCommand(String... command) throws IOException {
try {
Process process = new ProcessBuilder(command).redirectErrorStream(true).start();
process.waitFor();
+ return new String(process.getInputStream().readAllBytes());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Command interrupted", e);
@@ -428,6 +420,9 @@
if (!InstallUtils.isImageInstalled(this)) {
return;
}
+
+ resizeDiskIfNecessary();
+
// TODO: implement intent for setting, close and tap to the notification
// Currently mock a PendingIntent for notification.
Intent intent = new Intent();
@@ -453,4 +448,57 @@
android.os.Trace.beginAsyncSection("executeTerminal", 0);
VmLauncherServices.startVmLauncherService(this, this, notification);
}
+
+ private long roundUpDiskSize(long diskSize) {
+ // Round up every disk_size_round_up_step_size_in_mb MB
+ int disk_size_step = getResources().getInteger(
+ R.integer.disk_size_round_up_step_size_in_mb) * 1024 * 1024;
+ return (long) Math.ceil(((double) diskSize) / disk_size_step) * disk_size_step;
+ }
+
+ private long getMinFilesystemSize(File file) throws IOException, NumberFormatException {
+ try {
+ String result = runCommand("/system/bin/resize2fs", "-P", file.getAbsolutePath());
+ // The return value is the number of 4k block
+ long minSize = Long.parseLong(
+ result.lines().toArray(String[]::new)[1].substring(42)) * 4 * 1024;
+ return roundUpDiskSize(minSize);
+ } catch (IOException | NumberFormatException e) {
+ Log.e(TAG, "Failed to get filesystem size", e);
+ throw e;
+ }
+ }
+
+ private static long getFilesystemSize(File file) throws ErrnoException {
+ return Os.stat(file.getAbsolutePath()).st_size;
+ }
+
+ private void resizeDiskIfNecessary() {
+ try {
+ File file = getPartitionFile(this, "root_part");
+ SharedPreferences sharedPref = this.getSharedPreferences(
+ getString(R.string.preference_file_key), Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+
+ long minDiskSize = getMinFilesystemSize(file);
+ editor.putLong(getString(R.string.preference_min_disk_size_key), minDiskSize);
+
+ long currentDiskSize = getFilesystemSize(file);
+ long newSizeInBytes = sharedPref.getLong(getString(R.string.preference_disk_size_key),
+ roundUpDiskSize(currentDiskSize));
+ editor.putLong(getString(R.string.preference_disk_size_key), newSizeInBytes);
+ editor.apply();
+
+ Log.d(TAG, "Current disk size: " + currentDiskSize);
+ Log.d(TAG, "Targeting disk size: " + newSizeInBytes);
+
+ if (newSizeInBytes != currentDiskSize) {
+ diskResize(file, newSizeInBytes);
+ }
+ } catch (FileNotFoundException e) {
+ Log.d(TAG, "No partition file");
+ } catch (IOException | ErrnoException | NumberFormatException e) {
+ Log.e(TAG, "Failed to resize disk", e);
+ }
+ }
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
index 1b14ef2..54e8ab2 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
@@ -15,45 +15,77 @@
*/
package com.android.virtualization.terminal
+import android.content.Context
+import android.content.Intent
import android.os.Bundle
import android.os.FileUtils
-import android.widget.TextView
-import android.widget.Toast
-import android.text.style.RelativeSizeSpan
-import android.text.Spannable
import android.text.SpannableString
import android.text.Spanned
-import android.text.format.Formatter
import android.text.TextUtils
+import android.text.format.Formatter
+import android.text.style.RelativeSizeSpan
+import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.google.android.material.button.MaterialButton
import com.google.android.material.slider.Slider
-
-import java.util.regex.Matcher
import java.util.regex.Pattern
class SettingsDiskResizeActivity : AppCompatActivity() {
- private val maxDiskSize: Float = 256F
+ private val maxDiskSizeMb: Float = (16 shl 10).toFloat()
private val numberPattern: Pattern = Pattern.compile("[\\d]*[\\٫.,]?[\\d]+");
- private var diskSize: Float = 104F
+
+ private fun bytesToMb(bytes: Long): Long {
+ return bytes shr 20;
+ }
+
+ private fun mbToBytes(bytes: Long): Long {
+ return bytes shl 20;
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_disk_resize)
+ val sharedPref =
+ this.getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+ var diskSizeMb =
+ bytesToMb(
+ sharedPref.getLong(
+ getString(R.string.preference_disk_size_key),
+ 0
+ )
+ ).toFloat();
+ val minDiskSizeMb =
+ bytesToMb(
+ sharedPref.getLong(
+ getString(R.string.preference_min_disk_size_key),
+ 0
+ )
+ ).toFloat();
+
val diskSizeText = findViewById<TextView>(R.id.settings_disk_resize_resize_gb_assigned)
val diskMaxSizeText = findViewById<TextView>(R.id.settings_disk_resize_resize_gb_max)
diskMaxSizeText.text = getString(R.string.settings_disk_resize_resize_gb_max_format,
- localizedFileSize(maxDiskSize));
+ localizedFileSize(maxDiskSizeMb)
+ );
val diskSizeSlider = findViewById<Slider>(R.id.settings_disk_resize_disk_size_slider)
- diskSizeSlider.setValueTo(maxDiskSize)
+ diskSizeSlider.setValueTo(maxDiskSizeMb)
val cancelButton = findViewById<MaterialButton>(R.id.settings_disk_resize_cancel_button)
val resizeButton = findViewById<MaterialButton>(R.id.settings_disk_resize_resize_button)
- diskSizeSlider.value = diskSize
+ diskSizeSlider.valueFrom = minDiskSizeMb
+ diskSizeSlider.valueTo = maxDiskSizeMb
+ diskSizeSlider.value = diskSizeMb
+ diskSizeSlider.stepSize =
+ resources.getInteger(R.integer.disk_size_round_up_step_size_in_mb).toFloat()
+ diskSizeSlider.setLabelFormatter { value: Float ->
+ localizedFileSize(value)
+ }
diskSizeText.text = enlargeFontOfNumber(
getString(R.string.settings_disk_resize_resize_gb_assigned_format,
- localizedFileSize(diskSize)))
+ localizedFileSize(diskSizeMb)
+ )
+ )
diskSizeSlider.addOnChangeListener { _, value, _ ->
diskSizeText.text = enlargeFontOfNumber(
@@ -63,24 +95,35 @@
resizeButton.isVisible = true
}
cancelButton.setOnClickListener {
- diskSizeSlider.value = diskSize
+ diskSizeSlider.value = diskSizeMb
cancelButton.isVisible = false
resizeButton.isVisible = false
}
resizeButton.setOnClickListener {
- diskSize = diskSizeSlider.value
+ diskSizeMb = diskSizeSlider.value
cancelButton.isVisible = false
resizeButton.isVisible = false
- Toast.makeText(this@SettingsDiskResizeActivity, R.string.settings_disk_resize_resize_message, Toast.LENGTH_SHORT)
- .show()
+ val editor = sharedPref.edit()
+ editor.putLong(
+ getString(R.string.preference_disk_size_key),
+ mbToBytes(diskSizeMb.toLong())
+ )
+ editor.apply()
+
+ // Restart terminal
+ val intent =
+ baseContext.packageManager.getLaunchIntentForPackage(baseContext.packageName)
+ intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ finish()
+ startActivity(intent)
}
}
- fun localizedFileSize(sizeGb: Float): String {
+ fun localizedFileSize(sizeMb: Float): String {
// formatShortFileSize() uses SI unit (i.e. kB = 1000 bytes),
- // so covert sizeGb with "GB" instead of "GIB".
- val bytes = FileUtils.parseSize(sizeGb.toLong().toString() + "GB")
+ // so covert sizeMb with "MB" instead of "MIB".
+ val bytes = FileUtils.parseSize(sizeMb.toLong().toString() + "MB")
return Formatter.formatShortFileSize(this, bytes)
}
diff --git a/android/TerminalApp/res/layout/settings_disk_resize.xml b/android/TerminalApp/res/layout/settings_disk_resize.xml
index f868b28..a41b580 100644
--- a/android/TerminalApp/res/layout/settings_disk_resize.xml
+++ b/android/TerminalApp/res/layout/settings_disk_resize.xml
@@ -42,8 +42,6 @@
android:layout_width="match_parent"
android:layout_marginBottom="36dp"
app:tickVisible="false"
- android:valueFrom="0"
- android:stepSize="4"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
@@ -53,6 +51,7 @@
android:layout_height="wrap_content"
android:text="@string/settings_disk_resize_resize_cancel"
android:visibility="invisible"
+ android:layout_marginVertical="48dp"
android:layout_marginHorizontal="8dp"
app:layout_constraintTop_toTopOf="@+id/settings_disk_resize_disk_size_slider"
app:layout_constraintBottom_toBottomOf="parent"
@@ -64,7 +63,6 @@
android:layout_height="wrap_content"
android:text="@string/settings_disk_resize_resize_restart_vm_to_apply"
android:visibility="invisible"
- android:layout_marginHorizontal="8dp"
app:layout_constraintTop_toTopOf="@+id/settings_disk_resize_disk_size_slider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
diff --git a/android/TerminalApp/res/values/integers.xml b/android/TerminalApp/res/values/integers.xml
index 0c7d2b9..e20987c 100644
--- a/android/TerminalApp/res/values/integers.xml
+++ b/android/TerminalApp/res/values/integers.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="split_min_width">720</integer>
+ <integer name="disk_size_round_up_step_size_in_mb">4</integer>
</resources>
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index f8350a0..dfe7b95 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -98,4 +98,9 @@
<string name="service_notification_content">Click to open the terminal.</string>
<!-- Notification action button for closing the virtual machine [CHAR LIMIT=none] -->
<string name="service_notification_quit_action">Close</string>
+
+ <!-- Preference Keys -->
+ <string name="preference_file_key">com.android.virtualization.terminal.PREFERENCE_FILE_KEY</string>
+ <string name="preference_disk_size_key">PREFERENCE_DISK_SIZE_KEY</string>
+ <string name="preference_min_disk_size_key">PREFERENCE_MIN_DISK_SIZE_KEY</string>
</resources>