Modify installer to integrate disk resize

To adapt the disk resize feature, the image build script was modified to
generate partitions. This commit adapt this change as relabel the
selinux context of the installed VM image file to meet the requirement
of virtualization service

Bug: 376194294
Bug: 371491254
Test: Manually tested installation and disk resizing on pixel device
Change-Id: Ia86468e730e25c965206ce82c136474363d14edd
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
index 5967b6f..82df5c5 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
@@ -25,6 +25,7 @@
 import android.content.pm.ServiceInfo;
 import android.os.Build;
 import android.os.IBinder;
+import android.os.SELinux;
 import android.util.Log;
 
 import androidx.annotation.Nullable;
@@ -37,6 +38,7 @@
 import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
 
 import java.io.BufferedInputStream;
+import java.io.File;
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.net.URL;
@@ -45,6 +47,7 @@
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -60,6 +63,9 @@
                     ? "https://github.com/ikicha/debian_ci/releases/download/release_x86_64/images.tar.gz"
                     : "https://github.com/ikicha/debian_ci/releases/download/release_aarch64/images.tar.gz";
 
+    private static final String SELINUX_FILE_CONTEXT =
+            "u:object_r:virtualizationservice_data_file:";
+
     private final Object mLock = new Object();
 
     private Notification mNotification;
@@ -144,7 +150,9 @@
                 () -> {
                     // TODO(b/374015561): Provide progress update
                     boolean success = downloadFromSdcard() || downloadFromUrl();
-
+                    if (success) {
+                        reLabelImagesSELinuxContext();
+                    }
                     stopForeground(STOP_FOREGROUND_REMOVE);
 
                     synchronized (mLock) {
@@ -156,6 +164,24 @@
                 });
     }
 
+    private void reLabelImagesSELinuxContext() {
+        File payloadFolder = InstallUtils.getInternalStorageDir(this);
+
+        // The context should be u:object_r:privapp_data_file:s0:c35,c257,c512,c768
+        // and we want to get s0:c35,c257,c512,c768 part
+        String level = SELinux.getFileContext(payloadFolder.toString()).split(":", 4)[3];
+        String targetContext = SELINUX_FILE_CONTEXT + level;
+
+        File[] files = payloadFolder.listFiles();
+        for (File file : files) {
+            if (file.isFile() &&
+                    !Objects.equals(SELinux.getFileContext(file.toString()),
+                            targetContext)) {
+                SELinux.setFileContext(file.toString(), targetContext);
+            }
+        }
+    }
+
     private boolean downloadFromSdcard() {
         // Installing from sdcard is preferred, but only supported only in debuggable build.
         if (Build.isDebuggable()) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index c006e7b..886f6cb 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -88,6 +88,7 @@
     private ConditionVariable mBootCompleted = new ConditionVariable();
     private static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101;
     private ActivityResultLauncher<Intent> manageExternalStorageActivityResultLauncher;
+    private static int diskSizeStep;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -103,6 +104,8 @@
         }
 
         setContentView(R.layout.activity_headless);
+        diskSizeStep = getResources().getInteger(
+                R.integer.disk_size_round_up_step_size_in_mb) << 20;
 
         MaterialToolbar toolbar = (MaterialToolbar) findViewById(R.id.toolbar);
         setSupportActionBar(toolbar);
@@ -292,9 +295,9 @@
         }
     }
 
-    private static File getPartitionFile(Context context, String fileName)
+    public static File getPartitionFile(Context context, String fileName)
             throws FileNotFoundException {
-        File file = new File(context.getFilesDir(), fileName);
+        File file = new File(InstallUtils.getInternalStorageDir(context), fileName);
         if (!file.exists()) {
             Log.d(TAG, file.getAbsolutePath() + " - file not found");
             throw new FileNotFoundException("File not found: " + fileName);
@@ -514,15 +517,14 @@
         return mBootCompleted.block(timeoutMillis);
     }
 
-    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 static long roundUpDiskSize(long diskSize) {
+        // Round up every diskSizeStep MB
+        return (long) Math.ceil(((double) diskSize) / diskSizeStep) * diskSizeStep;
     }
 
-    private long getMinFilesystemSize(File file) throws IOException, NumberFormatException {
+    public static long getMinFilesystemSize(File file) throws IOException, NumberFormatException {
         try {
+            runE2fsck(file.getAbsolutePath());
             String result = runCommand("/system/bin/resize2fs", "-P", file.getAbsolutePath());
             // The return value is the number of 4k block
             long minSize = Long.parseLong(
@@ -545,12 +547,10 @@
                     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);
+            // The default partition size is 6G
             long newSizeInBytes = sharedPref.getLong(getString(R.string.preference_disk_size_key),
-                    roundUpDiskSize(currentDiskSize));
+                    6L << 30);
             editor.putLong(getString(R.string.preference_disk_size_key), newSizeInBytes);
             editor.apply();
 
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
index 54e8ab2..58be98d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
@@ -55,13 +55,10 @@
                     0
                 )
             ).toFloat();
+        val partition = MainActivity.getPartitionFile(this, "root_part")
         val minDiskSizeMb =
-            bytesToMb(
-                    sharedPref.getLong(
-                    getString(R.string.preference_min_disk_size_key),
-                    0
-                )
-            ).toFloat();
+            bytesToMb(MainActivity.getMinFilesystemSize(partition)).toFloat()
+                .coerceAtMost(diskSizeMb)
 
         val diskSizeText = findViewById<TextView>(R.id.settings_disk_resize_resize_gb_assigned)
         val diskMaxSizeText = findViewById<TextView>(R.id.settings_disk_resize_resize_gb_max)