Merge "crosvm merge: updated create_disk_file arguments"
diff --git a/authfs/tests/Android.bp b/authfs/tests/Android.bp
index 1b5cf09..61a6ef5 100644
--- a/authfs/tests/Android.bp
+++ b/authfs/tests/Android.bp
@@ -14,7 +14,8 @@
         "VirtualizationTestHelper",
     ],
     test_suites: ["general-tests"],
-    data_device_bins: ["open_then_run"],
+    //TODO(b/235263148) use data_device_bins_64
+    data_device_bins_first: ["open_then_run"],
     per_testcase_directory: true,
     data: [
         ":authfs_test_files",
diff --git a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
index cf852e3..479ae7f 100644
--- a/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
+++ b/compos/service/java/com/android/server/compos/IsolatedCompilationJobService.java
@@ -204,7 +204,7 @@
                 Log.w(TAG, "Failed to cancel CompilationTask", e);
             }
 
-            mMetrics.onCompilationEnded(IsolatedCompilationMetrics.RESULT_JOB_CANCELED);
+            mMetrics.onCompilationJobCanceled(mParams.getStopReason());
             try {
                 task.asBinder().unlinkToDeath(this, 0);
             } catch (NoSuchElementException e) {
diff --git a/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java b/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java
index 0ed2305..e333198 100644
--- a/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java
+++ b/compos/service/java/com/android/server/compos/IsolatedCompilationMetrics.java
@@ -17,6 +17,7 @@
 package com.android.server.compos;
 
 import android.annotation.IntDef;
+import android.app.job.JobParameters;
 import android.os.SystemClock;
 import android.util.Log;
 
@@ -76,7 +77,6 @@
     private long mCompilationStartTimeMs = 0;
 
     public static void onCompilationScheduled(@ScheduleJobResult int result) {
-        // TODO(b/218525257): write to ArtStatsLog instead of logcat
         ArtStatsLog.write(ArtStatsLog.ISOLATED_COMPILATION_SCHEDULED, result);
         Log.i(TAG, "ISOLATED_COMPILATION_SCHEDULED: " + result);
     }
@@ -85,13 +85,24 @@
         mCompilationStartTimeMs = SystemClock.elapsedRealtime();
     }
 
+    public void onCompilationJobCanceled(@JobParameters.StopReason int jobStopReason) {
+        statsLogPostCompilation(RESULT_JOB_CANCELED, jobStopReason);
+    }
+
     public void onCompilationEnded(@CompilationResult int result) {
+        statsLogPostCompilation(result, JobParameters.STOP_REASON_UNDEFINED);
+    }
+
+    private void statsLogPostCompilation(@CompilationResult int result,
+                @JobParameters.StopReason int jobStopReason) {
+
         long compilationTime = mCompilationStartTimeMs == 0 ? -1
                 : SystemClock.elapsedRealtime() - mCompilationStartTimeMs;
         mCompilationStartTimeMs = 0;
 
-        // TODO(b/218525257): write to ArtStatsLog instead of logcat
-        ArtStatsLog.write(ArtStatsLog.ISOLATED_COMPILATION_ENDED, compilationTime, result);
-        Log.i(TAG, "ISOLATED_COMPILATION_ENDED: " + result + ", " + compilationTime);
+        ArtStatsLog.write(ArtStatsLog.ISOLATED_COMPILATION_ENDED, compilationTime,
+                result, jobStopReason);
+        Log.i(TAG, "ISOLATED_COMPILATION_ENDED: " + result + ", " + compilationTime
+                + ", " + jobStopReason);
     }
 }
diff --git a/libs/apkverify/Android.bp b/libs/apkverify/Android.bp
index 2445dd5..d45a77f 100644
--- a/libs/apkverify/Android.bp
+++ b/libs/apkverify/Android.bp
@@ -24,6 +24,7 @@
     defaults: ["libapkverify.defaults"],
     // TODO(b/204562227): move to host_supported to the defaults to include tests
     host_supported: true,
