Merge "[dice] Remove unnecessary conversion for DiceMode"
diff --git a/libs/avb/Android.bp b/libs/avb/Android.bp
index 1d257bc..c173f1c 100644
--- a/libs/avb/Android.bp
+++ b/libs/avb/Android.bp
@@ -20,7 +20,7 @@
         "--ctypes-prefix=core::ffi",
     ],
     static_libs: [
-        "libavb",
+        "libavb_non_debug",
     ],
     shared_libs: [
         "libcrypto",
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/pvmfw/avb/Android.bp b/pvmfw/avb/Android.bp
index 03670c1..0c1e392 100644
--- a/pvmfw/avb/Android.bp
+++ b/pvmfw/avb/Android.bp
@@ -12,7 +12,7 @@
         "libtinyvec_nostd",
     ],
     whole_static_libs: [
-        "libavb",
+        "libavb_non_debug",
     ],
 }
 
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>();
 
diff --git a/vmbase/common.h b/vmbase/common.h
index 788dcf0..0f73b36 100644
--- a/vmbase/common.h
+++ b/vmbase/common.h
@@ -30,9 +30,13 @@
 	movk \reg, :abs_g0_nc:\imm
 .endm
 
+.macro hvc_call func_id:req
+    mov_i x0, \func_id
+    hvc 0
+.endm
+
 .macro reset_or_hang
-	mov_i x0, PSCI_SYSTEM_RESET
-	hvc 0
+	hvc_call PSCI_SYSTEM_RESET
 999:	wfi
 	b 999b
 .endm
diff --git a/vmbase/entry.S b/vmbase/entry.S
index 5f0a2ce..ab46465 100644
--- a/vmbase/entry.S
+++ b/vmbase/entry.S
@@ -63,13 +63,71 @@
 .set .Lsctlrval, .L_SCTLR_ELx_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED
 .set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1 | .L_SCTLR_EL1_WXN
 
+/* SMC function IDs */
+.set .L_SMCCC_VERSION_ID, 0x80000000
+.set .L_SMCCC_TRNG_VERSION_ID, 0x84000050
+.set .L_SMCCC_TRNG_FEATURES_ID, 0x84000051
+.set .L_SMCCC_TRNG_RND64_ID, 0xc4000053
+
+/* SMC function versions */
+.set .L_SMCCC_VERSION_1_1, 0x0101
+.set .L_SMCCC_TRNG_VERSION_1_0, 0x0100
+
 /* Bionic-compatible stack protector */
 .section .data.stack_protector, "aw"
 __bionic_tls:
 	.zero	40
 .global __stack_chk_guard
 __stack_chk_guard:
-	.quad	0x23d6d3f3c3b84098 	/* TODO: randomize */
+	.quad	0
+
+/**
+ * This macro stores a random value into a register.
+ * If a TRNG backed is not present or if an error occurs, the value remains unchanged.
+ */
+.macro rnd_reg reg:req
+	mov x20, x0
+	mov x21, x1
+	mov x22, x2
+	mov x23, x3
+
+	/* Verify SMCCC version >=1.1 */
+	hvc_call .L_SMCCC_VERSION_ID
+	cmp w0, 0
+	b.lt 100f
+	cmp w0, .L_SMCCC_VERSION_1_1
+	b.lt 100f
+
+	/* Verify TRNG ABI version 1.x */
+	hvc_call .L_SMCCC_TRNG_VERSION_ID
+	cmp w0, 0
+	b.lt 100f
+	cmp w0, .L_SMCCC_TRNG_VERSION_1_0
+	b.lt 100f
+
+	/* Call TRNG_FEATURES, ensure TRNG_RND is implemented */
+	mov_i x1, .L_SMCCC_TRNG_RND64_ID
+	hvc_call .L_SMCCC_TRNG_FEATURES_ID
+	cmp w0, 0
+	b.lt 100f
+
+	/* Call TRNG_RND, request 64 bits of entropy */
+	mov x1, #64
+	hvc_call .L_SMCCC_TRNG_RND64_ID
+	cmp x0, 0
+	b.lt 100f
+
+	mov \reg, x3
+	b 101f
+
+100:
+	reset_or_hang
+101:
+	mov x0, x20
+	mov x1, x21
+	mov x2, x22
+	mov x3, x23
+.endm
 
 /**
  * This is a generic entry point for an image. It carries out the operations required to prepare the
@@ -162,9 +220,15 @@
 	adr_l x30, __bionic_tls
 	msr tpidr_el0, x30
 
+	/* Randomize stack protector. */
+	rnd_reg x29
+	adr_l x30, __stack_chk_guard
+	str x29, [x30]
+
 	/* Call into Rust code. */
 	bl rust_entry
 
 	/* Loop forever waiting for interrupts. */
 4:	wfi
 	b 4b
+