Merge "exceptions_panic: Fix wrong PSCI function ID"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c967473..ea81bc4 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "avf-presubmit": [
     {
       "name": "MicrodroidHostTestCases"
     },
@@ -19,7 +19,7 @@
       "name": "compos_key_tests"
     }
   ],
-  "postsubmit": [
+  "avf-postsubmit": [
     {
       "name": "odsign_e2e_tests_full"
     },
diff --git a/apkdmverity/TEST_MAPPING b/apkdmverity/TEST_MAPPING
index 997b3f9..89750a8 100644
--- a/apkdmverity/TEST_MAPPING
+++ b/apkdmverity/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "postsubmit" : [
+  "avf-postsubmit" : [
     {
       "name" : "apkdmverity.test"
     }
diff --git a/authfs/TEST_MAPPING b/authfs/TEST_MAPPING
index 14f1824..3c84b76 100644
--- a/authfs/TEST_MAPPING
+++ b/authfs/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "avf-presubmit": [
     {
       "name": "authfs_device_test_src_lib"
     },
diff --git a/avmd/Android.bp b/avmd/Android.bp
index b09bed5..dc6a896 100644
--- a/avmd/Android.bp
+++ b/avmd/Android.bp
@@ -36,15 +36,11 @@
     ],
 }
 
-rust_test_host {
+rust_test {
     name: "avmdtool_tests",
     srcs: ["tests/*_test.rs"],
     test_suites: ["general-tests"],
-    prefer_rlib: true,
-    data: ["tests/data/*"],
+    compile_multilib: "first",
     data_bins: ["avmdtool"],
-    data_libs: [
-        "libcrypto",
-        "libz",
-    ],
+    data: ["tests/data/*"],
 }
diff --git a/avmd/TEST_MAPPING b/avmd/TEST_MAPPING
index dd687fe..ea58edb 100644
--- a/avmd/TEST_MAPPING
+++ b/avmd/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit" : [
+  "avf-presubmit" : [
     {
       "name" : "avmdtool_tests"
     }
diff --git a/libs/apkverify/TEST_MAPPING b/libs/apkverify/TEST_MAPPING
index 9248716..7224fc7 100644
--- a/libs/apkverify/TEST_MAPPING
+++ b/libs/apkverify/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit" : [
+  "avf-presubmit" : [
     {
       "name" : "libapkverify.test"
     },
diff --git a/libs/vbmeta/TEST_MAPPING b/libs/vbmeta/TEST_MAPPING
index adfcf89..e42aea0 100644
--- a/libs/vbmeta/TEST_MAPPING
+++ b/libs/vbmeta/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit" : [
+  "avf-presubmit" : [
     {
       "name" : "libvbmeta_rust.test"
     }
diff --git a/microdroid/README.md b/microdroid/README.md
index 6e5d709..fef71ce 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -162,8 +162,9 @@
 ## ADB
 
 On userdebug builds, you can have an adb connection to microdroid. To do so,
-first, add the `--debug=full` flag to the `/apex/com.android.virt/bin/vm
-run-app` command, and then
+first, delete `$TEST_ROOT/instance.img`; this is because changing debug settings
+requires a new instance. Then add the `--debug=full` flag to the
+`/apex/com.android.virt/bin/vm run-app` command, and then
 
 ```sh
 adb forward tcp:8000 vsock:$CID:5555
diff --git a/rialto/TEST_MAPPING b/rialto/TEST_MAPPING
index 8e3c085..88f616e 100644
--- a/rialto/TEST_MAPPING
+++ b/rialto/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "avf-presubmit": [
     {
       "name": "rialto_test"
     }
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
index fb92467..76bfafb 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
@@ -36,6 +36,7 @@
 import com.android.tradefed.result.TestDescription;
 import com.android.tradefed.result.TestResult;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.FileUtil;
@@ -58,6 +59,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -80,6 +82,7 @@
 
     @Rule public TestLogData mTestLogs = new TestLogData();
     @Rule public TestName mTestName = new TestName();
+    @Rule public TestMetrics mMetrics = new TestMetrics();
 
     private int minMemorySize() throws DeviceNotAvailableException {
         CommandRunner android = new CommandRunner(getDevice());
@@ -545,6 +548,92 @@
         shutdownMicrodroid(getDevice(), cid);
     }
 
+    private static class ProcessInfo {
+        public final String mName;
+        public final int mPid;
+
+        ProcessInfo(String name, int pid) {
+            mName = name;
+            mPid = pid;
+        }
+    }
+
+    private Map<String, Long> parseMemInfo(String file) {
+        Map<String, Long> stats = new HashMap<>();
+        file.lines().forEach(line -> {
+            if (line.endsWith(" kB")) line = line.substring(0, line.length() - 3);
+
+            String[] elems = line.split(":");
+            assertThat(elems.length).isEqualTo(2);
+            stats.put(elems[0].trim(), Long.parseLong(elems[1].trim()));
+        });
+        return stats;
+    }
+
+    private String skipFirstLine(String str) {
+        int index = str.indexOf("\n");
+        return (index < 0) ? "" : str.substring(index + 1);
+    }
+
+    private List<ProcessInfo> getRunningProcessesList() {
+        List<ProcessInfo> list = new ArrayList<ProcessInfo>();
+        skipFirstLine(runOnMicrodroid("ps", "-Ao", "PID,NAME")).lines().forEach(ps -> {
+            // Each line is '  <pid> <name>'.
+            ps = ps.trim();
+            int space = ps.indexOf(" ");
+            list.add(new ProcessInfo(
+                    ps.substring(space + 1),
+                    Integer.parseInt(ps.substring(0, space))));
+        });
+
+        return list;
+    }
+
+    private Map<String, Long> getProcMemInfo() {
+        return parseMemInfo(runOnMicrodroid("cat", "/proc/meminfo"));
+    }
+
+    private Map<String, Long> getProcSmapsRollup(int pid) {
+        String path = "/proc/" + pid + "/smaps_rollup";
+        return  parseMemInfo(skipFirstLine(runOnMicrodroid("cat", path, "||", "true")));
+    }
+
+    @Test
+    public void testMicrodroidRamUsage() throws Exception {
+        final String configPath = "assets/vm_config.json";
+        final String cid =
+                startMicrodroid(
+                        getDevice(),
+                        getBuild(),
+                        APK_NAME,
+                        PACKAGE_NAME,
+                        configPath,
+                        /* debug */ true,
+                        minMemorySize(),
+                        Optional.of(NUM_VCPUS),
+                        Optional.of(CPU_AFFINITY));
+        adbConnectToMicrodroid(getDevice(), cid);
+        waitForBootComplete();
+        rootMicrodroid();
+
+        for (Map.Entry<String, Long> stat : getProcMemInfo().entrySet()) {
+            mMetrics.addTestMetric(
+                    "avf_perf/microdroid/meminfo/" + stat.getKey().toLowerCase(),
+                    stat.getValue().toString());
+        }
+
+        for (ProcessInfo proc : getRunningProcessesList()) {
+            for (Map.Entry<String, Long> stat : getProcSmapsRollup(proc.mPid).entrySet()) {
+                String name = stat.getKey().toLowerCase();
+                mMetrics.addTestMetric(
+                        "avf_perf/microdroid/smaps/" + name + "/" + proc.mName,
+                        stat.getValue().toString());
+            }
+        }
+
+        shutdownMicrodroid(getDevice(), cid);
+    }
+
     @Test
     public void testCustomVirtualMachinePermission()
             throws DeviceNotAvailableException, IOException, JSONException {
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 29a74ca..60912ea 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -25,6 +25,7 @@
     use_embedded_native_libs: true,
     // We only support 64-bit ABI, but CTS demands all APKs to be multi-ABI.
     compile_multilib: "both",
+    min_sdk_version: "33",
 }
 
 // TODO(jiyong): make this a binary, not a shared library
diff --git a/tests/testapk/AndroidManifest.xml b/tests/testapk/AndroidManifest.xml
index bc955d2..9c8b2d5 100644
--- a/tests/testapk/AndroidManifest.xml
+++ b/tests/testapk/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.microdroid.test">
     <uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
+    <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
     <application>
         <uses-library android:name="android.system.virtualmachine" android:required="false" />
     </application>
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 db2ca0f..911efbb 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -358,9 +358,9 @@
         List<DataItem> rootArrayItems = ((Array) dataItems.get(0)).getDataItems();
         assertThat(rootArrayItems.size()).isAtLeast(2); // Public key and one certificate
         if (mProtectedVm) {
-            // When a true BCC is created, microdroid expects entries for at least: the root public
-            // key, pvmfw, u-boot, u-boot-env, microdroid, app payload and the service process.
-            assertThat(rootArrayItems.size()).isAtLeast(7);
+            // When a true DICE chain is created, microdroid expects entries for: u-boot,
+            // u-boot-env, microdroid, app payload and the service process.
+            assertThat(rootArrayItems.size()).isAtLeast(5);
         }
     }
 
diff --git a/virtualizationservice/TEST_MAPPING b/virtualizationservice/TEST_MAPPING
index 6456a98..8388ff2 100644
--- a/virtualizationservice/TEST_MAPPING
+++ b/virtualizationservice/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "avf-presubmit": [
     {
       "name": "virtualizationservice_device_test"
     }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index bba75ac..5bc646f 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -14,6 +14,7 @@
 
 //! Implementation of the AIDL interface of the VirtualizationService.
 
+use crate::atom::write_vm_creation_stats;
 use crate::composite::make_composite_image;
 use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmInstance, VmState};
 use crate::payload::add_microdroid_images;
@@ -48,11 +49,10 @@
 use binder_common::rpc_server::run_rpc_server_with_factory;
 use disk::QcowFile;
 use idsig::{HashAlgorithm, V4Signature};
-use log::{debug, error, info, warn, trace};
+use log::{debug, error, info, warn};
 use microdroid_payload_config::VmPayloadConfig;
 use rustutils::system_properties;
 use semver::VersionReq;
-use statslog_virtualization_rust::vm_creation_requested::{stats_write, Hypervisor};
 use std::convert::TryInto;
 use std::ffi::CStr;
 use std::fs::{create_dir, File, OpenOptions};
@@ -131,23 +131,7 @@
     ) -> binder::Result<Strong<dyn IVirtualMachine>> {
         let mut is_protected = false;
         let ret = self.create_vm_internal(config, console_fd, log_fd, &mut is_protected);
-        match ret {
-            Ok(_) => {
-                let ok_status = Status::ok();
-                write_vm_creation_stats(
-                    is_protected,
-                    /*creation_succeeded*/ true,
-                    ok_status.exception_code() as i32,
-                );
-            }
-            Err(ref e) => {
-                write_vm_creation_stats(
-                    is_protected,
-                    /*creation_succeeded*/ false,
-                    e.exception_code() as i32,
-                );
-            }
-        }
+        write_vm_creation_stats(config, is_protected, &ret);
         ret
     }
 
@@ -506,16 +490,6 @@
     }
 }
 
-/// Write the stats of VMCreation to statsd
-fn write_vm_creation_stats(is_protected: bool, creation_succeeded: bool, exception_code: i32) {
-    match stats_write(Hypervisor::Pkvm, is_protected, creation_succeeded, exception_code) {
-        Err(e) => {
-            warn!("statslog_rust failed with error: {}", e);
-        }
-        Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
-    }
-}
-
 /// Waits for incoming connections from VM. If a new connection is made, stores the stream in the
 /// corresponding `VmInstance`.
 fn handle_stream_connection_from_vm(state: Arc<Mutex<State>>) -> Result<()> {
@@ -1003,7 +977,7 @@
 }
 
 /// Converts a `&ParcelFileDescriptor` to a `File` by cloning the file.
-fn clone_file(file: &ParcelFileDescriptor) -> Result<File, Status> {
+pub fn clone_file(file: &ParcelFileDescriptor) -> Result<File, Status> {
     file.as_ref().try_clone().map_err(|e| {
         Status::new_exception_str(
             ExceptionCode::BAD_PARCELABLE,
diff --git a/virtualizationservice/src/atom.rs b/virtualizationservice/src/atom.rs
new file mode 100644
index 0000000..960eaa7
--- /dev/null
+++ b/virtualizationservice/src/atom.rs
@@ -0,0 +1,114 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Functions for creating and collecting atoms.
+
+use crate::aidl::clone_file;
+use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
+    IVirtualMachine::IVirtualMachine, VirtualMachineAppConfig::VirtualMachineAppConfig,
+    VirtualMachineConfig::VirtualMachineConfig,
+};
+use android_system_virtualizationservice::binder::{Status, Strong};
+use anyhow::{anyhow, Result};
+use log::{trace, warn};
+use microdroid_payload_config::VmPayloadConfig;
+use statslog_virtualization_rust::vm_creation_requested;
+use zip::ZipArchive;
+
+fn get_vm_payload_config(config: &VirtualMachineAppConfig) -> Result<VmPayloadConfig> {
+    let apk = config.apk.as_ref().ok_or_else(|| anyhow!("APK is none"))?;
+    let apk_file = clone_file(apk)?;
+    let mut apk_zip = ZipArchive::new(&apk_file)?;
+    let config_file = apk_zip.by_name(&config.configPath)?;
+    let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
+    Ok(vm_payload_config)
+}
+
+/// Write the stats of VMCreation to statsd
+pub fn write_vm_creation_stats(
+    config: &VirtualMachineConfig,
+    is_protected: bool,
+    ret: &binder::Result<Strong<dyn IVirtualMachine>>,
+) {
+    let creation_succeeded;
+    let binder_exception_code;
+    match ret {
+        Ok(_) => {
+            creation_succeeded = true;
+            binder_exception_code = Status::ok().exception_code() as i32;
+        }
+        Err(ref e) => {
+            creation_succeeded = false;
+            binder_exception_code = e.exception_code() as i32;
+        }
+    }
+
+    let config_type;
+    let num_cpus;
+    let cpu_affinity;
+    let memory_mib;
+    let apexes;
+    match config {
+        VirtualMachineConfig::AppConfig(config) => {
+            config_type = vm_creation_requested::ConfigType::VirtualMachineAppConfig;
+            num_cpus = config.numCpus;
+            cpu_affinity = config.cpuAffinity.clone().unwrap_or_default();
+            memory_mib = config.memoryMib;
+
+            let vm_payload_config = get_vm_payload_config(config);
+            if let Ok(vm_payload_config) = vm_payload_config {
+                apexes = vm_payload_config
+                    .apexes
+                    .iter()
+                    .map(|x| x.name.clone())
+                    .collect::<Vec<String>>()
+                    .join(":");
+            } else {
+                apexes = "INFO: Can't get VmPayloadConfig".into();
+            }
+        }
+        VirtualMachineConfig::RawConfig(config) => {
+            config_type = vm_creation_requested::ConfigType::VirtualMachineRawConfig;
+            num_cpus = config.numCpus;
+            cpu_affinity = config.cpuAffinity.clone().unwrap_or_default();
+            memory_mib = config.memoryMib;
+            apexes = String::new();
+        }
+    }
+
+    let empty_string = String::new();
+    let vm_creation_requested = vm_creation_requested::VmCreationRequested {
+        // TODO(seungjaeyoo) Implement sending proper data about uid & vm_identifier
+        uid: -1,
+        vm_identifier: &empty_string,
+        hypervisor: vm_creation_requested::Hypervisor::Pkvm,
+        is_protected,
+        creation_succeeded,
+        binder_exception_code,
+        config_type,
+        num_cpus,
+        cpu_affinity: &cpu_affinity,
+        memory_mib,
+        apexes: &apexes,
+        // TODO(seungjaeyoo) Fill information about task_profile
+        // TODO(seungjaeyoo) Fill information about disk_image for raw config
+    };
+
+    match vm_creation_requested.stats_write() {
+        Err(e) => {
+            warn!("statslog_rust failed with error: {}", e);
+        }
+        Ok(_) => trace!("statslog_rust succeeded for virtualization service"),
+    }
+}
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 3e1a151..a7e82da 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -16,7 +16,7 @@
 
 use crate::aidl::VirtualMachineCallbacks;
 use crate::Cid;
-use anyhow::{bail, Context, Error};
+use anyhow::{anyhow, bail, Context, Error};
 use command_fds::CommandFdExt;
 use lazy_static::lazy_static;
 use log::{debug, error, info};
@@ -29,7 +29,7 @@
 use std::mem;
 use std::num::NonZeroU32;
 use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::process::{Command, ExitStatus};
 use std::sync::{Arc, Condvar, Mutex};
 use std::time::Duration;
@@ -38,6 +38,7 @@
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::DeathReason::DeathReason;
 use binder::Strong;
 use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
+use tombstoned_client::{TombstonedConnection, DebuggerdDumpType};
 
 const CROSVM_PATH: &str = "/apex/com.android.virt/bin/crosvm";
 
@@ -336,9 +337,30 @@
             let ramdump = File::open(&ramdump_path)
                 .context(format!("Failed to open ramdump {:?} for reading", &ramdump_path))?;
             self.callbacks.callback_on_ramdump(self.cid, ramdump);
+
+            Self::send_ramdump_to_tombstoned(&ramdump_path)?;
         }
         Ok(())
     }
+
+    fn send_ramdump_to_tombstoned(ramdump_path: &Path) -> Result<(), Error> {
+        let mut input = File::open(ramdump_path)
+            .context(format!("Failed to open raudmp {:?} for reading", ramdump_path))?;
+
+        let pid = std::process::id() as i32;
+        let conn = TombstonedConnection::connect(pid, DebuggerdDumpType::Tombstone)
+            .context("Failed to connect to tombstoned")?;
+        let mut output = conn
+            .text_output
+            .as_ref()
+            .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
+
+        std::io::copy(&mut input, &mut output).context("Failed to send ramdump to tombstoned")?;
+        info!("Ramdump {:?} sent to tombstoned", ramdump_path);
+
+        conn.notify_completion()?;
+        Ok(())
+    }
 }
 
 fn death_reason(result: &Result<ExitStatus, io::Error>, failure_reason: &str) -> DeathReason {
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index 3b0adb9..93a5966 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -15,6 +15,7 @@
 //! Android VirtualizationService
 
 mod aidl;
+mod atom;
 mod composite;
 mod crosvm;
 mod payload;
diff --git a/vmbase/TEST_MAPPING b/vmbase/TEST_MAPPING
index 9b7e4cb..c315b4a 100644
--- a/vmbase/TEST_MAPPING
+++ b/vmbase/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "avf-presubmit": [
     {
       "name": "vmbase_example.integration_test"
     }
diff --git a/zipfuse/TEST_MAPPING b/zipfuse/TEST_MAPPING
index ef398a0..13055f0 100644
--- a/zipfuse/TEST_MAPPING
+++ b/zipfuse/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit" : [
+  "avf-presubmit" : [
     {
       "name" : "ZipFuseTest"
     }