+    apex_available: ["com.android.virt"],
 }
 
 rust_test {
diff --git a/libs/apkverify/src/lib.rs b/libs/apkverify/src/lib.rs
index 290a79a..c5aa9e5 100644
--- a/libs/apkverify/src/lib.rs
+++ b/libs/apkverify/src/lib.rs
@@ -24,4 +24,4 @@
 mod ziputil;
 
 // TODO(jooyung) fallback to v2 when v3 not found
-pub use v3::{get_public_key_der, verify};
+pub use v3::{get_public_key_der, pick_v4_apk_digest, verify};
diff --git a/libs/apkverify/src/sigutil.rs b/libs/apkverify/src/sigutil.rs
index 009154f..2b2f9da 100644
--- a/libs/apkverify/src/sigutil.rs
+++ b/libs/apkverify/src/sigutil.rs
@@ -282,6 +282,7 @@
     }
 }
 
+/// Rank the signature algorithm according to the preferences of the v4 signing scheme.
 pub fn rank_signature_algorithm(algo: u32) -> Result<u32> {
     rank_content_digest_algorithm(to_content_digest_algorithm(algo)?)
 }
diff --git a/libs/apkverify/src/v3.rs b/libs/apkverify/src/v3.rs
index 16530be..96ca7bc 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -128,16 +128,43 @@
     })
 }
 
