Test for checking persistence of encryptedstore
Test#encryptedStorageIsPersistent creates a VM, writes an example string
into a file backed by encryptedstore. Then it stops the VM, re-runs it
(this will reuse the instance image & backing storage). Then it reads
the file & checks that the content is the same as the string before.
Test: atest MicrodroidTests#encryptedStorageIsPersistent
Bug: 260084116
Change-Id: I9a0694de07175c1a29d37fd16488d1523eb13fed
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index c936e1b..7ee1f01 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -49,4 +49,10 @@
/** Returns a mask of effective capabilities that the process running the payload binary has. */
String[] getEffectiveCapabilities();
+
+ /* write the content into the specified file. */
+ void writeToFile(String content, String path);
+
+ /* get the content of the specified file. */
+ String readFromFile(String path);
}
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 9aed34d..536f663 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
@@ -126,6 +126,12 @@
}
}
+ protected enum EncryptedStoreOperation {
+ NONE,
+ READ,
+ WRITE,
+ }
+
public abstract static class VmEventListener implements VirtualMachineCallback {
private ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
private OptionalLong mVcpuStartedNanoTime = OptionalLong.empty();
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 160b679..897879b 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -113,6 +113,7 @@
private static final int MIN_MEM_ARM64 = 150;
private static final int MIN_MEM_X86_64 = 196;
+ private static final String EXAMPLE_STRING = "Literally any string!! :)";
@Test
@CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
@@ -1142,6 +1143,29 @@
assertThat(testResults.mEffectiveCapabilities).isEmpty();
}
+ @Test
+ @CddTest(requirements = {"9.17/C-1-1", "9.17/C-2-1"})
+ public void encryptedStorageIsPersistent() throws Exception {
+ assumeSupportedKernel();
+
+ VirtualMachineConfig config =
+ newVmConfigBuilder()
+ .setPayloadBinaryPath("MicrodroidTestNativeLib.so")
+ .setMemoryMib(minMemoryRequired())
+ .setEncryptedStorageKib(4096)
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_a", config);
+ TestResults testResults = runVmTestService(vm, EncryptedStoreOperation.WRITE);
+ assertThat(testResults.mException).isNull();
+
+ // Re-run the same VM & verify the file persisted. Note, the previous `runVmTestService`
+ // stopped the VM
+ testResults = runVmTestService(vm, EncryptedStoreOperation.READ);
+ assertThat(testResults.mException).isNull();
+ assertThat(testResults.mFileContent).isEqualTo(EXAMPLE_STRING);
+ }
+
private void assertFileContentsAreEqualInTwoVms(String fileName, String vmName1, String vmName2)
throws IOException {
File file1 = getVmFile(vmName1, fileName);
@@ -1197,9 +1221,15 @@
String mApkContentsPath;
String mEncryptedStoragePath;
String[] mEffectiveCapabilities;
+ String mFileContent;
}
private TestResults runVmTestService(VirtualMachine vm) throws Exception {
+ return runVmTestService(vm, EncryptedStoreOperation.NONE);
+ }
+
+ private TestResults runVmTestService(VirtualMachine vm, EncryptedStoreOperation mode)
+ throws Exception {
CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
TestResults testResults = new TestResults();
@@ -1222,6 +1252,14 @@
testService.getEncryptedStoragePath();
testResults.mEffectiveCapabilities =
testService.getEffectiveCapabilities();
+ if (mode == EncryptedStoreOperation.WRITE) {
+ testService.writeToFile(
+ /*content*/ EXAMPLE_STRING,
+ /*path*/ "/mnt/encryptedstore/test_file");
+ } else if (mode == EncryptedStoreOperation.READ) {
+ testResults.mFileContent =
+ testService.readFromFile("/mnt/encryptedstore/test_file");
+ }
} catch (Exception e) {
testResults.mException = e;
}
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index da408e4..4ba502a 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -232,6 +232,29 @@
return ScopedAStatus::fromServiceSpecificErrorWithMessage(-1, message.c_str());
}
}
+
+ ScopedAStatus writeToFile(const std::string& content, const std::string& path) override {
+ if (!android::base::WriteStringToFile(content, path)) {
+ std::string msg = "Failed to write " + content + " to file " + path +
+ ". Errono: " + std::to_string(errno);
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ msg.c_str());
+ }
+ // TODO(b/264520098): Remove sync() once TestService supports quit() method
+ // and Microdroid manager flushes filesystem caches on shutdown.
+ sync();
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus readFromFile(const std::string& path, std::string* out) override {
+ if (!android::base::ReadFileToString(path, out)) {
+ std::string msg =
+ "Failed to read " + path + " to string. Errono: " + std::to_string(errno);
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ msg.c_str());
+ }
+ return ScopedAStatus::ok();
+ }
};
auto testService = ndk::SharedRefBase::make<TestService>();