Merge "Sync encryptedstorage after payload execution"
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index f1c41b9..13bc9e3 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -53,6 +53,7 @@
use std::borrow::Cow::{Borrowed, Owned};
use std::convert::TryInto;
use std::env;
+use std::ffi::CString;
use std::fs::{self, create_dir, OpenOptions};
use std::io::Write;
use std::os::unix::process::CommandExt;
@@ -216,13 +217,21 @@
match try_run_payload(&service) {
Ok(code) => {
- info!("notifying payload finished");
- service.notifyPayloadFinished(code)?;
if code == 0 {
info!("task successfully finished");
} else {
error!("task exited with exit code: {}", code);
}
+ if let Err(e) = post_payload_work() {
+ error!(
+ "Failed to run post payload work. It is possible that certain tasks
+ like syncing encrypted store might be incomplete. Error: {:?}",
+ e
+ );
+ };
+
+ info!("notifying payload finished");
+ service.notifyPayloadFinished(code)?;
Ok(())
}
Err(err) => {
@@ -233,6 +242,28 @@
}
}
+fn post_payload_work() -> Result<()> {
+ // Sync the encrypted storage filesystem (flushes the filesystem caches).
+ if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
+ let mountpoint = CString::new(ENCRYPTEDSTORE_MOUNTPOINT).unwrap();
+
+ let ret = unsafe {
+ let dirfd = libc::open(
+ mountpoint.as_ptr(),
+ libc::O_DIRECTORY | libc::O_RDONLY | libc::O_CLOEXEC,
+ );
+ ensure!(dirfd >= 0, "Unable to open {:?}", mountpoint);
+ let ret = libc::syncfs(dirfd);
+ libc::close(dirfd);
+ ret
+ };
+ if ret != 0 {
+ error!("failed to sync encrypted storage.");
+ return Err(anyhow!(std::io::Error::last_os_error()));
+ }
+ }
+ Ok(())
+}
fn dice_derivation(
dice: DiceDriver,
verified_data: &MicrodroidData,
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index 7ee1f01..4611134 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -55,4 +55,10 @@
/* get the content of the specified file. */
String readFromFile(String path);
+
+ /**
+ * Request the service to exit, triggering the termination of the VM. This may cause any
+ * requests in flight to fail.
+ */
+ oneway void quit();
}
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 c6915e5..9cafd68 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -1520,15 +1520,34 @@
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() {
- private void testVMService(VirtualMachine vm) {
+ ITestService mTestService = null;
+
+ private void initializeTestService(VirtualMachine vm) {
try {
- ITestService testService =
+ mTestService =
ITestService.Stub.asInterface(
vm.connectToVsockServer(ITestService.SERVICE_PORT));
- testsToRun.runTests(testService, testResults);
+ } 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(VirtualMachine vm) {
+ try {
+ mTestService.quit();
} catch (Exception e) {
testResults.mException = e;
}
@@ -1539,7 +1558,7 @@
Log.i(TAG, "onPayloadReady");
payloadReady.complete(true);
testVMService(vm);
- forceStop(vm);
+ quitVMService(vm);
}
@Override
@@ -1547,10 +1566,19 @@
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;
}
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 4ba502a..365ea75 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -240,9 +240,6 @@
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();
}
@@ -255,6 +252,8 @@
}
return ScopedAStatus::ok();
}
+
+ ScopedAStatus quit() override { exit(0); }
};
auto testService = ndk::SharedRefBase::make<TestService>();