Merge "Remove unused mk_payload"
diff --git a/pvmfw/src/debug_policy.rs b/pvmfw/src/debug_policy.rs
index 37e2af8..4cb338d 100644
--- a/pvmfw/src/debug_policy.rs
+++ b/pvmfw/src/debug_policy.rs
@@ -14,7 +14,7 @@
 
 //! Support for the debug policy overlay in pvmfw
 
-use alloc::vec;
+use alloc::{vec, vec::Vec};
 use core::ffi::CStr;
 use core::fmt;
 use libfdt::FdtError;
@@ -63,12 +63,8 @@
     fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to re-pack", e))
 }
 
-/// Dsiables ramdump by removing crashkernel from bootargs in /chosen.
-///
-/// # Safety
-///
-/// This may corrupt the input `Fdt` when error happens while editing prop value.
-unsafe fn disable_ramdump(fdt: &mut libfdt::Fdt) -> Result<(), DebugPolicyError> {
+/// Disables ramdump by removing crashkernel from bootargs in /chosen.
+fn disable_ramdump(fdt: &mut libfdt::Fdt) -> Result<(), DebugPolicyError> {
     let chosen_path = CStr::from_bytes_with_nul(b"/chosen\0").unwrap();
     let bootargs_name = CStr::from_bytes_with_nul(b"bootargs\0").unwrap();
 
@@ -129,6 +125,63 @@
     }
 }
 
+/// Enables console output by adding kernel.printk.devkmsg and kernel.console to bootargs.
+/// This uses hardcoded console name 'hvc0' and it should be match with microdroid's bootconfig.debuggable.
+fn enable_console_output(fdt: &mut libfdt::Fdt) -> Result<(), DebugPolicyError> {
+    let chosen_path = CStr::from_bytes_with_nul(b"/chosen\0").unwrap();
+    let bootargs_name = CStr::from_bytes_with_nul(b"bootargs\0").unwrap();
+
+    let chosen = match fdt
+        .node(chosen_path)
+        .map_err(|e| DebugPolicyError::Fdt("Failed to find /chosen", e))?
+    {
+        Some(node) => node,
+        None => return Ok(()),
+    };
+
+    let bootargs = match chosen
+        .getprop_str(bootargs_name)
+        .map_err(|e| DebugPolicyError::Fdt("Failed to find bootargs prop", e))?
+    {
+        Some(value) if !value.to_bytes().is_empty() => value,
+        _ => return Ok(()),
+    };
+
+    let mut new_bootargs = Vec::from(bootargs.to_bytes());
+    new_bootargs.extend_from_slice(b" printk.devkmsg=on console=hvc0\0");
+
+    // We'll set larger prop, and need to prepare some room first.
+    fdt.unpack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to unpack", e))?;
+
+    // We've checked existence of /chosen node at the beginning.
+    let mut chosen_mut = fdt.node_mut(chosen_path).unwrap().unwrap();
+    chosen_mut.setprop(bootargs_name, new_bootargs.as_slice()).map_err(|e| {
+        DebugPolicyError::OverlaidFdt("Failed to enabled console output. FDT might be corrupted", e)
+    })?;
+
+    fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to pack", e))?;
+    Ok(())
+}
+
+/// Returns true only if fdt has log prop in the /avf/guest/common node with value <1>
+fn is_console_output_enabled(fdt: &libfdt::Fdt) -> Result<bool, DebugPolicyError> {
+    let common = match fdt
+        .node(CStr::from_bytes_with_nul(b"/avf/guest/common\0").unwrap())
+        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find /avf/guest/common node", e))?
+    {
+        Some(node) => node,
+        None => return Ok(false),
+    };
+
+    match common
+        .getprop_u32(CStr::from_bytes_with_nul(b"log\0").unwrap())
+        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find log prop", e))?
+    {
+        Some(1) => Ok(true),
+        _ => Ok(false),
+    }
+}
+
 /// Handles debug policies.
 ///
 /// # Safety
@@ -146,7 +199,14 @@
     // Handles ramdump in the debug policy
     if is_ramdump_enabled(fdt)? {
         info!("ramdump is enabled by debug policy");
-        return Ok(());
+    } else {
+        disable_ramdump(fdt)?;
     }
-    disable_ramdump(fdt)
+
+    // Handles conseole output in the debug policy
+    if is_console_output_enabled(fdt)? {
+        enable_console_output(fdt)?;
+        info!("console output is enabled by debug policy");
+    }
+    Ok(())
 }
diff --git a/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl b/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
index 1eda67e..c8c8660 100644
--- a/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/IBenchmarkService.aidl
@@ -41,7 +41,4 @@
 
     /** Runs the vsock server on VM and receives data. */
     void runVsockServerAndReceiveData(int serverFd, int numBytesToReceive);
-
-    /** Adds two numbers and returns the result. */
-    int add(int a, int b);
 }
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
index 9d2b6c7..dac4993 100644
--- a/tests/benchmark/Android.bp
+++ b/tests/benchmark/Android.bp
@@ -19,6 +19,7 @@
     jni_libs: [
         "MicrodroidBenchmarkNativeLib",
         "MicrodroidIdleNativeLib",
+        "MicrodroidTestNativeLib",
         "libiovsock_host_jni",
     ],
     jni_uses_platform_apis: true,
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 fd0158b..4b11d77 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -29,6 +29,8 @@
 import android.app.Instrumentation;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseInputStream;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
 import android.os.Process;
 import android.os.RemoteException;
 import android.system.virtualmachine.VirtualMachine;
