TerminalApp: Template for offline disk resize
1: Get root_partition from app's internal directory
2: Run e2fsck and resize2fs on root partition
This isn't enabled yet.
Bug: 371491254
Test: Resize partition (increase and shrink) and verify root partitions
gets mounted in VM after resize
Change-Id: Ic277513628b16979ab274fe007d8a620d3e4f84a
Signed-off-by: Akilesh Kailash <akailash@google.com>
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index c232e37..c3a9fa8 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -17,8 +17,11 @@
import android.content.ClipData;
import android.content.ClipboardManager;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -35,6 +38,12 @@
import com.google.android.material.appbar.MaterialToolbar;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
public class MainActivity extends AppCompatActivity
implements VmLauncherServices.VmLauncherServiceCallback,
AccessibilityManager.TouchExplorationStateChangeListener {
@@ -45,6 +54,17 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ 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();
+ }
+
Toast.makeText(this, R.string.vm_creation_message, Toast.LENGTH_SHORT).show();
VmLauncherServices.startVmLauncherService(this, this);
@@ -69,6 +89,90 @@
getSystemService(AccessibilityManager.class).addTouchExplorationStateChangeListener(this);
}
+ private void diskResize(Context context, 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);
+
+ long currentSize = Os.stat(filePath).st_size;
+ runE2fsck(filePath);
+ if (sizeInBytes > currentSize) {
+ allocateSpace(file, sizeInBytes);
+ }
+
+ resizeFilesystem(filePath, sizeInBytes);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "ErrnoException during disk resize", e);
+ throw new IOException("ErrnoException during disk resize", e);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to resize disk", e);
+ throw e;
+ }
+ }
+
+ private static File getPartitionFile(Context context, String fileName)
+ throws FileNotFoundException {
+ File file = new File(context.getFilesDir(), fileName);
+ if (!file.exists()) {
+ Log.d(TAG, fileName + " - file not found");
+ throw new FileNotFoundException("File not found: " + fileName);
+ }
+ return file;
+ }
+
+ private static void allocateSpace(File file, long sizeInBytes) throws IOException {
+ try {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ FileDescriptor fd = raf.getFD();
+ Os.posix_fallocate(fd, 0, sizeInBytes);
+ raf.close();
+ Log.d(TAG, "Allocated space to: " + sizeInBytes + " bytes");
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to allocate space", e);
+ throw new IOException("Failed to allocate space", e);
+ }
+ }
+
+ private static void runE2fsck(String filePath) throws IOException {
+ try {
+ runCommand("/system/bin/e2fsck", "-f", filePath);
+ Log.d(TAG, "e2fsck completed: " + filePath);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to run e2fsck", e);
+ throw e;
+ }
+ }
+
+ private static void resizeFilesystem(String filePath, long sizeInBytes) throws IOException {
+ long sizeInMB = sizeInBytes / (1024 * 1024);
+ if (sizeInMB == 0) {
+ Log.e(TAG, "Invalid size: " + sizeInBytes + " bytes");
+ throw new IllegalArgumentException("Size cannot be zero MB");
+ }
+ String sizeArg = sizeInMB + "M";
+ try {
+ runCommand("/system/bin/resize2fs", filePath, sizeArg);
+ Log.d(TAG, "resize2fs completed: " + filePath + ", size: " + sizeArg);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to run resize2fs", e);
+ throw e;
+ }
+ }
+
+ private static void runCommand(String... command) throws IOException {
+ try {
+ Process process = new ProcessBuilder(command).redirectErrorStream(true).start();
+ process.waitFor();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IOException("Command interrupted", e);
+ }
+ }
+
@Override
protected void onDestroy() {
getSystemService(AccessibilityManager.class).removeTouchExplorationStateChangeListener(this);