Merge changes I82acaa87,I0137f514,I0a055d1f,I9fca6467
* changes:
Add testVsockLatency benchmark
Refactor testRpcBinderLatency
Extract runVmTestService into MicrodroidDeviceTestBase
Report median of collected metrics
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/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index f46e158..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();
@@ -1727,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");
@@ -1837,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() {