@@ -40,6 +42,7 @@
 import com.android.microdroid.test.common.ProcessUtil;
 import com.android.microdroid.test.device.MicrodroidDeviceTestBase;
 import com.android.microdroid.testservice.IBenchmarkService;
+import com.android.microdroid.testservice.ITestService;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -48,8 +51,14 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -57,7 +66,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.OptionalLong;
-import java.util.Random;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Function;
 
@@ -72,7 +80,8 @@
 
     private static final String APEX_ETC_FS = "/apex/com.android.virt/etc/fs/";
     private static final double SIZE_MB = 1024.0 * 1024.0;
-    private static final double NANO_TO_MILLI = 1000000.0;
+    private static final double NANO_TO_MILLI = 1_000_000.0;
+    private static final double NANO_TO_MICRO = 1_000.0;
     private static final String MICRODROID_IMG_PREFIX = "microdroid_";
     private static final String MICRODROID_IMG_SUFFIX = ".img";
 
@@ -569,64 +578,113 @@
     }
 
     @Test
-    public void testVsockRpcBinderLatency() throws Exception {
+    public void testRpcBinderLatency() throws Exception {
+        final int NUM_WARMUPS = 10;
+        final int NUM_REQUESTS = 10_000;
+
         VirtualMachineConfig config =
                 newVmConfigBuilder()
-                        .setPayloadConfigPath("assets/vm_config_io.json")
+                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
                         .setDebugLevel(DEBUG_LEVEL_NONE)
                         .build();
 
-        List<Double> requestLatencies = new ArrayList<>(IO_TEST_TRIAL_COUNT);
+        List<Double> requestLatencies = new ArrayList<>(IO_TEST_TRIAL_COUNT * NUM_REQUESTS);
         for (int i = 0; i < IO_TEST_TRIAL_COUNT; ++i) {
-            String vmName = "test_vm_request_" + i;
-            VirtualMachine vm = forceCreateNewVirtualMachine(vmName, config);
-            BenchmarkVmListener.create(new VsockRpcBinderLatencyListener(requestLatencies))
-                    .runToFinish(TAG, vm);
+            VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_latency" + i, config);
+            TestResults testResults =
+                    runVmTestService(
+                            TAG,
+                            vm,
+                            (ts, tr) -> {
+                                // Correctness check
+                                tr.mAddInteger = ts.addInteger(123, 456);
+
+                                // Warmup
+                                for (int j = 0; j < NUM_WARMUPS; j++) {
+                                    ts.addInteger(j, j + 1);
+                                }
+
+                                // Count Fibonacci numbers, measure latency.
+                                int a = 0;
+                                int b = 1;
+                                int c;
+                                tr.mTimings = new long[NUM_REQUESTS];
+                                for (int j = 0; j < NUM_REQUESTS; j++) {
+                                    long start = System.nanoTime();
+                                    c = ts.addInteger(a, b);
+                                    tr.mTimings[j] = System.nanoTime() - start;
+                                    a = b;
+                                    b = c;
+                                }
+                            });
+            testResults.assertNoException();
+            assertThat(testResults.mAddInteger).isEqualTo(579);
+            for (long duration : testResults.mTimings) {
+                requestLatencies.add((double) duration / NANO_TO_MICRO);
+            }
         }
-        reportMetrics(requestLatencies, "vsock/rpcbinder/request_latency", "ms");
+        reportMetrics(requestLatencies, "latency/rpcbinder", "us");
     }
 
-    private static class VsockRpcBinderLatencyListener
-            implements BenchmarkVmListener.InnerListener {
-        private static final int NUM_REQUESTS = 10000;
-        private static final int NUM_WARMUP_REQUESTS = 10;
+    @Test
+    public void testVsockLatency() throws Exception {
+        final int NUM_WARMUPS = 10;
+        final int NUM_REQUESTS = 10_000;
 
-        private final List<Double> mResults;
+        VirtualMachineConfig config =
+                newVmConfigBuilder()
+                        .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+                        .setDebugLevel(DEBUG_LEVEL_NONE)
+                        .build();
 
-        VsockRpcBinderLatencyListener(List<Double> results) {
-            mResults = results;
-        }
+        List<Double> requestLatencies = new ArrayList<>(IO_TEST_TRIAL_COUNT * NUM_REQUESTS);
+        for (int i = 0; i < IO_TEST_TRIAL_COUNT; ++i) {
+            VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_latency" + i, config);
+            TestResults testResults =
+                    runVmTestService(
+                            TAG,
+                            vm,
+                            (ts, tr) -> {
+                                ts.runEchoReverseServer();
+                                ParcelFileDescriptor pfd =
+                                        vm.connectVsock(ITestService.ECHO_REVERSE_PORT);
+                                try (InputStream input = new AutoCloseInputStream(pfd);
+                                        OutputStream output = new AutoCloseOutputStream(pfd)) {
+                                    BufferedReader reader =
+                                            new BufferedReader(new InputStreamReader(input));
+                                    Writer writer = new OutputStreamWriter(output);
 
-        @Override
-        public void onPayloadReady(VirtualMachine vm, IBenchmarkService benchmarkService)
-                throws RemoteException {
-            // Warm up a few times.
-            Random rand = new Random();
-            for (int i = 0; i < NUM_WARMUP_REQUESTS; i++) {
-                int a = rand.nextInt();
-                int b = rand.nextInt();
-                int c = benchmarkService.add(a, b);
-                assertThat(c).isEqualTo(a + b);
-            }
+                                    // Correctness check.
+                                    writer.write("hello\n");
+                                    writer.flush();
+                                    tr.mFileContent = reader.readLine().trim();
 
-            // Use the VM to compute Fibonnacci numbers, save timestamps between requests.
-            int a = 0;
-            int b = 1;
-            int c;
-            long timestamps[] = new long[NUM_REQUESTS + 1];
-            for (int i = 0; i < NUM_REQUESTS; i++) {
-                timestamps[i] = System.nanoTime();
-                c = benchmarkService.add(a, b);
-                a = b;
-                b = c;
-            }
-            timestamps[NUM_REQUESTS] = System.nanoTime();
+                                    // Warmup.
+                                    for (int j = 0; j < NUM_WARMUPS; ++j) {
+                                        String text = "test" + j + "\n";
+                                        writer.write(text);
+                                        writer.flush();
+                                        reader.readLine();
+                                    }
 
-            // Log individual request latencies.
-            for (int i = 0; i < NUM_REQUESTS; i++) {
-                long diff = timestamps[i + 1] - timestamps[i];
-                mResults.add((double) diff / NANO_TO_MILLI);
+                                    // Measured requests.
+                                    tr.mTimings = new long[NUM_REQUESTS];
+                                    for (int j = 0; j < NUM_REQUESTS; j++) {
+                                        String text = "test" + j + "\n";
+                                        long start = System.nanoTime();
+                                        writer.write(text);
+                                        writer.flush();
+                                        reader.readLine();
+                                        tr.mTimings[j] = System.nanoTime() - start;
+                                    }
+                                }
+                            });
+            testResults.assertNoException();
+            assertThat(testResults.mFileContent).isEqualTo("olleh");
+            for (long duration : testResults.mTimings) {
+                requestLatencies.add((double) duration / NANO_TO_MICRO);
             }
         }
+        reportMetrics(requestLatencies, "latency/vsock", "us");
     }
 }
diff --git a/tests/benchmark/src/native/benchmarkbinary.cpp b/tests/benchmark/src/native/benchmarkbinary.cpp
index 022698f..6cfc71d 100644
--- a/tests/benchmark/src/native/benchmarkbinary.cpp
+++ b/tests/benchmark/src/native/benchmarkbinary.cpp
@@ -96,11 +96,6 @@
         return resultStatus(res);
     }
 
-    ndk::ScopedAStatus add(int32_t a, int32_t b, int32_t* out) override {
-        *out = a + b;
-        return ndk::ScopedAStatus::ok();
-    }
-
 private:
     /**
      * Measures the read rate for reading the given file.
diff --git a/tests/helper/Android.bp b/tests/helper/Android.bp
index 61c5dcd..c9eafad 100644
--- a/tests/helper/Android.bp
+++ b/tests/helper/Android.bp
@@ -15,6 +15,7 @@
     static_libs: [
         "androidx.test.runner",
         "androidx.test.ext.junit",
+        "com.android.microdroid.testservice-java",
         "MicrodroidTestHelper",
         "truth-prebuilt",
     ],
diff --git a/tests/helper/src/java/com/android/microdroid/test/common/MetricsProcessor.java b/tests/helper/src/java/com/android/microdroid/test/common/MetricsProcessor.java
index b6bc479..42eb6a1 100644
--- a/tests/helper/src/java/com/android/microdroid/test/common/MetricsProcessor.java
+++ b/tests/helper/src/java/com/android/microdroid/test/common/MetricsProcessor.java
@@ -16,6 +16,8 @@
 
 package com.android.microdroid.test.common;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -41,29 +43,42 @@
      */
     public Map<String, Double> computeStats(List<? extends Number> metrics, String name,
             String unit) {
+        List<Double> values = new ArrayList<>(metrics.size());
+        for (Number metric : metrics) {
+            values.add(metric.doubleValue());
+        }
+        Collections.sort(values);
+
         double sum = 0;
         double min = Double.MAX_VALUE;
         double max = Double.MIN_VALUE;
-        for (Number metric : metrics) {
-            double d = metric.doubleValue();
+        for (Double d : values) {
             sum += d;
             if (min > d) min = d;
             if (max < d) max = d;
         }
-        double avg = sum / metrics.size();
+        double avg = sum / values.size();
         double sqSum = 0;
-        for (Number metric : metrics) {
-            double d = metric.doubleValue();
+        for (Double d : values) {
             sqSum += (d - avg) * (d - avg);
         }
-        double stdDev = Math.sqrt(sqSum / (metrics.size() - 1));
-
+        double stdDev = Math.sqrt(sqSum / (values.size() - 1));
+        double median = Double.MIN_VALUE;
+        if (values.size() > 0) {
+            int rank = values.size() / 2;
+            if (values.size() % 2 == 0) {
+                median = (values.get(rank - 1) + values.get(rank)) / 2;
+            } else {
+                median = values.get(rank);
+            }
+        }
         Map<String, Double> stats = new HashMap<String, Double>();
         String prefix = mPrefix + name;
         stats.put(prefix + "_min_" + unit, min);
         stats.put(prefix + "_max_" + unit, max);
         stats.put(prefix + "_average_" + unit, avg);
         stats.put(prefix + "_stdev_" + unit, stdDev);
+        stats.put(prefix + "_median_" + unit, median);
         return stats;
     }
 }
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index 9ec36b3..be3c1da 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -17,6 +17,7 @@
 
 import static android.content.pm.PackageManager.FEATURE_VIRTUALIZATION_FRAMEWORK;
 
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.TruthJUnit.assume;
 
 import android.app.Instrumentation;
@@ -38,6 +39,7 @@
 
 import com.android.microdroid.test.common.DeviceProperties;
 import com.android.microdroid.test.common.MetricsProcessor;
+import com.android.microdroid.testservice.ITestService;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
@@ -428,4 +430,104 @@
             throw new RuntimeException("Failed to run the command.");
         }
     }
+
+    protected static class TestResults {
+        public Exception mException;
+        public Integer mAddInteger;
+        public String mAppRunProp;
+        public String mSublibRunProp;
+        public String mExtraApkTestProp;
+        public String mApkContentsPath;
+        public String mEncryptedStoragePath;
+        public String[] mEffectiveCapabilities;
+        public String mFileContent;
+        public byte[] mBcc;
+        public long[] mTimings;
+
+        public void assertNoException() {
+            if (mException != null) {
+                // Rethrow, wrapped in a new exception, so we get stack traces of the original
+                // failure as well as the body of the test.
+                throw new RuntimeException(mException);
+            }
+        }
+    }
+
+    protected TestResults runVmTestService(
+            String logTag, VirtualMachine vm, RunTestsAgainstTestService testsToRun)
+            throws Exception {
+        CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
+        CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
+        CompletableFuture<Boolean> payloadFinished = new CompletableFuture<>();
+        TestResults testResults = new TestResults();
+        VmEventListener listener =
+                new VmEventListener() {
+                    ITestService mTestService = null;
+
+                    private void initializeTestService(VirtualMachine vm) {
+                        try {
+                            mTestService =
+                                    ITestService.Stub.asInterface(
+                                            vm.connectToVsockServer(ITestService.SERVICE_PORT));
+                            // Make sure linkToDeath works, and include it in the log in case it's
+                            // helpful.
+                            mTestService
+                                    .asBinder()
+                                    .linkToDeath(
+                                            () -> Log.i(logTag, "ITestService binder died"), 0);
+                        } catch (Exception e) {
+                            testResults.mException = e;
+                        }
+                    }
+
+                    private void testVMService(VirtualMachine vm) {
+                        try {
+                            if (mTestService == null) initializeTestService(vm);
+                            testsToRun.runTests(mTestService, testResults);
+                        } catch (Exception e) {
+                            testResults.mException = e;
+                        }
+                    }
+
+                    private void quitVMService() {
+                        try {
+                            mTestService.quit();
+                        } catch (Exception e) {
+                            testResults.mException = e;
+                        }
+                    }
+
+                    @Override
+                    public void onPayloadReady(VirtualMachine vm) {
+                        Log.i(logTag, "onPayloadReady");
+                        payloadReady.complete(true);
+                        testVMService(vm);
+                        quitVMService();
+                    }
+
+                    @Override
+                    public void onPayloadStarted(VirtualMachine vm) {
+                        Log.i(logTag, "onPayloadStarted");
+                        payloadStarted.complete(true);
+                    }
+
+                    @Override
+                    public void onPayloadFinished(VirtualMachine vm, int exitCode) {
+                        Log.i(logTag, "onPayloadFinished: " + exitCode);
+                        payloadFinished.complete(true);
+                        forceStop(vm);
+                    }
+                };
+
+        listener.runToFinish(logTag, vm);
+        assertThat(payloadStarted.getNow(false)).isTrue();
+        assertThat(payloadReady.getNow(false)).isTrue();
+        assertThat(payloadFinished.getNow(false)).isTrue();
+        return testResults;
+    }
+
+    @FunctionalInterface
+    protected interface RunTestsAgainstTestService {
+        void runTests(ITestService testService, TestResults testResults) throws Exception;
+    }
 }
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index f1e5054..d217c00 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -22,6 +22,20 @@
     out: ["avf_debug_policy_without_ramdump.dtbo"],
 }
 
