Merge changes I8007849d,Ia8d589f5

* changes:
  Test that AVF-enabled devices also support updatable APEXes
  Supporting AVF implies that device supports updatable APEX
diff --git a/docs/debug/tracing.md b/docs/debug/tracing.md
index ebc0ac3..facd9d0 100644
--- a/docs/debug/tracing.md
+++ b/docs/debug/tracing.md
@@ -16,11 +16,13 @@
 * Only boot clock is supported, and there is no way for user space to change the tracing_clock.
 * Hypervisor tracing periodically polls the data from the hypervisor, this is different from the
   regular ftrace instance which pushes the events into the ring buffer.
+* Resetting ring buffers (by clearing the trace file) is only supported when there are no active
+  readers. If the trace file is cleared while there are active readers, then the ring buffers will
+  be cleared after the last reader disconnects.
+* Changing the size of the ring buffer while the tracing session is active is also not supported.
 
 Note: the list above is not exhaustive.
 
-TODO(b/271412868): add more documentation on the user space interface.
-
 ### Perfetto integration
 
 [Perfetto](https://perfetto.dev/docs/) is an open-source stack for performance instrumentation and
@@ -87,6 +89,61 @@
 tracebox -t 15s -b 32mb hyp
 ```
 
+### Analysing traces using SQL
+
+On top of visualisation, Perfetto also provides a SQL interface to analyse traces. More
+documentation is available at https://perfetto.dev/docs/quickstart/trace-analysis and
+https://perfetto.dev/docs/analysis/trace-processor.
+
+Hypervisor events can be queried via `pkvm_hypervisor_events` SQL view. You can load that view by
+calling `SELECT IMPORT("pkvm.hypervisor");`, e.g.:
+
+```sql
+SELECT IMPORT("pkvm.hypervisor");
+SELECT * FROM pkvm_hypervisor_events limit 5;
+```
+
+Below are some SQL queries that might be useful when analysing hypervisor traces.
+
+**What is the longest time CPU spent in hypervisor, grouped by the reason to enter hypervisor**
+```sql
+SELECT IMPORT("pkvm.hypervisor");
+
+SELECT
+  cpu,
+  reason,
+  ts,
+  dur
+FROM pkvm_hypervisor_events
+JOIN (
+  SELECT
+    MAX(dur) as dur2,
+    cpu as cpu2,
+    reason as reason2
+  FROM pkvm_hypervisor_events
+  GROUP BY 2, 3) AS sc
+ON
+  cpu = sc.cpu2
+  AND dur = sc.dur2
+  AND (reason = sc.reason2 OR (reason IS NULL AND sc.reason2 IS NULL))
+ORDER BY dur desc;
+```
+
+**What are the 10 longest times CPU spent in hypervisor because of host_mem_abort**
+```sql
+SELECT
+  hyp.dur as dur,
+  hyp.ts as ts,
+  EXTRACT_ARG(slices.arg_set_id, 'esr') as esr,
+  EXTRACT_ARG(slices.arg_set_id, 'addr') as addr
+FROM pkvm_hypervisor_events as hyp
+JOIN slices
+ON hyp.slice_id = slices.id
+WHERE hyp.reason = 'host_mem_abort'
+ORDER BY dur desc
+LIMIT 10;
+```
+
 ## Microdroid VM tracing
 
 IMPORTANT: Tracing is only supported for debuggable Microdroid VMs.
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 9c9be6c..de06d01 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -110,13 +110,26 @@
                 "authfs",
                 "authfs_service",
                 "encryptedstore",
-                "microdroid_crashdump_kernel",
                 "microdroid_kexec",
                 "microdroid_manager",
                 "zipfuse",
             ],
         },
     },
+    arch: {
+        // b/273792258: These could be in multilib.lib64 except that
+        // microdroid_crashdump_kernel doesn't exist for riscv64 yet
+        arm64: {
+            deps: [
+                "microdroid_crashdump_kernel",
+            ],
+        },
+        x86_64: {
+            deps: [
+                "microdroid_crashdump_kernel",
+            ],
+        },
+    },
     linker_config_src: "linker.config.json",
     base_dir: "system",
     dirs: microdroid_rootdirs,
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 78500af..6330b20 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -23,17 +23,17 @@
 }
 
 genrule {
-    name: "test_avf_debug_policy_with_console_output",
+    name: "test_avf_debug_policy_with_log.dtbo",
     defaults: ["test_avf_debug_policy_overlay"],
-    srcs: ["assets/avf_debug_policy_with_console_output.dts"],
-    out: ["avf_debug_policy_with_console_output.dtbo"],
+    srcs: ["assets/avf_debug_policy_with_log.dts"],
+    out: ["avf_debug_policy_with_log.dtbo"],
 }
 
 genrule {
-    name: "test_avf_debug_policy_without_console_output",
+    name: "test_avf_debug_policy_without_log.dtbo",
     defaults: ["test_avf_debug_policy_overlay"],
-    srcs: ["assets/avf_debug_policy_without_console_output.dts"],
-    out: ["avf_debug_policy_without_console_output.dtbo"],
+    srcs: ["assets/avf_debug_policy_without_log.dts"],
+    out: ["avf_debug_policy_without_log.dtbo"],
 }
 
 genrule {
@@ -76,8 +76,8 @@
         ":pvmfw_test",
         ":test_avf_debug_policy_with_ramdump",
         ":test_avf_debug_policy_without_ramdump",
-        ":test_avf_debug_policy_with_console_output",
-        ":test_avf_debug_policy_without_console_output",
+        ":test_avf_debug_policy_with_log.dtbo",
+        ":test_avf_debug_policy_without_log.dtbo",
         ":test_avf_debug_policy_with_adb",
         ":test_avf_debug_policy_without_adb",
         "assets/bcc.dat",
diff --git a/tests/hostside/assets/avf_debug_policy_with_console_output.dts b/tests/hostside/assets/avf_debug_policy_with_log.dts
similarity index 100%
rename from tests/hostside/assets/avf_debug_policy_with_console_output.dts
rename to tests/hostside/assets/avf_debug_policy_with_log.dts
diff --git a/tests/hostside/assets/avf_debug_policy_without_console_output.dts b/tests/hostside/assets/avf_debug_policy_without_log.dts
similarity index 100%
rename from tests/hostside/assets/avf_debug_policy_without_console_output.dts
rename to tests/hostside/assets/avf_debug_policy_without_log.dts
diff --git a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
index 10f7003..0d64442 100644
--- a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
@@ -23,6 +23,7 @@
 
 import static org.junit.Assume.assumeTrue;
 import static org.junit.Assume.assumeFalse;
+import static org.junit.Assert.assertThrows;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -31,8 +32,9 @@
 import com.android.microdroid.test.host.MicrodroidHostTestCaseBase;
 import com.android.microdroid.test.host.Pvmfw;
 import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.TestDevice;
+import com.android.tradefed.device.DeviceRuntimeException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.TestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.util.CommandStatus;
 import com.android.tradefed.util.CommandResult;
@@ -68,6 +70,9 @@
     @NonNull private static final String CUSTOM_PVMFW_IMG_PATH = TEST_ROOT + PVMFW_FILE_NAME;
     @NonNull private static final String CUSTOM_PVMFW_IMG_PATH_PROP = "hypervisor.pvmfw.path";
 
+    @NonNull
+    private static final String AVF_DEBUG_POLICY_ADB_DT_PROP_PATH = "/avf/guest/microdroid/adb";
+
     @NonNull private static final String MICRODROID_CMDLINE_PATH = "/proc/cmdline";
     @NonNull private static final String MICRODROID_DT_ROOT_PATH = "/proc/device-tree";
 
@@ -173,8 +178,8 @@
     }
 
     @Test
-    public void testConsoleOutput() throws Exception {
-        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_console_output.dtbo");
+    public void testLog_consoleOutput() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_log.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
 
         CommandResult result = tryLaunchProtectedNonDebuggableVm();
@@ -185,8 +190,20 @@
     }
 
     @Test
-    public void testNoConsoleOutput() throws Exception {
-        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_console_output.dtbo");
+    public void testLog_logcat() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_log.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        tryLaunchProtectedNonDebuggableVm();
+
+        assertWithMessage("Microdroid's logcat should have been enabled")
+                .that(hasMicrodroidLogcatOutput())
+                .isTrue();
+    }
+
+    @Test
+    public void testNoLog_noConsoleOutput() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_log.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
 
         CommandResult result = tryLaunchProtectedNonDebuggableVm();
@@ -197,6 +214,32 @@
     }
 
     @Test
+    public void testNoLog_noLogcat() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_log.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        assertThrows(
+                "Microdroid shouldn't be recognized because of missing adb connection",
+                DeviceRuntimeException.class,
+                () ->
+                        launchProtectedVmAndWaitForBootCompleted(
+                                MICRODROID_DEBUG_NONE, BOOT_FAILURE_WAIT_TIME_MS));
+        assertThat(hasMicrodroidLogcatOutput()).isFalse();
+    }
+
+    @Test
+    public void testAdb_boots() throws Exception {
+        assumeTrue(
+                "Skip if host wouldn't install adbd",
+                isDebugPolicyEnabled(AVF_DEBUG_POLICY_ADB_DT_PROP_PATH));
+
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_adb.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+
+        launchProtectedVmAndWaitForBootCompleted(MICRODROID_DEBUG_NONE);
+    }
+
+    @Test
     public void testNoAdb_boots() throws Exception {
         Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_adb.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
@@ -214,13 +257,23 @@
         Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_adb.dtbo");
         pvmfw.serialize(mCustomPvmfwBinFileOnHost);
 
-        try {
-            launchProtectedVmAndWaitForBootCompleted(
-                    MICRODROID_DEBUG_NONE, BOOT_FAILURE_WAIT_TIME_MS);
-            assertWithMessage("adb shouldn't be available").fail();
-        } catch (Exception e) {
-            // expected exception. passthrough.
+        assertThrows(
+                "Microdroid shouldn't be recognized because of missing adb connection",
+                DeviceRuntimeException.class,
+                () ->
+                        launchProtectedVmAndWaitForBootCompleted(
+                                MICRODROID_DEBUG_NONE, BOOT_FAILURE_WAIT_TIME_MS));
+    }
+
+    private boolean isDebugPolicyEnabled(@NonNull String dtPropertyPath)
+            throws DeviceNotAvailableException {
+        CommandRunner runner = new CommandRunner(mAndroidDevice);
+        CommandResult result =
+                runner.runForResult("xxd", "-p", "/proc/device-tree" + dtPropertyPath);
+        if (result.getStatus() == CommandStatus.SUCCESS) {
+            return HEX_STRING_ONE.equals(result.getStdout().trim());
         }
+        return false;
     }
 
     @NonNull
@@ -245,11 +298,17 @@
                 .build();
     }
 
-    @NonNull
-    private boolean hasConsoleOutput(CommandResult result) throws DeviceNotAvailableException {
+    private boolean hasConsoleOutput(@NonNull CommandResult result)
+            throws DeviceNotAvailableException {
         return result.getStdout().contains("Run /init as init process");
     }
 
+    private boolean hasMicrodroidLogcatOutput() throws DeviceNotAvailableException {
+        CommandResult result =
+                new CommandRunner(mAndroidDevice).runForResult("test", "-s", MICRODROID_LOG_PATH);
+        return result.getExitCode() == 0;
+    }
+
     private ITestDevice launchProtectedVmAndWaitForBootCompleted(String debugLevel)
             throws DeviceNotAvailableException {
         return launchProtectedVmAndWaitForBootCompleted(debugLevel, BOOT_COMPLETE_TIMEOUT_MS);
@@ -271,10 +330,10 @@
     }
 
     // Try to launch protected non-debuggable VM for a while and quit.
-    // Non-debuggable VM doesn't enable adb, so there's no ITestDevice instance of it.
+    // Non-debuggable VM might not enable adb, so there's no ITestDevice instance of it.
     private CommandResult tryLaunchProtectedNonDebuggableVm() throws DeviceNotAvailableException {
         // Can't use MicrodroidBuilder because it expects adb connection
-        // but non-debuggable VM doesn't enable adb.
+        // but non-debuggable VM may not enable adb.
         CommandRunner runner = new CommandRunner(mAndroidDevice);
         runner.run("mkdir", "-p", TEST_ROOT);
         mAndroidDevice.pushFile(mCustomPvmfwBinFileOnHost, TEST_ROOT + PVMFW_FILE_NAME);