vm_launcher_lib: Fix bug in InstallUtils#isImageInstalled()

InstallUtils#isImageInstalled() may return true while installing
if vm_config.json is untarred before before image.raw.

This fixes the issue by creating a marker file for installation
completed. This also handles the app crash in the middle.

Bug: 369740847
Test: Manully
Change-Id: Ib9eabfbe3294611a8c051afd717861853ca6e228
diff --git a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java
index eb6dd77..e9edbc8 100644
--- a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java
+++ b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java
@@ -38,17 +38,15 @@
 
     private static final String VM_CONFIG_FILENAME = "vm_config.json";
     private static final String COMPRESSED_PAYLOAD_FILENAME = "images.tar.gz";
+    private static final String INSTALLATION_COMPLETED_FILENAME = "completed";
     private static final String PAYLOAD_DIR = "linux";
 
     public static String getVmConfigPath(Context context) {
-        return new File(context.getFilesDir(), PAYLOAD_DIR)
-                .toPath()
-                .resolve(VM_CONFIG_FILENAME)
-                .toString();
+        return getInternalStorageDir(context).toPath().resolve(VM_CONFIG_FILENAME).toString();
     }
 
     public static boolean isImageInstalled(Context context) {
-        return Files.exists(Path.of(getVmConfigPath(context)));
+        return Files.exists(getInstallationCompletedPath(context));
     }
 
     private static Path getPayloadPath() {
@@ -65,6 +63,14 @@
         return Files.exists(getPayloadPath());
     }
 
+    private static File getInternalStorageDir(Context context) {
+        return new File(context.getFilesDir(), PAYLOAD_DIR);
+    }
+
+    private static Path getInstallationCompletedPath(Context context) {
+        return getInternalStorageDir(context).toPath().resolve(INSTALLATION_COMPLETED_FILENAME);
+    }
+
     public static boolean installImageFromExternalStorage(Context context) {
         if (!payloadFromExternalStorageExists()) {
             Log.d(TAG, "no artifact file from external storage");
@@ -89,10 +95,6 @@
             Log.e(TAG, "installation failed", e);
             return false;
         }
-        if (!isImageInstalled(context)) {
-            return false;
-        }
-
         if (!resolvePathInVmConfig(context)) {
             Log.d(TAG, "resolving path failed");
             try {
@@ -110,6 +112,14 @@
             Log.d(TAG, "failed to remove installed payload", e);
         }
 
+        // Create marker for installation done.
+        try {
+            File file = new File(getInstallationCompletedPath(context).toString());
+            file.createNewFile();
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to mark install completed", e);
+            return false;
+        }
         return true;
     }