+genrule {
+    name: "test_avf_debug_policy_with_console_output",
+    defaults: ["test_avf_debug_policy_overlay"],
+    srcs: ["assets/avf_debug_policy_with_console_output.dts"],
+    out: ["avf_debug_policy_with_console_output.dtbo"],
+}
+
+genrule {
+    name: "test_avf_debug_policy_without_console_output",
+    defaults: ["test_avf_debug_policy_overlay"],
+    srcs: ["assets/avf_debug_policy_without_console_output.dts"],
+    out: ["avf_debug_policy_without_console_output.dtbo"],
+}
+
 java_test_host {
     name: "MicrodroidHostTestCases",
     srcs: ["java/**/*.java"],
@@ -48,6 +62,8 @@
         ":pvmfw_test",
         ":test_avf_debug_policy_with_ramdump",
         ":test_avf_debug_policy_without_ramdump",
+        ":test_avf_debug_policy_with_console_output",
+        ":test_avf_debug_policy_without_console_output",
         "assets/bcc.dat",
     ],
     data_native_bins: [
diff --git a/tests/hostside/assets/avf_debug_policy_with_console_output.dts b/tests/hostside/assets/avf_debug_policy_with_console_output.dts
new file mode 100644
index 0000000..8cf19d6
--- /dev/null
+++ b/tests/hostside/assets/avf_debug_policy_with_console_output.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+    fragment@avf {
+        target-path = "/";
+
+        __overlay__ {
+            avf {
+                guest {
+                    common {
+                        log = <1>;
+                    };
+                };
+            };
+        };
+    };
+};
\ No newline at end of file
diff --git a/tests/hostside/assets/avf_debug_policy_without_console_output.dts b/tests/hostside/assets/avf_debug_policy_without_console_output.dts
new file mode 100644
index 0000000..da6400c
--- /dev/null
+++ b/tests/hostside/assets/avf_debug_policy_without_console_output.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+    fragment@avf {
+        target-path = "/";
+
+        __overlay__ {
+            avf {
+                guest {
+                    common {
+                        log = <0>;
+                    };
+                };
+            };
+        };
+    };
+};
\ No newline at end of file
diff --git a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
index bda52dd..1ada5a1 100644
--- a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
@@ -19,6 +19,7 @@
 import static com.android.tradefed.device.TestDevice.MicrodroidBuilder;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assume.assumeTrue;
 
