Merge "Handle test failure better"
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 b3b8816..5c48a41 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -33,6 +33,7 @@
 import android.system.virtualmachine.VirtualMachineConfig.DebugLevel;
 import android.system.virtualmachine.VirtualMachineException;
 import android.system.virtualmachine.VirtualMachineManager;
+import android.util.Log;
 
 import androidx.annotation.CallSuper;
 import androidx.test.core.app.ApplicationProvider;
@@ -47,9 +48,13 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.RandomAccessFile;
 import java.nio.file.Files;
 import java.util.List;
@@ -68,10 +73,27 @@
 
 @RunWith(Parameterized.class)
 public class MicrodroidTests {
+    private static final String TAG = "MicrodroidTests";
+
     @Rule public Timeout globalTimeout = Timeout.seconds(300);
 
     private static final String KERNEL_VERSION = SystemProperties.get("ro.kernel.version");
 
+    /** Copy output from the VM to logcat. This is helpful when things go wrong. */
+    private static void logVmOutput(InputStream vmOutputStream, String name) {
+        new Thread(() -> {
+            try {
+                BufferedReader reader = new BufferedReader(new InputStreamReader(vmOutputStream));
+                String line;
+                while ((line = reader.readLine()) != null && !Thread.interrupted()) {
+                    Log.i(TAG, name + ": " + line);
+                }
+            } catch (Exception e) {
+                Log.w(TAG, name, e);
+            }
+        }).start();
+    }
+
     private static class Inner {
         public boolean mProtectedVm;
         public Context mContext;
@@ -149,6 +171,8 @@
         void runToFinish(VirtualMachine vm) throws VirtualMachineException, InterruptedException {
             vm.setCallback(mExecutorService, this);
             vm.run();
+            logVmOutput(vm.getConsoleOutputStream(), "Console");
+            logVmOutput(vm.getLogOutputStream(), "Log");
             mExecutorService.awaitTermination(300, TimeUnit.SECONDS);
         }
 
@@ -238,6 +262,7 @@
 
                     @Override
                     public void onPayloadReady(VirtualMachine vm) {
+                        Log.i(TAG, "onPayloadReady");
                         payloadReady.complete(true);
                         testVMService(vm);
                         forceStop(vm);
@@ -245,7 +270,9 @@
 
                     @Override
                     public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
+                        Log.i(TAG, "onPayloadStarted");
                         payloadStarted.complete(true);
+                        logVmOutput(new FileInputStream(stream.getFileDescriptor()), "Payload");
                     }
                 };
         listener.runToFinish(mInner.mVm);
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 89570c0..9493fc7 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -134,16 +134,18 @@
 
     auto callback = []([[maybe_unused]] void* param) {
         // Tell microdroid_manager that we're ready.
-        // Failing to notify is not a fatal error; the payload can continue.
+        // If we can't, abort in order to fail fast - the host won't proceed without
+        // receiving the onReady signal.
         ndk::SpAIBinder binder(
                 RpcClient(VMADDR_CID_HOST, IVirtualMachineService::VM_BINDER_SERVICE_PORT));
         auto virtualMachineService = IVirtualMachineService::fromBinder(binder);
         if (virtualMachineService == nullptr) {
-            std::cerr << "failed to connect VirtualMachineService";
-            return;
+            std::cerr << "failed to connect VirtualMachineService\n";
+            abort();
         }
         if (!virtualMachineService->notifyPayloadReady().isOk()) {
-            std::cerr << "failed to notify payload ready to virtualizationservice";
+            std::cerr << "failed to notify payload ready to virtualizationservice\n";
+            abort();
         }
     };
 
@@ -197,7 +199,7 @@
     if (auto res = start_test_service(); res.ok()) {
         return 0;
     } else {
-        std::cerr << "starting service failed: " << res.error();
+        std::cerr << "starting service failed: " << res.error() << "\n";
         return 1;
     }
 }