Implement microdroid boot time test

Bug: 238382512
Test: atest MicrodroidBenchmarks
Change-Id: I91eef534b2ccb07bfe6bf614cbd6e57ffe22f75e
diff --git a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index 4964216..e96f58b 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -119,4 +119,44 @@
         bundle.putInt("avf_perf/microdroid/minimum_required_memory", minimum);
         mInstrumentation.sendStatus(0, bundle);
     }
+
+    @Test
+    public void testMicrodroidBootTime()
+            throws VirtualMachineException, InterruptedException, IOException {
+        assume().withMessage("Skip on CF; too slow").that(isCuttlefish()).isFalse();
+
+        final int trialCount = 10;
+
+        double sum = 0;
+        double squareSum = 0;
+        double min = Double.MAX_VALUE;
+        double max = Double.MIN_VALUE;
+        for (int i = 0; i < trialCount; i++) {
+            VirtualMachineConfig.Builder builder =
+                    mInner.newVmConfigBuilder("assets/vm_config.json");
+            VirtualMachineConfig normalConfig =
+                    builder.debugLevel(DebugLevel.NONE).memoryMib(256).build();
+            mInner.forceCreateNewVirtualMachine("test_vm_boot_time", normalConfig);
+
+            BootResult result = tryBootVm(TAG, "test_vm_boot_time");
+            assertThat(result.payloadStarted).isTrue();
+
+            double elapsedMilliseconds = result.elapsedNanoTime / 1000000.0;
+
+            sum += elapsedMilliseconds;
+            squareSum += elapsedMilliseconds * elapsedMilliseconds;
+            if (min > elapsedMilliseconds) min = elapsedMilliseconds;
+            if (max < elapsedMilliseconds) max = elapsedMilliseconds;
+        }
+
+        Bundle bundle = new Bundle();
+        double average = sum / trialCount;
+        double variance = squareSum / trialCount - average * average;
+        double stdev = Math.sqrt(variance);
+        bundle.putDouble("avf_perf/microdroid/boot_time_average_ms", average);
+        bundle.putDouble("avf_perf/microdroid/boot_time_min_ms", min);
+        bundle.putDouble("avf_perf/microdroid/boot_time_max_ms", max);
+        bundle.putDouble("avf_perf/microdroid/boot_time_stdev_ms", stdev);
+        mInstrumentation.sendStatus(0, bundle);
+    }
 }
diff --git a/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
index b4c814b..87c53a7 100644
--- a/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/MicrodroidDeviceTestBase.java
@@ -185,10 +185,12 @@
     public static class BootResult {
         public final boolean payloadStarted;
         public final int deathReason;
+        public final long elapsedNanoTime;
 
-        BootResult(boolean payloadStarted, int deathReason) {
+        BootResult(boolean payloadStarted, int deathReason, long elapsedNanoTime) {
             this.payloadStarted = payloadStarted;
             this.deathReason = deathReason;
+            this.elapsedNanoTime = elapsedNanoTime;
         }
     }
 
@@ -197,10 +199,12 @@
         VirtualMachine vm = mInner.getVirtualMachineManager().get(vmName);
         final CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
         final CompletableFuture<Integer> deathReason = new CompletableFuture<>();
+        final CompletableFuture<Long> endTime = new CompletableFuture<>();
         VmEventListener listener =
                 new VmEventListener() {
                     @Override
                     public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
+                        endTime.complete(System.nanoTime());
                         payloadStarted.complete(true);
                         forceStop(vm);
                     }
@@ -211,8 +215,11 @@
                         super.onDied(vm, reason);
                     }
                 };
+        long beginTime = System.nanoTime();
         listener.runToFinish(logTag, vm);
         return new BootResult(
-                payloadStarted.getNow(false), deathReason.getNow(DeathReason.INFRASTRUCTURE_ERROR));
+                payloadStarted.getNow(false),
+                deathReason.getNow(DeathReason.INFRASTRUCTURE_ERROR),
+                endTime.getNow(beginTime) - beginTime);
     }
 }