@@ -32,6 +33,7 @@
 import com.android.tradefed.device.TestDevice;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.FileUtil;
 
 import org.junit.After;
@@ -41,6 +43,7 @@
 
 import java.io.File;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 import java.io.FileNotFoundException;
 
 /** Tests debug policy of pvmfw.bin with custom debug policy */
@@ -50,13 +53,16 @@
     @NonNull private static final String BCC_FILE_NAME = "bcc.dat";
     @NonNull private static final String PACKAGE_FILE_NAME = "MicrodroidTestApp.apk";
     @NonNull private static final String PACKAGE_NAME = "com.android.microdroid.test";
-    @NonNull private static final String MICRODROID_DEBUG_LEVEL = "full";
+    @NonNull private static final String MICRODROID_DEBUG_FULL = "full";
     @NonNull private static final String MICRODROID_CONFIG_PATH = "assets/vm_config_apex.json";
-    private static final int BOOT_COMPLETE_TIMEOUT = 30000; // 30 seconds
+    @NonNull private static final String MICRODROID_LOG_PATH = TEST_ROOT + "log.txt";
+    @NonNull private static final String MICRODROID_CONSOLE_PATH = TEST_ROOT + "console.txt";
+    private static final int BOOT_COMPLETE_TIMEOUT_MS = 30000; // 30 seconds
+    private static final int CONSOLE_OUTPUT_WAIT_MS = 5000; // 5 seconds
 
     @NonNull private static final String CUSTOM_PVMFW_FILE_PREFIX = "pvmfw";
     @NonNull private static final String CUSTOM_PVMFW_FILE_SUFFIX = ".bin";
