Support config-less VMs
Update the Java API to allow the config file to be omitted. Instead,
the binary path can be specified explicitly.
Remove certs from VirtualMachineConfig; they were only used for
compatibility checking, and running a VM with a different APK
(regardless of singing certs) isn't supported. Require whether the VM
is protected to be specified explicitly, to avoid accidents.
Modify the config serialization format & bump the version.
Modify demo + test clients to match.
Refactor the tests to split off the extra APK test (which requires a
config file), minimizing code duplication.
Migrate one success test to run without config file.
Bug: 243513572
Test: atest MicrodroidTests
Change-Id: I6b195d4daa9c8132e1f71a04d2253f538edcbe4a
diff --git a/demo/java/com/android/microdroid/demo/MainActivity.java b/demo/java/com/android/microdroid/demo/MainActivity.java
index 1fdce03..7624876 100644
--- a/demo/java/com/android/microdroid/demo/MainActivity.java
+++ b/demo/java/com/android/microdroid/demo/MainActivity.java
@@ -258,7 +258,9 @@
try {
VirtualMachineConfig.Builder builder =
- new VirtualMachineConfig.Builder(getApplication(), "assets/vm_config.json");
+ new VirtualMachineConfig.Builder(getApplication());
+ builder.setPayloadConfigPath("assets/vm_config.json");
+ builder.setProtectedVm(true);
if (debug) {
builder.setDebugLevel(VirtualMachineConfig.DEBUG_LEVEL_FULL);
}
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index 2b4d185..bdec164 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -78,6 +78,7 @@
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -791,11 +792,29 @@
@Override
public String toString() {
- return "VirtualMachine("
- + "name:" + getName() + ", "
- + "config:" + getConfig().getPayloadConfigPath() + ", "
- + "package: " + mPackageName
- + ")";
+ VirtualMachineConfig config = getConfig();
+ String payloadConfigPath = config.getPayloadConfigPath();
+ String payloadBinaryPath = config.getPayloadBinaryPath();
+
+ StringBuilder result = new StringBuilder();
+ result.append("VirtualMachine(")
+ .append("name:")
+ .append(getName())
+ .append(", ");
+ if (payloadBinaryPath != null) {
+ result.append("payload:")
+ .append(payloadBinaryPath)
+ .append(", ");
+ }
+ if (payloadConfigPath != null) {
+ result.append("config:")
+ .append(payloadConfigPath)
+ .append(", ");
+ }
+ result.append("package: ")
+ .append(mPackageName)
+ .append(")");
+ return result.toString();
}
private static List<String> parseExtraApkListFromPayloadConfig(JsonReader reader)
@@ -841,10 +860,14 @@
private static List<ExtraApkSpec> setupExtraApks(
@NonNull Context context, @NonNull VirtualMachineConfig config, @NonNull File vmDir)
throws VirtualMachineException {
+ String configPath = config.getPayloadConfigPath();
+ if (configPath == null) {
+ return Collections.emptyList();
+ }
try {
ZipFile zipFile = new ZipFile(context.getPackageCodePath());
InputStream inputStream =
- zipFile.getInputStream(zipFile.getEntry(config.getPayloadConfigPath()));
+ zipFile.getInputStream(zipFile.getEntry(configPath));
List<String> apkList =
parseExtraApkListFromPayloadConfig(
new JsonReader(new InputStreamReader(inputStream)));
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
index 7f41874..3061f65 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -18,18 +18,15 @@
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
-import static java.util.Objects.requireNonNull;
-
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.PackageInfoFlags;
-import android.content.pm.Signature;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.sysprop.HypervisorProperties;
import android.system.virtualizationservice.VirtualMachineAppConfig;
+import android.system.virtualizationservice.VirtualMachinePayloadConfig;
import java.io.File;
import java.io.FileNotFoundException;
@@ -38,9 +35,7 @@
import java.io.OutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.Objects;
/**
* Represents a configuration of a virtual machine. A configuration consists of hardware
@@ -51,11 +46,11 @@
*/
public final class VirtualMachineConfig {
// These defines the schema of the config file persisted on disk.
- private static final int VERSION = 1;
+ private static final int VERSION = 2;
private static final String KEY_VERSION = "version";
- private static final String KEY_CERTS = "certs";
private static final String KEY_APKPATH = "apkPath";
private static final String KEY_PAYLOADCONFIGPATH = "payloadConfigPath";
+ private static final String KEY_PAYLOADBINARYPATH = "payloadBinaryPath";
private static final String KEY_DEBUGLEVEL = "debugLevel";
private static final String KEY_PROTECTED_VM = "protectedVm";
private static final String KEY_MEMORY_MIB = "memoryMib";
@@ -63,7 +58,6 @@
// Paths to the APK file of this application.
@NonNull private final String mApkPath;
- @NonNull private final Signature[] mCerts;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -116,21 +110,26 @@
private final int mNumCpus;
/**
- * Path within the APK to the payload config file that defines software aspects of this config.
+ * Path within the APK to the payload config file that defines software aspects of the VM.
*/
- @NonNull private final String mPayloadConfigPath;
+ @Nullable private final String mPayloadConfigPath;
+
+ /**
+ * Path within the APK to the payload binary file that will be executed within the VM.
+ */
+ @Nullable private final String mPayloadBinaryPath;
private VirtualMachineConfig(
@NonNull String apkPath,
- @NonNull Signature[] certs,
- @NonNull String payloadConfigPath,
+ @Nullable String payloadConfigPath,
+ @Nullable String payloadBinaryPath,
@DebugLevel int debugLevel,
boolean protectedVm,
int memoryMib,
int numCpus) {
- mApkPath = apkPath;
- mCerts = certs;
+ mApkPath = Objects.requireNonNull(apkPath);
mPayloadConfigPath = payloadConfigPath;
+ mPayloadBinaryPath = payloadBinaryPath;
mDebugLevel = debugLevel;
mProtectedVm = protectedVm;
mMemoryMib = memoryMib;
@@ -142,37 +141,33 @@
static VirtualMachineConfig from(@NonNull InputStream input)
throws IOException, VirtualMachineException {
PersistableBundle b = PersistableBundle.readFromStream(input);
- final int version = b.getInt(KEY_VERSION);
+ int version = b.getInt(KEY_VERSION);
if (version > VERSION) {
throw new VirtualMachineException("Version too high");
}
- final String apkPath = b.getString(KEY_APKPATH);
+ String apkPath = b.getString(KEY_APKPATH);
if (apkPath == null) {
throw new VirtualMachineException("No apkPath");
}
- final String[] certStrings = b.getStringArray(KEY_CERTS);
- if (certStrings == null || certStrings.length == 0) {
- throw new VirtualMachineException("No certs");
+ String payloadBinaryPath = b.getString(KEY_PAYLOADBINARYPATH);
+ String payloadConfigPath = null;
+ if (payloadBinaryPath == null) {
+ payloadConfigPath = b.getString(KEY_PAYLOADCONFIGPATH);
+ if (payloadConfigPath == null) {
+ throw new VirtualMachineException("No payloadBinaryPath");
+ }
}
- List<Signature> certList = new ArrayList<>();
- for (String s : certStrings) {
- certList.add(new Signature(s));
- }
- Signature[] certs = certList.toArray(new Signature[0]);
- final String payloadConfigPath = b.getString(KEY_PAYLOADCONFIGPATH);
- if (payloadConfigPath == null) {
- throw new VirtualMachineException("No payloadConfigPath");
- }
- @DebugLevel final int debugLevel = b.getInt(KEY_DEBUGLEVEL);
+ @DebugLevel int debugLevel = b.getInt(KEY_DEBUGLEVEL);
if (debugLevel != DEBUG_LEVEL_NONE && debugLevel != DEBUG_LEVEL_APP_ONLY
&& debugLevel != DEBUG_LEVEL_FULL) {
throw new VirtualMachineException("Invalid debugLevel: " + debugLevel);
}
- final boolean protectedVm = b.getBoolean(KEY_PROTECTED_VM);
- final int memoryMib = b.getInt(KEY_MEMORY_MIB);
- final int numCpus = b.getInt(KEY_NUM_CPUS);
- return new VirtualMachineConfig(apkPath, certs, payloadConfigPath, debugLevel, protectedVm,
- memoryMib, numCpus);
+ boolean protectedVm = b.getBoolean(KEY_PROTECTED_VM);
+ int memoryMib = b.getInt(KEY_MEMORY_MIB);
+ int numCpus = b.getInt(KEY_NUM_CPUS);
+
+ return new VirtualMachineConfig(apkPath, payloadConfigPath, payloadBinaryPath, debugLevel,
+ protectedVm, memoryMib, numCpus);
}
/** Persists this config to a stream, for example a file. */
@@ -180,13 +175,8 @@
PersistableBundle b = new PersistableBundle();
b.putInt(KEY_VERSION, VERSION);
b.putString(KEY_APKPATH, mApkPath);
- List<String> certList = new ArrayList<>();
- for (Signature cert : mCerts) {
- certList.add(cert.toCharsString());
- }
- String[] certs = certList.toArray(new String[0]);
- b.putStringArray(KEY_CERTS, certs);
b.putString(KEY_PAYLOADCONFIGPATH, mPayloadConfigPath);
+ b.putString(KEY_PAYLOADBINARYPATH, mPayloadBinaryPath);
b.putInt(KEY_DEBUGLEVEL, mDebugLevel);
b.putBoolean(KEY_PROTECTED_VM, mProtectedVm);
b.putInt(KEY_NUM_CPUS, mNumCpus);
@@ -201,12 +191,23 @@
*
* @hide
*/
- @NonNull
+ @Nullable
public String getPayloadConfigPath() {
return mPayloadConfigPath;
}
/**
+ * Returns the path within the APK to the payload binary file that will be executed within the
+ * VM.
+ *
+ * @hide
+ */
+ @Nullable
+ public String getPayloadBinaryPath() {
+ return mPayloadBinaryPath;
+ }
+
+ /**
* Returns the debug level for the VM.
*
* @hide
@@ -247,24 +248,17 @@
/**
* Tests if this config is compatible with other config. Being compatible means that the configs
* can be interchangeably used for the same virtual machine. Compatible changes includes the
- * number of CPUs and the size of the RAM, and change of the payload as long as the payload is
- * signed by the same signer. All other changes (e.g. using a payload from a different signer,
+ * number of CPUs and the size of the RAM. All other changes (e.g. using a different payload,
* change of the debug mode, etc.) are considered as incompatible.
*
* @hide
*/
public boolean isCompatibleWith(@NonNull VirtualMachineConfig other) {
- if (!Arrays.equals(this.mCerts, other.mCerts)) {
- return false;
- }
- if (this.mDebugLevel != other.mDebugLevel) {
- // TODO(jiyong): should we treat APP_ONLY and FULL the same?
- return false;
- }
- if (this.mProtectedVm != other.mProtectedVm) {
- return false;
- }
- return true;
+ return this.mDebugLevel == other.mDebugLevel
+ && this.mProtectedVm == other.mProtectedVm
+ && Objects.equals(this.mPayloadConfigPath, other.mPayloadConfigPath)
+ && Objects.equals(this.mPayloadBinaryPath, other.mPayloadBinaryPath)
+ && this.mApkPath.equals(other.mApkPath);
}
/**
@@ -273,10 +267,19 @@
* service doesn't accept paths as it might not have permission to open app-owned files and that
* could be abused to run a VM with software that the calling application doesn't own.
*/
- /* package */ VirtualMachineAppConfig toParcel() throws FileNotFoundException {
+ VirtualMachineAppConfig toParcel() throws FileNotFoundException {
VirtualMachineAppConfig parcel = new VirtualMachineAppConfig();
parcel.apk = ParcelFileDescriptor.open(new File(mApkPath), MODE_READ_ONLY);
- parcel.payload = VirtualMachineAppConfig.Payload.configPath(mPayloadConfigPath);
+ if (mPayloadBinaryPath != null) {
+ VirtualMachinePayloadConfig payloadConfig = new VirtualMachinePayloadConfig();
+ payloadConfig.payloadPath = mPayloadBinaryPath;
+ payloadConfig.args = new String[]{};
+ parcel.payload =
+ VirtualMachineAppConfig.Payload.payloadConfig(payloadConfig);
+ } else {
+ parcel.payload =
+ VirtualMachineAppConfig.Payload.configPath(mPayloadConfigPath);
+ }
switch (mDebugLevel) {
case DEBUG_LEVEL_APP_ONLY:
parcel.debugLevel = VirtualMachineAppConfig.DebugLevel.APP_ONLY;
@@ -304,27 +307,95 @@
*/
public static final class Builder {
private final Context mContext;
- private final String mPayloadConfigPath;
+ @Nullable private String mPayloadConfigPath;
+ @Nullable private String mPayloadBinaryPath;
@DebugLevel private int mDebugLevel;
private boolean mProtectedVm;
+ private boolean mProtectedVmSet;
private int mMemoryMib;
private int mNumCpus;
/**
- * Creates a builder for the given context (APK), and the payload config file in APK.
+ * Creates a builder for the given context (APK).
*
* @hide
*/
- public Builder(@NonNull Context context, @NonNull String payloadConfigPath) {
- mContext = requireNonNull(context, "context must not be null");
- mPayloadConfigPath = requireNonNull(payloadConfigPath,
- "payloadConfigPath must not be null");
+ public Builder(@NonNull Context context) {
+ mContext = Objects.requireNonNull(context);
mDebugLevel = DEBUG_LEVEL_NONE;
- mProtectedVm = false;
mNumCpus = 1;
}
/**
+ * Builds an immutable {@link VirtualMachineConfig}
+ *
+ * @hide
+ */
+ @NonNull
+ public VirtualMachineConfig build() {
+ final String apkPath = mContext.getPackageCodePath();
+
+ final int availableCpus = Runtime.getRuntime().availableProcessors();
+ if (mNumCpus < 1 || mNumCpus > availableCpus) {
+ throw new IllegalArgumentException("Number of vCPUs (" + mNumCpus + ") is out of "
+ + "range [1, " + availableCpus + "]");
+ }
+
+ if (mPayloadBinaryPath == null) {
+ if (mPayloadConfigPath == null) {
+ throw new IllegalStateException("payloadBinaryPath must be set");
+ }
+ } else {
+ if (mPayloadConfigPath != null) {
+ throw new IllegalStateException(
+ "payloadBinaryPath and payloadConfigPath may not both be set");
+ }
+ }
+
+ if (!mProtectedVmSet) {
+ throw new IllegalStateException("protectedVm must be set explicitly");
+ }
+
+ if (mProtectedVm
+ && !HypervisorProperties.hypervisor_protected_vm_supported().orElse(false)) {
+ throw new UnsupportedOperationException(
+ "Protected VMs are not supported on this device.");
+ }
+ if (!mProtectedVm && !HypervisorProperties.hypervisor_vm_supported().orElse(false)) {
+ throw new UnsupportedOperationException(
+ "Unprotected VMs are not supported on this device.");
+ }
+
+ return new VirtualMachineConfig(
+ apkPath, mPayloadConfigPath, mPayloadBinaryPath, mDebugLevel, mProtectedVm,
+ mMemoryMib, mNumCpus);
+ }
+
+ /**
+ * Sets the path within the APK to the payload config file that defines software aspects
+ * of the VM.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setPayloadConfigPath(@NonNull String payloadConfigPath) {
+ mPayloadConfigPath = Objects.requireNonNull(payloadConfigPath);
+ return this;
+ }
+
+ /**
+ * Sets the path within the APK to the payload binary file that will be executed within
+ * the VM.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setPayloadBinaryPath(@NonNull String payloadBinaryPath) {
+ mPayloadBinaryPath = Objects.requireNonNull(payloadBinaryPath);
+ return this;
+ }
+
+ /**
* Sets the debug level
*
* @hide
@@ -336,13 +407,15 @@
}
/**
- * Sets whether to protect the VM memory from the host. Defaults to false.
+ * Sets whether to protect the VM memory from the host. No default is provided, this
+ * must be set explicitly.
*
* @hide
*/
@NonNull
public Builder setProtectedVm(boolean protectedVm) {
mProtectedVm = protectedVm;
+ mProtectedVmSet = true;
return this;
}
@@ -368,47 +441,5 @@
mNumCpus = num;
return this;
}
-
- /**
- * Builds an immutable {@link VirtualMachineConfig}
- *
- * @hide
- */
- @NonNull
- public VirtualMachineConfig build() {
- final String apkPath = mContext.getPackageCodePath();
- final String packageName = mContext.getPackageName();
- Signature[] certs;
- try {
- certs = mContext.getPackageManager()
- .getPackageInfo(packageName,
- PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES))
- .signingInfo
- .getSigningCertificateHistory();
- } catch (PackageManager.NameNotFoundException e) {
- // This cannot happen as `packageName` is from this app.
- throw new RuntimeException(e);
- }
-
- final int availableCpus = Runtime.getRuntime().availableProcessors();
- if (mNumCpus < 1 || mNumCpus > availableCpus) {
- throw new IllegalArgumentException("Number of vCPUs (" + mNumCpus + ") is out of "
- + "range [1, " + availableCpus + "]");
- }
-
- if (mProtectedVm
- && !HypervisorProperties.hypervisor_protected_vm_supported().orElse(false)) {
- throw new UnsupportedOperationException(
- "Protected VMs are not supported on this device.");
- }
- if (!mProtectedVm && !HypervisorProperties.hypervisor_vm_supported().orElse(false)) {
- throw new UnsupportedOperationException(
- "Unprotected VMs are not supported on this device.");
- }
-
- return new VirtualMachineConfig(
- apkPath, certs, mPayloadConfigPath, mDebugLevel, mProtectedVm, mMemoryMib,
- mNumCpus);
- }
}
}
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 2856a30..2deeb70 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
@@ -77,10 +77,12 @@
return mContext;
}
- /** Create a new VirtualMachineConfig.Builder with the parameterized protection mode. */
+ public VirtualMachineConfig.Builder newVmConfigBuilder() {
+ return new VirtualMachineConfig.Builder(mContext).setProtectedVm(mProtectedVm);
+ }
+
public VirtualMachineConfig.Builder newVmConfigBuilder(String payloadConfigPath) {
- return new VirtualMachineConfig.Builder(mContext, payloadConfigPath)
- .setProtectedVm(mProtectedVm);
+ return newVmConfigBuilder().setPayloadConfigPath(payloadConfigPath);
}
/**
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 707930f..b0ec359 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -87,78 +87,35 @@
"9.17/C-2-1"
})
public void connectToVmService() throws Exception {
- assume()
- .withMessage("SKip on 5.4 kernel. b/218303240")
- .that(KERNEL_VERSION)
- .isNotEqualTo("5.4");
+ assumeSupportedKernel();
- VirtualMachineConfig.Builder builder =
- mInner.newVmConfigBuilder("assets/vm_config_extra_apk.json");
- if (Build.SUPPORTED_ABIS.length > 0) {
- String primaryAbi = Build.SUPPORTED_ABIS[0];
- switch(primaryAbi) {
- case "x86_64":
- builder.setMemoryMib(MIN_MEM_X86_64);
- break;
- case "arm64-v8a":
- builder.setMemoryMib(MIN_MEM_ARM64);
- break;
- }
- }
- VirtualMachineConfig config = builder.build();
+ VirtualMachineConfig config = mInner.newVmConfigBuilder()
+ .setPayloadBinaryPath("MicrodroidTestNativeLib.so")
+ .setMemoryMib(minMemoryRequired())
+ .build();
VirtualMachine vm = mInner.forceCreateNewVirtualMachine("test_vm_extra_apk", config);
- class TestResults {
- Exception mException;
- Integer mAddInteger;
- String mAppRunProp;
- String mSublibRunProp;
- String mExtraApkTestProp;
- }
- final CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
- final CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
- final TestResults testResults = new TestResults();
- VmEventListener listener =
- new VmEventListener() {
- private void testVMService(VirtualMachine vm) {
- try {
- ITestService testService = ITestService.Stub.asInterface(
- vm.connectToVsockServer(ITestService.SERVICE_PORT));
- testResults.mAddInteger = testService.addInteger(123, 456);
- testResults.mAppRunProp =
- testService.readProperty("debug.microdroid.app.run");
- testResults.mSublibRunProp =
- testService.readProperty("debug.microdroid.app.sublib.run");
- testResults.mExtraApkTestProp =
- testService.readProperty("debug.microdroid.test.extra_apk");
- } catch (Exception e) {
- testResults.mException = e;
- }
- }
-
- @Override
- public void onPayloadReady(VirtualMachine vm) {
- Log.i(TAG, "onPayloadReady");
- payloadReady.complete(true);
- testVMService(vm);
- forceStop(vm);
- }
-
- @Override
- public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
- Log.i(TAG, "onPayloadStarted");
- payloadStarted.complete(true);
- logVmOutput(TAG, new FileInputStream(stream.getFileDescriptor()),
- "Payload");
- }
- };
- listener.runToFinish(TAG, vm);
- assertThat(payloadStarted.getNow(false)).isTrue();
- assertThat(payloadReady.getNow(false)).isTrue();
+ TestResults testResults = runVmTestService(vm);
assertThat(testResults.mException).isNull();
assertThat(testResults.mAddInteger).isEqualTo(123 + 456);
assertThat(testResults.mAppRunProp).isEqualTo("true");
assertThat(testResults.mSublibRunProp).isEqualTo("true");
+ }
+
+ @Test
+ @CddTest(requirements = {
+ "9.17/C-1-1",
+ "9.17/C-2-1"
+ })
+ public void extraApk() throws Exception {
+ assumeSupportedKernel();
+
+ VirtualMachineConfig config = mInner.newVmConfigBuilder("assets/vm_config_extra_apk.json")
+ .setMemoryMib(minMemoryRequired())
+ .build();
+ VirtualMachine vm = mInner.forceCreateNewVirtualMachine("test_vm_extra_apk", config);
+
+ TestResults testResults = runVmTestService(vm);
assertThat(testResults.mExtraApkTestProp).isEqualTo("PASS");
}
@@ -198,10 +155,7 @@
"9.17/C-2-7"
})
public void changingDebugLevelInvalidatesVmIdentity() throws Exception {
- assume()
- .withMessage("SKip on 5.4 kernel. b/218303240")
- .that(KERNEL_VERSION)
- .isNotEqualTo("5.4");
+ assumeSupportedKernel();
VirtualMachineConfig.Builder builder = mInner.newVmConfigBuilder("assets/vm_config.json");
VirtualMachineConfig normalConfig = builder.setDebugLevel(DEBUG_LEVEL_NONE).build();
@@ -263,10 +217,7 @@
"9.17/C-2-7"
})
public void instancesOfSameVmHaveDifferentCdis() throws Exception {
- assume()
- .withMessage("SKip on 5.4 kernel. b/218303240")
- .that(KERNEL_VERSION)
- .isNotEqualTo("5.4");
+ assumeSupportedKernel();
VirtualMachineConfig normalConfig = mInner.newVmConfigBuilder("assets/vm_config.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
@@ -290,10 +241,7 @@
"9.17/C-2-7"
})
public void sameInstanceKeepsSameCdis() throws Exception {
- assume()
- .withMessage("SKip on 5.4 kernel. b/218303240")
- .that(KERNEL_VERSION)
- .isNotEqualTo("5.4");
+ assumeSupportedKernel();
VirtualMachineConfig normalConfig = mInner.newVmConfigBuilder("assets/vm_config.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
@@ -314,10 +262,7 @@
"9.17/C-2-7"
})
public void bccIsSuperficiallyWellFormed() throws Exception {
- assume()
- .withMessage("SKip on 5.4 kernel. b/218303240")
- .that(KERNEL_VERSION)
- .isNotEqualTo("5.4");
+ assumeSupportedKernel();
VirtualMachineConfig normalConfig = mInner.newVmConfigBuilder("assets/vm_config.json")
.setDebugLevel(DEBUG_LEVEL_FULL)
@@ -479,4 +424,76 @@
assertThat(vm).isNotEqualTo(newVm);
}
+
+ private int minMemoryRequired() {
+ if (Build.SUPPORTED_ABIS.length > 0) {
+ String primaryAbi = Build.SUPPORTED_ABIS[0];
+ switch (primaryAbi) {
+ case "x86_64":
+ return MIN_MEM_X86_64;
+ case "arm64-v8a":
+ return MIN_MEM_ARM64;
+ }
+ }
+ return 0;
+ }
+
+ private void assumeSupportedKernel() {
+ assume()
+ .withMessage("Skip on 5.4 kernel. b/218303240")
+ .that(KERNEL_VERSION)
+ .isNotEqualTo("5.4");
+ }
+
+ static class TestResults {
+ Exception mException;
+ Integer mAddInteger;
+ String mAppRunProp;
+ String mSublibRunProp;
+ String mExtraApkTestProp;
+ }
+
+ private TestResults runVmTestService(VirtualMachine vm) throws Exception {
+ CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
+ CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
+ TestResults testResults = new TestResults();
+ VmEventListener listener =
+ new VmEventListener() {
+ private void testVMService(VirtualMachine vm) {
+ try {
+ ITestService testService = ITestService.Stub.asInterface(
+ vm.connectToVsockServer(ITestService.SERVICE_PORT));
+ testResults.mAddInteger = testService.addInteger(123, 456);
+ testResults.mAppRunProp =
+ testService.readProperty("debug.microdroid.app.run");
+ testResults.mSublibRunProp =
+ testService.readProperty("debug.microdroid.app.sublib.run");
+ testResults.mExtraApkTestProp =
+ testService.readProperty("debug.microdroid.test.extra_apk");
+ } catch (Exception e) {
+ testResults.mException = e;
+ }
+ }
+
+ @Override
+ public void onPayloadReady(VirtualMachine vm) {
+ Log.i(TAG, "onPayloadReady");
+ payloadReady.complete(true);
+ testVMService(vm);
+ forceStop(vm);
+ }
+
+ @Override
+ public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
+ Log.i(TAG, "onPayloadStarted");
+ payloadStarted.complete(true);
+ logVmOutput(TAG, new FileInputStream(stream.getFileDescriptor()),
+ "Payload");
+ }
+ };
+ listener.runToFinish(TAG, vm);
+ assertThat(payloadStarted.getNow(false)).isTrue();
+ assertThat(payloadReady.getNow(false)).isTrue();
+ return testResults;
+ }
}
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index b4fee86..c8d07a3 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -181,7 +181,7 @@
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
- if (strcmp(argv[1], "crash") == 0) {
+ if (argc >= 2 && strcmp(argv[1], "crash") == 0) {
printf("test crash!!!!\n");
abort();
}