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`.