-    @NonNull private static final String CUSTOM_PVMFW_IMG_PATH = TEST_ROOT + "/" + PVMFW_FILE_NAME;
+    @NonNull private static final String CUSTOM_PVMFW_IMG_PATH = TEST_ROOT + PVMFW_FILE_NAME;
     @NonNull private static final String CUSTOM_PVMFW_IMG_PATH_PROP = "hypervisor.pvmfw.path";
 
     @NonNull private static final String MICRODROID_CMDLINE_PATH = "/proc/cmdline";
@@ -162,6 +168,30 @@
                 .isEqualTo(HEX_STRING_ZERO);
     }
 
+    @Test
+    public void testConsoleOutput() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_console_output.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        CommandResult result = tryLaunchProtectedNonDebuggableVm();
+
+        assertWithMessage("Microdroid's console message should have been enabled")
+                .that(hasConsoleOutput(result))
+                .isTrue();
+    }
+
+    @Test
+    public void testNoConsoleOutput() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_console_output.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        CommandResult result = tryLaunchProtectedNonDebuggableVm();
+
+        assertWithMessage("Microdroid's console message shouldn't have been disabled")
+                .that(hasConsoleOutput(result))
+                .isFalse();
+    }
+
     @NonNull
     private String readMicrodroidFileAsString(@NonNull String path)
             throws DeviceNotAvailableException {
@@ -184,18 +214,50 @@
                 .build();
     }
 
+    @NonNull
+    private boolean hasConsoleOutput(CommandResult result) throws DeviceNotAvailableException {
+        return result.getStdout().contains("Run /init as init process");
+    }
+
     private ITestDevice launchProtectedVmAndWaitForBootCompleted()
             throws DeviceNotAvailableException {
         mMicrodroidDevice =
                 MicrodroidBuilder.fromDevicePath(
                                 getPathForPackage(PACKAGE_NAME), MICRODROID_CONFIG_PATH)
-                        .debugLevel(MICRODROID_DEBUG_LEVEL)
+                        .debugLevel(MICRODROID_DEBUG_FULL)
                         .protectedVm(/* protectedVm= */ true)
                         .addBootFile(mCustomPvmfwBinFileOnHost, PVMFW_FILE_NAME)
                         .build(mAndroidDevice);
-        assertThat(mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT)).isTrue();
+        assertThat(mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT_MS)).isTrue();
         assertThat(mMicrodroidDevice.enableAdbRoot()).isTrue();
-
         return mMicrodroidDevice;
     }
