Test that we can parcel & unparcel VirtualMachineDescriptor
The test creates a VirtualMachineDescriptor, writes it to a parcel,
reads it from the parcel, and then tries to create a VM from it.
This change also fixes the bug in how VirtualMachineDescriptor is
parceled/unparceled: the writeToParcel was writing a full
ParcelFileDescriptor parcelable, while VirtualMachineDescriptor(Parcel)
c-tor was reading just a raw fd.
Bug: 259384440
Test: atest MicrodroidTestApp
Change-Id: I809fa635ebb934e0ba957d3e2642d1b40d21ec50
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineDescriptor.java b/javalib/src/android/system/virtualmachine/VirtualMachineDescriptor.java
index 483779a..02475a6 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineDescriptor.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineDescriptor.java
@@ -34,6 +34,7 @@
*
* @hide
*/
+// TODO(b/268613460): should implement autocloseable.
@SystemApi
public final class VirtualMachineDescriptor implements Parcelable {
@NonNull private final ParcelFileDescriptor mConfigFd;
@@ -49,9 +50,9 @@
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
- mConfigFd.writeToParcel(out, flags);
- mInstanceImgFd.writeToParcel(out, flags);
- if (mEncryptedStoreFd != null) mEncryptedStoreFd.writeToParcel(out, flags);
+ out.writeParcelable(mConfigFd, flags);
+ out.writeParcelable(mInstanceImgFd, flags);
+ out.writeParcelable(mEncryptedStoreFd, flags);
}
@NonNull
@@ -95,14 +96,19 @@
@NonNull ParcelFileDescriptor configFd,
@NonNull ParcelFileDescriptor instanceImgFd,
@Nullable ParcelFileDescriptor encryptedStoreFd) {
- mConfigFd = configFd;
- mInstanceImgFd = instanceImgFd;
+ mConfigFd = requireNonNull(configFd);
+ mInstanceImgFd = requireNonNull(instanceImgFd);
mEncryptedStoreFd = encryptedStoreFd;
}
private VirtualMachineDescriptor(Parcel in) {
- mConfigFd = requireNonNull(in.readFileDescriptor());
- mInstanceImgFd = requireNonNull(in.readFileDescriptor());
- mEncryptedStoreFd = in.readFileDescriptor();
+ mConfigFd = requireNonNull(readParcelFileDescriptor(in));
+ mInstanceImgFd = requireNonNull(readParcelFileDescriptor(in));
+ mEncryptedStoreFd = readParcelFileDescriptor(in);
+ }
+
+ private ParcelFileDescriptor readParcelFileDescriptor(Parcel in) {
+ return in.readParcelable(
+ ParcelFileDescriptor.class.getClassLoader(), ParcelFileDescriptor.class);
}
}
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 e0748c1..926dd77 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.content.Context;
import android.content.ContextWrapper;
import android.os.Build;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
@@ -1546,6 +1547,99 @@
getVirtualMachineManager().delete("vm_from_another_app");
}
+ @Test
+ public void testVmDescriptorParcelUnparcel_noTrustedStorage() throws Exception {
+ assumeSupportedKernel();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilder()
+ .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+
+ VirtualMachine originalVm = forceCreateNewVirtualMachine("original_vm", config);
+ // Just start & stop the VM.
+ runVmTestService(originalVm, (ts, tr) -> {});
+
+ // Now create the descriptor and manually parcel & unparcel it.
+ VirtualMachineDescriptor vmDescriptor = toParcelFromParcel(originalVm.toDescriptor());
+
+ if (getVirtualMachineManager().get("import_vm_from_unparceled") != null) {
+ getVirtualMachineManager().delete("import_vm_from_unparceled");
+ }
+
+ VirtualMachine importVm =
+ getVirtualMachineManager()
+ .importFromDescriptor("import_vm_from_unparceled", vmDescriptor);
+
+ assertFileContentsAreEqualInTwoVms(
+ "config.xml", "original_vm", "import_vm_from_unparceled");
+ assertFileContentsAreEqualInTwoVms(
+ "instance.img", "original_vm", "import_vm_from_unparceled");
+
+ // Check that we can start and stop imported vm as well
+ runVmTestService(importVm, (ts, tr) -> {});
+ }
+
+ @Test
+ public void testVmDescriptorParcelUnparcel_withTrustedStorage() throws Exception {
+ assumeSupportedKernel();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilder()
+ .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .setEncryptedStorageBytes(1_000_000)
+ .build();
+
+ VirtualMachine originalVm = forceCreateNewVirtualMachine("original_vm", config);
+ // Just start & stop the VM.
+ {
+ TestResults testResults =
+ runVmTestService(
+ originalVm,
+ (ts, tr) -> {
+ ts.writeToFile("not a secret!", "/mnt/encryptedstore/secret.txt");
+ });
+ assertThat(testResults.mException).isNull();
+ }
+
+ // Now create the descriptor and manually parcel & unparcel it.
+ VirtualMachineDescriptor vmDescriptor = toParcelFromParcel(originalVm.toDescriptor());
+
+ if (getVirtualMachineManager().get("import_vm_from_unparceled") != null) {
+ getVirtualMachineManager().delete("import_vm_from_unparceled");
+ }
+
+ VirtualMachine importVm =
+ getVirtualMachineManager()
+ .importFromDescriptor("import_vm_from_unparceled", vmDescriptor);
+
+ assertFileContentsAreEqualInTwoVms(
+ "config.xml", "original_vm", "import_vm_from_unparceled");
+ assertFileContentsAreEqualInTwoVms(
+ "instance.img", "original_vm", "import_vm_from_unparceled");
+ assertFileContentsAreEqualInTwoVms(
+ "storage.img", "original_vm", "import_vm_from_unparceled");
+
+ TestResults testResults =
+ runVmTestService(
+ importVm,
+ (ts, tr) -> {
+ tr.mFileContent = ts.readFromFile("/mnt/encryptedstore/secret.txt");
+ });
+
+ assertThat(testResults.mException).isNull();
+ assertThat(testResults.mFileContent).isEqualTo("not a secret!");
+ }
+
+ private VirtualMachineDescriptor toParcelFromParcel(VirtualMachineDescriptor descriptor) {
+ Parcel parcel = Parcel.obtain();
+ descriptor.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return VirtualMachineDescriptor.CREATOR.createFromParcel(parcel);
+ }
+
private void assertFileContentsAreEqualInTwoVms(String fileName, String vmName1, String vmName2)
throws IOException {
File file1 = getVmFile(vmName1, fileName);