+/// Gets the APK digest.
+pub fn pick_v4_apk_digest<R: Read + Seek>(apk: R) -> Result<(u32, Box<[u8]>)> {
+    let mut sections = ApkSections::new(apk)?;
+    let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
+    let signers = block.read::<Signers>()?;
+    if signers.len() != 1 {
+        bail!("should only have one signer");
+    }
+    signers[0].pick_v4_apk_digest()
+}
+
 impl Signer {
-    fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<Box<[u8]>> {
-        // 1. Choose the strongest supported signature algorithm ID from signatures. The strength
-        //    ordering is up to each implementation/platform version.
-        let strongest: &Signature = self
+    /// Select the signature that uses the strongest algorithm according to the preferences of the
+    /// v4 signing scheme.
+    fn strongest_signature(&self) -> Result<&Signature> {
+        Ok(self
             .signatures
             .iter()
             .filter(|sig| is_supported_signature_algorithm(sig.signature_algorithm_id))
             .max_by_key(|sig| rank_signature_algorithm(sig.signature_algorithm_id).unwrap())
-            .ok_or_else(|| anyhow!("No supported signatures found"))?;
+            .ok_or_else(|| anyhow!("No supported signatures found"))?)
+    }
+
+    fn pick_v4_apk_digest(&self) -> Result<(u32, Box<[u8]>)> {
+        let strongest = self.strongest_signature()?;
+        let signed_data: SignedData = self.signed_data.slice(..).read()?;
+        let digest = signed_data
+            .digests
+            .iter()
+            .find(|&dig| dig.signature_algorithm_id == strongest.signature_algorithm_id)
+            .ok_or_else(|| anyhow!("Digest not found"))?;
+        Ok((digest.signature_algorithm_id, digest.digest.as_ref().to_vec().into_boxed_slice()))
+    }
+
+    fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<Box<[u8]>> {
+        // 1. Choose the strongest supported signature algorithm ID from signatures.
+        let strongest = self.strongest_signature()?;
 
         // 2. Verify the corresponding signature from signatures against signed data using public key.
         //    (It is now safe to parse signed data.)
diff --git a/libs/idsig/Android.bp b/libs/idsig/Android.bp
index 2e9c663..25eeae4 100644
--- a/libs/idsig/Android.bp
+++ b/libs/idsig/Android.bp
@@ -10,6 +10,7 @@
     prefer_rlib: true,
     rustlibs: [
         "libanyhow",
+        "libapkverify",
         "libbyteorder",
         "libnum_traits",
         "libopenssl",
diff --git a/libs/idsig/src/apksigv4.rs b/libs/idsig/src/apksigv4.rs
index 3004ed1..db8a8c6 100644
--- a/libs/idsig/src/apksigv4.rs
+++ b/libs/idsig/src/apksigv4.rs
@@ -15,6 +15,7 @@
  */
 
 use anyhow::{anyhow, bail, Context, Result};
+use apkverify::pick_v4_apk_digest;
 use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 use num_derive::{FromPrimitive, ToPrimitive};
 use num_traits::{FromPrimitive, ToPrimitive};
@@ -190,9 +191,12 @@
         ret.hashing_info.raw_root_hash = hash_tree.root_hash.into_boxed_slice();
         ret.hashing_info.log2_blocksize = log2(block_size);
 
-        // TODO(jiyong): fill the signing_info struct by reading the APK file. The information,
-        // especially `apk_digest` is needed to check if `V4Signature` is outdated, in which case
-        // it needs to be created from the updated APK.
+        apk.seek(SeekFrom::Start(start))?;
+        let (signature_algorithm_id, apk_digest) = pick_v4_apk_digest(apk)?;
+        ret.signing_info.signature_algorithm_id =
+            SignatureAlgorithmId::from(signature_algorithm_id)?;
+        ret.signing_info.apk_digest = apk_digest;
+        // TODO(jiyong): add a signature to the signing_info struct
 
         Ok(ret)
     }
diff --git a/microdroid/bootconfig.common b/microdroid/bootconfig.common
index eda95a2..362ff23 100644
--- a/microdroid/bootconfig.common
+++ b/microdroid/bootconfig.common
@@ -1,2 +1,3 @@
 androidboot.first_stage_console = 1
 androidboot.hardware = microdroid
+kernel.8250.nr_uarts = 2
diff --git a/vmbase/README.md b/vmbase/README.md
new file mode 100644
index 0000000..42b9d7b
--- /dev/null
+++ b/vmbase/README.md
@@ -0,0 +1,186 @@
+# vmbase
+
+This directory contains a Rust crate and static library which can be used to write `no_std` Rust
+binaries to run in an aarch64 VM under crosvm (via the VirtualizationService), such as for pVM
+firmware, a VM bootloader or kernel.
+
+In particular it provides:
+
+- An [entry point](entry.S) that initialises the MMU with a hard-coded identity mapping, enables the
+  cache, prepares the image and allocates a stack.
+- An [exception vector](exceptions.S) to call your exception handlers.
+- A UART driver and `println!` macro for early console logging.
+- Functions to shutdown or reboot the VM.
+
+Libraries are also available for heap allocation, page table manipulation and PSCI calls.
+
+## Usage
+
+The [example](example/) subdirectory contains an example of how to use it for a VM bootloader.
+
+### Build file
+
+Start by creating a `rust_ffi_static` rule containing your main module:
+
+```soong
+rust_ffi_static {
+    name: "libvmbase_example",
+    crate_name: "vmbase_example",
+    srcs: ["src/main.rs"],
+    edition: "2021",
+    no_stdlibs: true,
+    stdlibs: [
+        "libcompiler_builtins.rust_sysroot",
+        "libcore.rust_sysroot",
+    ],
+    rustlibs: [
+        "libvmbase",
+    ],
+    enabled: false,
+    target: {
+        android_arm64: {
+            enabled: true,
+        },
+    },
+}
+```
+
+Note that stdlibs must be explicitly specified, as we don't want the normal set of libraries used
+for a C++ binary intended to run in Android userspace.
+
+### Entry point
+
+Your main module needs to specify a couple of special attributes:
+
+```rust
+#![no_main]
+#![no_std]
+```
+
+This tells rustc that it doesn't depend on `std`, and won't have the usual `main` function as an
+entry point. Instead, `vmbase` provides a macro to specify your main function:
+
+```rust
+use vmbase::{main, println};
+
+main!(main);
+
+pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
+    println!("Hello world");
+}
+```
+
+vmbase adds a wrapper around your main function to initialise the console driver first (with the
+UART at base address `0x3f8`, the first UART allocated by crosvm), and make a PSCI `SYSTEM_OFF` call
+to shutdown the VM if your main function ever returns.
+
+You can also shutdown the VM by calling `vmbase::power::shutdown` or 'reboot' by calling
+`vmbase::power::reboot`. Either will cause crosvm to terminate the VM, but by convention we use
+shutdown to indicate that the VM has finished cleanly, and reboot to indicate an error condition.
+
+### Exception handlers
+
+You must provide handlers for each of the 8 types of exceptions which can occur on aarch64. These
+must use the C ABI, and have the expected names. For example, to log sync exceptions and reboot:
+
+```rust
+use vmbase::{console::emergency_write_str, power::reboot};
+
+extern "C" fn sync_exception_current() {
+    emergency_write_str("sync_exception_current\n");
+
+    let mut esr: u64;
+    unsafe {
+        asm!("mrs {esr}, esr_el1", esr = out(reg) esr);
+    }
+    eprintln!("esr={:#08x}", esr);
+
+    reboot();
+}
+```
+
+The `println!` macro shouldn't be used in exception handlers, because it relies on a global instance
+of the UART driver which might be locked when the exception happens, which would result in deadlock.
+Instead you can use `emergency_write_str` and `eprintln!`, which will re-initialise the UART every
+time to ensure that it can be used. This should still be used with care, as it may interfere with
+whatever the rest of the program is doing with the UART.
+
+Note also that in some cases when the system is in a bad state resulting in the stack not working
+properly, `eprintln!` may hang. `emergency_write_str` may be more reliable as it seems to avoid
+any stack allocation. This is why the example above uses `emergency_write_str` first to ensure that
+at least something is logged, before trying `eprintln!` to print more details.
+
+See [example/src/exceptions.rs](examples/src/exceptions.rs) for a complete example.
+
+### Linker script and initial idmap
+
+The [entry point](entry.S) code expects to be provided a hardcoded identity-mapped page table to use
+initially. This must contain at least the region where the image itself is loaded, some writable
+DRAM to use for the `.bss` and `.data` sections and stack, and a device mapping for the UART MMIO
+region. See the [example/idmap.S](example/idmap.S) for an example of how this can be constructed.
+
+The addresses in the pagetable must map the addresses the image is linked at, as we don't support
+relocation. This can be achieved with a linker script, like the one in
+[example/image.ld](example/image.ld). The key part is the regions provided to be used for the image
+and writable data:
+
+```ld
+MEMORY
+{
+	image		    : ORIGIN = 0x80200000, LENGTH = 2M
+	writable_data	: ORIGIN = 0x80400000, LENGTH = 2M
+}
+```
+
+### Building a binary
+
+To link your Rust code together with the entry point code and idmap into a static binary, you need
+to use a `cc_binary` rule:
+
+```soong
+cc_binary {
+    name: "vmbase_example_elf",
+    stem: "vmbase_example",
+    srcs: [
+        "idmap.S",
+    ],
+    static_libs: [
+        "libvmbase_entry",
+        "libvmbase_example",
+    ],
+    static_executable: true,
+    nocrt: true,
+    system_shared_libs: ["libc"],
+    stl: "none",
+    linker_scripts: ["image.ld"],
+    installable: false,
+    enabled: false,
+    target: {
+        android_arm64: {
+            enabled: true,
+        },
+    },
+}
+```
+
+This takes your Rust library (`libvmbase_example`), the vmbase library entry point and exception
+vector (`libvmbase_entry`) and your initial idmap (`idmap.S`) and builds a static binary with your
+linker script (`image.ld`). This is an ELF binary, but to run it as a VM bootloader you need to
+`objcopy` it to a raw binary image instead, which you can do with a `raw_binary` rule:
+
+```soong
+raw_binary {
+    name: "vmbase_example",
+    src: ":vmbase_example_elf",
+    stem: "vmbase_example.bin",
+    enabled: false,
+    target: {
+        android_arm64: {
+            enabled: true,
+        },
+    },
+}
+```
+
+The resulting binary can then be used to start a VM by passing it as the bootloader in a
+`VirtualMachineRawConfig`.