+
+    // Try to launch protected non-debuggable VM for a while and quit.
+    // Non-debuggable VM doesn't enable adb, so there's no ITestDevice instance of it.
+    private CommandResult tryLaunchProtectedNonDebuggableVm() throws DeviceNotAvailableException {
+        // Can't use MicrodroidBuilder because it expects adb connection
+        // but non-debuggable VM doesn't enable adb.
+        CommandRunner runner = new CommandRunner(mAndroidDevice);
+        runner.run("mkdir", "-p", TEST_ROOT);
+        mAndroidDevice.pushFile(mCustomPvmfwBinFileOnHost, TEST_ROOT + PVMFW_FILE_NAME);
+
+        // This will fail because app wouldn't finish itself.
+        // But let's run the app once and get logs.
+        String command =
+                String.join(
+                        " ",
+                        "/apex/com.android.virt/bin/vm",
+                        "run-app",
+                        "--log",
+                        MICRODROID_LOG_PATH,
+                        "--protected",
+                        getPathForPackage(PACKAGE_NAME),
+                        TEST_ROOT + "idsig",
+                        TEST_ROOT + "instance.img",
+                        "--config-path",
+                        MICRODROID_CONFIG_PATH);
+        return mAndroidDevice.executeShellV2Command(
+                command, CONSOLE_OUTPUT_WAIT_MS, TimeUnit.MILLISECONDS, /* retryAttempts= */ 0);
+    }
 }
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index a66f9c3..f3f1252 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -51,7 +51,6 @@
 import android.system.virtualmachine.VirtualMachineDescriptor;
 import android.system.virtualmachine.VirtualMachineException;
 import android.system.virtualmachine.VirtualMachineManager;
-import android.util.Log;
 
 import com.android.compatibility.common.util.CddTest;
 import com.android.microdroid.test.device.MicrodroidDeviceTestBase;
@@ -147,6 +146,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             tr.mAddInteger = ts.addInteger(123, 456);
@@ -192,7 +192,7 @@
         VirtualMachine vm = forceCreateNewVirtualMachine("test_vm", config);
 
         TestResults testResults =
-                runVmTestService(vm, (ts, tr) -> tr.mAddInteger = ts.addInteger(37, 73));
+                runVmTestService(TAG, vm, (ts, tr) -> tr.mAddInteger = ts.addInteger(37, 73));
         testResults.assertNoException();
         assertThat(testResults.mAddInteger).isEqualTo(37 + 73);
     }
@@ -375,6 +375,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (service, results) -> {
                             service.runEchoReverseServer();
@@ -687,7 +688,8 @@
                 forceCreateNewVirtualMachine("test_vm_config_requires_permission", config);
 
         SecurityException e =
-                assertThrows(SecurityException.class, () -> runVmTestService(vm, (ts, tr) -> {}));
+                assertThrows(
+                        SecurityException.class, () -> runVmTestService(TAG, vm, (ts, tr) -> {}));
         assertThat(e).hasMessageThat()
                 .contains("android.permission.USE_CUSTOM_VIRTUAL_MACHINE permission");
     }
@@ -772,6 +774,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             tr.mApkContentsPath = ts.getApkContentsPath();
@@ -807,6 +810,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             tr.mExtraApkTestProp =
@@ -994,6 +998,7 @@
         VirtualMachine vm = forceCreateNewVirtualMachine("bcc_vm", normalConfig);
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (service, results) -> {
                             results.mBcc = service.getBcc();
@@ -1279,6 +1284,7 @@
         // Run something to make the instance.img different with the initialized one.
         TestResults origTestResults =
                 runVmTestService(
+                        TAG,
                         vmOrig,
                         (ts, tr) -> {
                             tr.mAddInteger = ts.addInteger(123, 456);
@@ -1305,6 +1311,7 @@
         assertThat(vmImport).isEqualTo(vmm.get(vmNameImport));
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vmImport,
                         (ts, tr) -> {
                             tr.mAddInteger = ts.addInteger(123, 456);
@@ -1331,6 +1338,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             tr.mEncryptedStoragePath = ts.getEncryptedStoragePath();
@@ -1355,6 +1363,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             ts.writeToFile(
@@ -1413,6 +1422,7 @@
 
         final TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             tr.mEffectiveCapabilities = ts.getEffectiveCapabilities();
@@ -1437,6 +1447,7 @@
         VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_a", config);
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             ts.writeToFile(
@@ -1449,6 +1460,7 @@
         // stopped the VM
         testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (ts, tr) -> {
                             tr.mFileContent = ts.readFromFile("/mnt/encryptedstore/test_file");
@@ -1472,6 +1484,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         vm,
                         (testService, ts) -> {
                             ts.mFileContent = testService.readFromFile("/mnt/apk/assets/file.txt");
@@ -1516,7 +1529,7 @@
                         .build();
         final VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_logcat", vmConfig);
 
-        runVmTestService(vm, (service, results) -> {});
+        runVmTestService(TAG, vm, (service, results) -> {});
 
         // only check logs printed after this test
         Process logcatProcess =
@@ -1565,6 +1578,7 @@
         try (VirtualMachine vm = forceCreateNewVirtualMachine("vm_from_another_app", config)) {
             TestResults results =
                     runVmTestService(
+                            TAG,
                             vm,
                             (ts, tr) -> {
                                 tr.mAddInteger = ts.addInteger(101, 303);
@@ -1587,7 +1601,7 @@
 
         VirtualMachine originalVm = forceCreateNewVirtualMachine("original_vm", config);
         // Just start & stop the VM.
-        runVmTestService(originalVm, (ts, tr) -> {});
+        runVmTestService(TAG, originalVm, (ts, tr) -> {});
 
         // Now create the descriptor and manually parcel & unparcel it.
         VirtualMachineDescriptor vmDescriptor = toParcelFromParcel(originalVm.toDescriptor());
@@ -1606,7 +1620,7 @@
                 "instance.img", "original_vm", "import_vm_from_unparceled");
 
         // Check that we can start and stop imported vm as well
-        runVmTestService(importVm, (ts, tr) -> {});
+        runVmTestService(TAG, importVm, (ts, tr) -> {});
     }
 
     @Test
@@ -1625,6 +1639,7 @@
         {
             TestResults testResults =
                     runVmTestService(
+                            TAG,
                             originalVm,
                             (ts, tr) -> {
                                 ts.writeToFile("not a secret!", "/mnt/encryptedstore/secret.txt");
@@ -1652,6 +1667,7 @@
 
         TestResults testResults =
                 runVmTestService(
+                        TAG,
                         importVm,
                         (ts, tr) -> {
                             tr.mFileContent = ts.readFromFile("/mnt/encryptedstore/secret.txt");
@@ -1677,7 +1693,7 @@
 
         VirtualMachine vm = forceCreateNewVirtualMachine("vm_to_share", config);
         // Just start & stop the VM.
-        runVmTestService(vm, (ts, tr) -> {});
+        runVmTestService(TAG, vm, (ts, tr) -> {});
         // Get a descriptor that we will share with another app (VM_SHARE_APP_PACKAGE_NAME)
         VirtualMachineDescriptor vmDesc = vm.toDescriptor();
 
@@ -1686,6 +1702,7 @@
                 new ComponentName(
                         VM_SHARE_APP_PACKAGE_NAME,
                         "com.android.microdroid.test.sharevm.VmShareServiceImpl"));
+        serviceIntent.setAction("com.android.microdroid.test.sharevm.VmShareService");
 
         VmShareServiceConnection connection = new VmShareServiceConnection();
         boolean ret = ctx.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE);
@@ -1726,6 +1743,7 @@
         VirtualMachine vm = forceCreateNewVirtualMachine("vm_to_share", config);
         // Just start & stop the VM.
         runVmTestService(
+                TAG,
                 vm,
                 (ts, tr) -> {
                     ts.writeToFile(EXAMPLE_STRING, "/mnt/encryptedstore/private.key");
@@ -1738,6 +1756,7 @@
                 new ComponentName(
                         VM_SHARE_APP_PACKAGE_NAME,
                         "com.android.microdroid.test.sharevm.VmShareServiceImpl"));
+        serviceIntent.setAction("com.android.microdroid.test.sharevm.VmShareService");
 
         VmShareServiceConnection connection = new VmShareServiceConnection();
         boolean ret = ctx.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE);
@@ -1835,102 +1854,4 @@
                 .that(KERNEL_VERSION)
                 .isNotEqualTo("5.4");
     }
-
-    static class TestResults {
-
-        Exception mException;
-        Integer mAddInteger;
-        String mAppRunProp;
-        String mSublibRunProp;
-        String mExtraApkTestProp;
-        String mApkContentsPath;
-        String mEncryptedStoragePath;
-        String[] mEffectiveCapabilities;
-        String mFileContent;
-        byte[] mBcc;
-
-        void assertNoException() {
-            if (mException != null) {
-                // Rethrow, wrapped in a new exception, so we get stack traces of the original
-                // failure as well as the body of the test.
-                throw new RuntimeException(mException);
-            }
-        }
-    }
-
-    private TestResults runVmTestService(VirtualMachine vm, RunTestsAgainstTestService testsToRun)
-            throws Exception {
-        CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
-        CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
-        CompletableFuture<Boolean> payloadFinished = new CompletableFuture<>();
-        TestResults testResults = new TestResults();
-        VmEventListener listener =
-                new VmEventListener() {
-                    ITestService mTestService = null;
-
-                    private void initializeTestService(VirtualMachine vm) {
-                        try {
-                            mTestService =
-                                    ITestService.Stub.asInterface(
-                                            vm.connectToVsockServer(ITestService.SERVICE_PORT));
-                            // Make sure linkToDeath works, and include it in the log in case it's
-                            // helpful.
-                            mTestService
-                                    .asBinder()
-                                    .linkToDeath(() -> Log.i(TAG, "ITestService binder died"), 0);
-                        } catch (Exception e) {
-                            testResults.mException = e;
-                        }
-                    }
-
-                    private void testVMService(VirtualMachine vm) {
-                        try {
-                            if (mTestService == null) initializeTestService(vm);
-                            testsToRun.runTests(mTestService, testResults);
-                        } catch (Exception e) {
-                            testResults.mException = e;
-                        }
-                    }
-
-                    private void quitVMService() {
-                        try {
-                            mTestService.quit();
-                        } catch (Exception e) {
-                            testResults.mException = e;
-                        }
-                    }
-
-                    @Override
-                    public void onPayloadReady(VirtualMachine vm) {
-                        Log.i(TAG, "onPayloadReady");
-                        payloadReady.complete(true);
-                        testVMService(vm);
-                        quitVMService();
-                    }
-
-                    @Override
-                    public void onPayloadStarted(VirtualMachine vm) {
-                        Log.i(TAG, "onPayloadStarted");
-                        payloadStarted.complete(true);
-                    }
-
-                    @Override
-                    public void onPayloadFinished(VirtualMachine vm, int exitCode) {
-                        Log.i(TAG, "onPayloadFinished: " + exitCode);
-                        payloadFinished.complete(true);
-                        forceStop(vm);
-                    }
-                };
-
-        listener.runToFinish(TAG, vm);
-        assertThat(payloadStarted.getNow(false)).isTrue();
-        assertThat(payloadReady.getNow(false)).isTrue();
-        assertThat(payloadFinished.getNow(false)).isTrue();
-        return testResults;
-    }
-
-    @FunctionalInterface
-    interface RunTestsAgainstTestService {
-        void runTests(ITestService testService, TestResults testResults) throws Exception;
-    }
 }
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 365ea75..19d6cd4 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -84,28 +84,26 @@
         return ErrnoError() << "Failed to fdopen";
     }
 
-    char* line = nullptr;
-    size_t size = 0;
-    if (getline(&line, &size, input) < 0) {
-        return ErrnoError() << "Failed to read";
+    // Run forever, reverse one line at a time.
+    while (true) {
+        char* line = nullptr;
+        size_t size = 0;
+        if (getline(&line, &size, input) < 0) {
+            return ErrnoError() << "Failed to read";
+        }
+
+        std::string_view original = line;
+        if (!original.empty() && original.back() == '\n') {
+            original = original.substr(0, original.size() - 1);
+        }
+
+        std::string reversed(original.rbegin(), original.rend());
+        reversed += "\n";
+
+        if (write(connect_fd, reversed.data(), reversed.size()) < 0) {
+            return ErrnoError() << "Failed to write";
+        }
     }
-
-    if (fclose(input) != 0) {
-        return ErrnoError() << "Failed to fclose";
-    }
-
-    std::string_view original = line;
-    if (!original.empty() && original.back() == '\n') {
-        original = original.substr(0, original.size() - 1);
-    }
-
-    std::string reversed(original.rbegin(), original.rend());
-
-    if (write(connect_fd, reversed.data(), reversed.size()) < 0) {
-        return ErrnoError() << "Failed to write";
-    }
-
-    return {};
 }
 
 Result<void> start_echo_reverse_server() {
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index aceb319..1781007 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -19,6 +19,7 @@
     write_vm_booted_stats, write_vm_creation_stats};
 use crate::composite::make_composite_image;
 use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmContext, VmInstance, VmState};
+use crate::debug_config::should_prepare_console_output;
 use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images};
 use crate::selinux::{getfilecon, SeContext};
 use android_os_permissions_aidl::aidl::android::os::IPermissionController;
@@ -978,13 +979,6 @@
     })
 }
 
-fn is_debuggable(config: &VirtualMachineConfig) -> bool {
-    match config {
-        VirtualMachineConfig::AppConfig(config) => config.debugLevel != DebugLevel::NONE,
-        _ => false,
-    }
-}
-
 fn is_protected(config: &VirtualMachineConfig) -> bool {
     match config {
         VirtualMachineConfig::RawConfig(config) => config.protectedVm,
@@ -1031,7 +1025,11 @@
         return Ok(Some(clone_file(fd)?));
     }
 
-    if !is_debuggable(config) {
+    if let VirtualMachineConfig::AppConfig(app_config) = config {
+        if !should_prepare_console_output(app_config.debugLevel) {
+            return Ok(None);
+        }
+    } else {
         return Ok(None);
     }
 
diff --git a/virtualizationmanager/src/debug_config.rs b/virtualizationmanager/src/debug_config.rs
new file mode 100644
index 0000000..332df08
--- /dev/null
+++ b/virtualizationmanager/src/debug_config.rs
@@ -0,0 +1,39 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Functions for AVF debug policy and debug level
+
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
+    VirtualMachineAppConfig::DebugLevel::DebugLevel
+};
+use std::fs::File;
+use std::io::Read;
+
+/// Get debug policy value in bool. It's true iff the value is explicitly set to <1>.
+fn get_debug_policy_bool(path: &'static str) -> Option<bool> {
+    if let Ok(mut file) = File::open(path) {
+        let mut log: [u8; 4] = Default::default();
+        file.read_exact(&mut log).map_err(|_| false).unwrap();
+        // DT spec uses big endian although Android is always little endian.
+        return Some(u32::from_be_bytes(log) == 1);
+    }
+    None
+}
+
+/// Get whether console output should be configred for VM to leave console and adb log.
+/// Caller should create pipe and prepare for receiving VM log with it.
+pub fn should_prepare_console_output(debug_level: DebugLevel) -> bool {
+    debug_level != DebugLevel::NONE
+        || get_debug_policy_bool("/proc/device-tree/avf/guest/common/log").unwrap_or_default()
+}
diff --git a/virtualizationmanager/src/main.rs b/virtualizationmanager/src/main.rs
index 3f0b64b..bd7f8af 100644
--- a/virtualizationmanager/src/main.rs
+++ b/virtualizationmanager/src/main.rs
@@ -18,6 +18,7 @@
 mod atom;
 mod composite;
 mod crosvm;
+mod debug_config;
 mod payload;
 mod selinux;