Merge changes from topic "avf_unprotected_crashkernel"
* changes:
Temporally disable tombstone tests
virtualizationservice: Specify crashkernel only when necessary
diff --git a/compos/common/lib.rs b/compos/common/lib.rs
index 8d49ff0..1f937c9 100644
--- a/compos/common/lib.rs
+++ b/compos/common/lib.rs
@@ -53,9 +53,6 @@
/// /system_ext available in CompOS.
pub const IDSIG_MANIFEST_EXT_APK_FILE: &str = "idsig_manifest_ext_apk";
-/// Number of CPUs to run dex2oat (actually the entire compos VM) with
-pub const DEX2OAT_THREADS_PROP_NAME: &str = "dalvik.vm.boot-dex2oat-threads";
-
/// The Android path of fs-verity build manifest APK for /system.
pub const BUILD_MANIFEST_APK_PATH: &str = "/system/etc/security/fsverity/BuildManifest.apk";
diff --git a/compos/composd/src/instance_manager.rs b/compos/composd/src/instance_manager.rs
index c4791e9..0a6c3d6 100644
--- a/compos/composd/src/instance_manager.rs
+++ b/compos/composd/src/instance_manager.rs
@@ -22,10 +22,8 @@
use anyhow::{bail, Result};
use binder::Strong;
use compos_common::compos_client::VmParameters;
-use compos_common::{CURRENT_INSTANCE_DIR, DEX2OAT_THREADS_PROP_NAME, TEST_INSTANCE_DIR};
-use rustutils::system_properties;
+use compos_common::{CURRENT_INSTANCE_DIR, TEST_INSTANCE_DIR};
use std::num::NonZeroU32;
-use std::str::FromStr;
use std::sync::{Arc, Mutex, Weak};
use virtualizationservice::IVirtualizationService::IVirtualizationService;
@@ -79,14 +77,10 @@
}
fn new_vm_parameters() -> Result<VmParameters> {
- let cpus = match system_properties::read(DEX2OAT_THREADS_PROP_NAME)? {
- Some(s) => Some(NonZeroU32::from_str(&s)?),
- None => {
- // dex2oat uses all CPUs by default. To match the behavior, give the VM all CPUs by
- // default.
- NonZeroU32::new(num_cpus::get() as u32)
- }
- };
+ // By default, dex2oat starts as many threads as there are CPUs. This can be overridden with
+ // a system property. Start the VM with all CPUs and assume the guest will start a suitable
+ // number of dex2oat threads.
+ let cpus = NonZeroU32::new(num_cpus::get() as u32);
let task_profiles = vec!["SCHED_SP_COMPUTE".to_string()];
Ok(VmParameters { cpus, task_profiles, memory_mib: Some(VM_MEMORY_MIB), ..Default::default() })
}
diff --git a/compos/verify/verify.rs b/compos/verify/verify.rs
index 71d8bcc..528719f 100644
--- a/compos/verify/verify.rs
+++ b/compos/verify/verify.rs
@@ -33,6 +33,7 @@
use log::error;
use std::fs::File;
use std::io::Read;
+use std::num::NonZeroU32;
use std::panic;
use std::path::Path;
@@ -114,7 +115,11 @@
&idsig,
&idsig_manifest_apk,
&idsig_manifest_ext_apk,
- &VmParameters { debug_mode: args.debug, ..Default::default() },
+ &VmParameters {
+ cpus: Some(NonZeroU32::new(1).unwrap()), // This VM runs very little work at boot
+ debug_mode: args.debug,
+ ..Default::default()
+ },
)?;
let service = vm_instance.connect_service()?;
diff --git a/libs/dice/src/bcc.rs b/libs/dice/src/bcc.rs
index 18b5083..b333781 100644
--- a/libs/dice/src/bcc.rs
+++ b/libs/dice/src/bcc.rs
@@ -28,9 +28,9 @@
use open_dice_bcc_bindgen::BCC_INPUT_COMPONENT_VERSION;
use open_dice_bcc_bindgen::BCC_INPUT_RESETTABLE;
-use crate::check_call;
+use crate::check_result;
use crate::Cdi;
-use crate::Error;
+use crate::DiceError;
use crate::InputValues;
use crate::Result;
@@ -56,7 +56,7 @@
// SAFETY - The buffer is only read and never stored and the returned pointers should all
// point within the address range of the buffer or be NULL.
- check_call(unsafe {
+ check_result(unsafe {
BccHandoverParse(
buffer.as_ptr(),
buffer.len(),
@@ -68,20 +68,20 @@
})?;
let cdi_attest = {
- let i = index_from_ptr(buffer, cdi_attest).ok_or(Error::PlatformError)?;
- let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?;
- s.try_into().map_err(|_| Error::PlatformError)?
+ let i = index_from_ptr(buffer, cdi_attest).ok_or(DiceError::PlatformError)?;
+ let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(DiceError::PlatformError)?;
+ s.try_into().map_err(|_| DiceError::PlatformError)?
};
let cdi_seal = {
- let i = index_from_ptr(buffer, cdi_seal).ok_or(Error::PlatformError)?;
- let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?;
- s.try_into().map_err(|_| Error::PlatformError)?
+ let i = index_from_ptr(buffer, cdi_seal).ok_or(DiceError::PlatformError)?;
+ let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(DiceError::PlatformError)?;
+ s.try_into().map_err(|_| DiceError::PlatformError)?
};
let bcc = if bcc.is_null() {
None
} else {
- let i = index_from_ptr(buffer, bcc).ok_or(Error::PlatformError)?;
- Some(buffer.get(i..(i + bcc_size)).ok_or(Error::PlatformError)?)
+ let i = index_from_ptr(buffer, bcc).ok_or(DiceError::PlatformError)?;
+ Some(buffer.get(i..(i + bcc_size)).ok_or(DiceError::PlatformError)?)
};
Ok(Self { buffer, cdi_attest, cdi_seal, bcc })
@@ -93,7 +93,7 @@
let mut size: usize = 0;
// SAFETY - The function only reads `self.buffer`, writes to `buffer` within its bounds,
// reads `input_values` as a constant input and doesn't store any pointer.
- check_call(unsafe {
+ check_result(unsafe {
BccHandoverMainFlow(
context,
self.buffer.as_ptr(),
@@ -148,7 +148,7 @@
// SAFETY - The function writes to the buffer, within the given bounds, and only reads the
// input values. It writes its result to buffer_size.
- check_call(unsafe {
+ check_result(unsafe {
BccFormatConfigDescriptor(
&values as *const _,
buffer.len(),
diff --git a/libs/dice/src/lib.rs b/libs/dice/src/lib.rs
index f0ac2ae..4a45ab4 100644
--- a/libs/dice/src/lib.rs
+++ b/libs/dice/src/lib.rs
@@ -18,62 +18,16 @@
#![no_std]
-use core::fmt;
-use core::result;
-
-pub use diced_open_dice::{Config, Hash, InputValues, HASH_SIZE};
+pub use diced_open_dice::{
+ check_result, Cdi, Config, DiceError, Hash, InputValues, Result, CDI_SIZE, HASH_SIZE,
+ HIDDEN_SIZE,
+};
pub use open_dice_cbor_bindgen::DiceMode;
use open_dice_cbor_bindgen::DiceHash;
-use open_dice_cbor_bindgen::DiceResult;
-use open_dice_cbor_bindgen::DiceResult_kDiceResultBufferTooSmall as DICE_RESULT_BUFFER_TOO_SMALL;
-use open_dice_cbor_bindgen::DiceResult_kDiceResultInvalidInput as DICE_RESULT_INVALID_INPUT;
-use open_dice_cbor_bindgen::DiceResult_kDiceResultOk as DICE_RESULT_OK;
-use open_dice_cbor_bindgen::DiceResult_kDiceResultPlatformError as DICE_RESULT_PLATFORM_ERROR;
pub mod bcc;
-const CDI_SIZE: usize = open_dice_cbor_bindgen::DICE_CDI_SIZE as usize;
-
-/// Array type of CDIs.
-pub type Cdi = [u8; CDI_SIZE];
-
-/// Error type used by DICE.
-pub enum Error {
- /// Provided input was invalid.
- InvalidInput,
- /// Provided buffer was too small.
- BufferTooSmall,
- /// Unexpected platform error.
- PlatformError,
- /// Unexpected return value.
- Unknown(DiceResult),
-}
-
-impl fmt::Debug for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- Error::InvalidInput => write!(f, "invalid input"),
- Error::BufferTooSmall => write!(f, "buffer too small"),
- Error::PlatformError => write!(f, "platform error"),
- Error::Unknown(n) => write!(f, "unknown error: {}", n),
- }
- }
-}
-
-/// Result of DICE functions.
-pub type Result<T> = result::Result<T, Error>;
-
-fn check_call(ret: DiceResult) -> Result<()> {
- match ret {
- DICE_RESULT_OK => Ok(()),
- DICE_RESULT_INVALID_INPUT => Err(Error::InvalidInput),
- DICE_RESULT_BUFFER_TOO_SMALL => Err(Error::BufferTooSmall),
- DICE_RESULT_PLATFORM_ERROR => Err(Error::PlatformError),
- n => Err(Error::Unknown(n)),
- }
-}
-
fn ctx() -> *mut core::ffi::c_void {
core::ptr::null_mut()
}
@@ -82,6 +36,6 @@
pub fn hash(bytes: &[u8]) -> Result<Hash> {
let mut output: Hash = [0; HASH_SIZE];
// SAFETY - DiceHash takes a sized input buffer and writes to a constant-sized output buffer.
- check_call(unsafe { DiceHash(ctx(), bytes.as_ptr(), bytes.len(), output.as_mut_ptr()) })?;
+ check_result(unsafe { DiceHash(ctx(), bytes.as_ptr(), bytes.len(), output.as_mut_ptr()) })?;
Ok(output)
}
diff --git a/microdroid_manager/src/dice.rs b/microdroid_manager/src/dice.rs
index 739c944..a7288b6 100644
--- a/microdroid_manager/src/dice.rs
+++ b/microdroid_manager/src/dice.rs
@@ -17,7 +17,7 @@
use anyhow::{bail, Context, Error, Result};
use byteorder::{NativeEndian, ReadBytesExt};
use diced_open_dice_cbor::{
- Config, ContextImpl, DiceMode, Hash, Hidden, InputValuesOwned, OpenDiceCborContext, CDI_SIZE,
+ Config, ContextImpl, DiceMode, Hash, Hidden, InputValues, OpenDiceCborContext, CDI_SIZE,
};
use keystore2_crypto::ZVec;
use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
@@ -142,11 +142,10 @@
debug: bool,
hidden: Hidden,
) -> Result<DiceContext> {
- let input_values = InputValuesOwned::new(
+ let input_values = InputValues::new(
code_hash,
Config::Descriptor(config_desc),
authority_hash,
- None,
if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
hidden,
);
diff --git a/pvmfw/src/dice.rs b/pvmfw/src/dice.rs
index 4e1e60a..42cc802 100644
--- a/pvmfw/src/dice.rs
+++ b/pvmfw/src/dice.rs
@@ -22,6 +22,7 @@
use dice::Config;
use dice::DiceMode;
use dice::InputValues;
+use dice::HIDDEN_SIZE;
use pvmfw_avb::{DebugLevel, Digest, VerifiedBootData};
fn to_dice_mode(debug_level: DebugLevel) -> DiceMode {
@@ -61,13 +62,11 @@
let config = &config_descriptor_buffer[..config_descriptor_size];
let input_values = InputValues::new(
- &code_hash,
- None, // code_descriptor
+ code_hash,
Config::Descriptor(config),
- &auth_hash,
- None, // authority_descriptor
+ auth_hash,
mode,
- None, // TODO(b/249723852): Get salt from instance.img (virtio-blk) and/or TRNG.
+ [0u8; HIDDEN_SIZE], // TODO(b/249723852): Get salt from instance.img (virtio-blk) and/or TRNG.
);
bcc.main_flow(&input_values, next_bcc)
diff --git a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
index f17000a..db87126 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -50,8 +50,11 @@
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.OptionalLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
@@ -136,102 +139,87 @@
mInstrumentation.sendStatus(0, bundle);
}
- @Test
- public void testMicrodroidBootTime()
+ private static class BootTimeStats {
+ private final Map<BootTimeMetric, List<Double>> mData = new HashMap<>();
+
+ public BootTimeStats(int trialCount) {
+ for (BootTimeMetric metric : BootTimeMetric.values()) {
+ mData.put(metric, new ArrayList<>(trialCount));
+ }
+ }
+
+ public void collect(BootResult result) {
+ for (BootTimeMetric metric : BootTimeMetric.values()) {
+ OptionalLong value = result.getBootTimeMetricNanoTime(metric);
+ if (value.isPresent()) {
+ mData.get(metric).add(value.getAsLong() / NANO_TO_MILLI);
+ }
+ }
+ }
+
+ public List<Double> get(BootTimeMetric metric) {
+ return Collections.unmodifiableList(mData.get(metric));
+ }
+ }
+
+ private BootTimeStats runBootTimeTest(
+ String name,
+ Function<VirtualMachineConfig.Builder, VirtualMachineConfig.Builder> fnConfig)
throws VirtualMachineException, InterruptedException, IOException {
assume().withMessage("Skip on CF; too slow").that(isCuttlefish()).isFalse();
final int trialCount = 10;
- List<Double> bootTimeMetrics = new ArrayList<>();
+ BootTimeStats stats = new BootTimeStats(trialCount);
for (int i = 0; i < trialCount; i++) {
- VirtualMachineConfig normalConfig =
+ VirtualMachineConfig.Builder builder =
newVmConfigBuilder()
.setPayloadBinaryName("MicrodroidIdleNativeLib.so")
- .setDebugLevel(DEBUG_LEVEL_NONE)
.setMemoryBytes(256 * ONE_MEBI)
- .build();
- forceCreateNewVirtualMachine("test_vm_boot_time", normalConfig);
+ .setDebugLevel(DEBUG_LEVEL_NONE);
+ VirtualMachineConfig config = fnConfig.apply(builder).build();
+ forceCreateNewVirtualMachine(name, config);
- BootResult result = tryBootVm(TAG, "test_vm_boot_time");
+ BootResult result = tryBootVm(TAG, name);
assertThat(result.payloadStarted).isTrue();
-
- bootTimeMetrics.add(result.endToEndNanoTime / NANO_TO_MILLI);
+ stats.collect(result);
}
+ return stats;
+ }
- reportMetrics(bootTimeMetrics, "boot_time", "ms");
+ @Test
+ public void testMicrodroidBootTime()
+ throws VirtualMachineException, InterruptedException, IOException {
+ BootTimeStats stats = runBootTimeTest("test_vm_boot_time", (builder) -> builder);
+ reportMetrics(stats.get(BootTimeMetric.TOTAL), "boot_time", "ms");
}
@Test
public void testMicrodroidMulticoreBootTime()
throws VirtualMachineException, InterruptedException, IOException {
- assume().withMessage("Skip on CF; too slow").that(isCuttlefish()).isFalse();
-
- final int trialCount = 10;
- final int[] trialNumCpus = {2, 4, 8};
-
- for (int numCpus : trialNumCpus) {
- List<Double> bootTimeMetrics = new ArrayList<>();
- for (int i = 0; i < trialCount; i++) {
- VirtualMachineConfig normalConfig =
- newVmConfigBuilder()
- .setPayloadBinaryName("MicrodroidIdleNativeLib.so")
- .setDebugLevel(DEBUG_LEVEL_NONE)
- .setMemoryBytes(256 * ONE_MEBI)
- .setNumCpus(numCpus)
- .build();
- forceCreateNewVirtualMachine("test_vm_boot_time_multicore", normalConfig);
-
- BootResult result = tryBootVm(TAG, "test_vm_boot_time_multicore");
- assertThat(result.payloadStarted).isTrue();
-
- bootTimeMetrics.add(result.endToEndNanoTime / NANO_TO_MILLI);
- }
-
+ for (int numCpus : new int[] {2, 4, 8}) {
+ BootTimeStats stats =
+ runBootTimeTest(
+ "test_vm_boot_time_multicore",
+ (builder) -> builder.setNumCpus(numCpus));
String metricName = "boot_time_" + numCpus + "cpus";
- reportMetrics(bootTimeMetrics, metricName, "ms");
+ reportMetrics(stats.get(BootTimeMetric.TOTAL), metricName, "ms");
}
}
@Test
public void testMicrodroidDebugBootTime()
throws VirtualMachineException, InterruptedException, IOException {
- assume().withMessage("Skip on CF; too slow").that(isCuttlefish()).isFalse();
-
- final int trialCount = 10;
-
- List<Double> vmStartingTimeMetrics = new ArrayList<>();
- List<Double> bootTimeMetrics = new ArrayList<>();
- List<Double> bootloaderTimeMetrics = new ArrayList<>();
- List<Double> kernelBootTimeMetrics = new ArrayList<>();
- List<Double> userspaceBootTimeMetrics = new ArrayList<>();
-
- for (int i = 0; i < trialCount; i++) {
- // To grab boot events from log, set debug mode to FULL
- VirtualMachineConfig normalConfig =
- newVmConfigBuilder()
- .setPayloadBinaryName("MicrodroidIdleNativeLib.so")
- .setDebugLevel(DEBUG_LEVEL_FULL)
- .setVmOutputCaptured(true)
- .setMemoryBytes(256 * ONE_MEBI)
- .build();
- forceCreateNewVirtualMachine("test_vm_boot_time_debug", normalConfig);
-
- BootResult result = tryBootVm(TAG, "test_vm_boot_time_debug");
- assertThat(result.payloadStarted).isTrue();
-
- vmStartingTimeMetrics.add(result.getVMStartingElapsedNanoTime() / NANO_TO_MILLI);
- bootTimeMetrics.add(result.endToEndNanoTime / NANO_TO_MILLI);
- bootloaderTimeMetrics.add(result.getBootloaderElapsedNanoTime() / NANO_TO_MILLI);
- kernelBootTimeMetrics.add(result.getKernelElapsedNanoTime() / NANO_TO_MILLI);
- userspaceBootTimeMetrics.add(result.getUserspaceElapsedNanoTime() / NANO_TO_MILLI);
- }
-
- reportMetrics(vmStartingTimeMetrics, "vm_starting_time", "ms");
- reportMetrics(bootTimeMetrics, "boot_time", "ms");
- reportMetrics(bootloaderTimeMetrics, "bootloader_time", "ms");
- reportMetrics(kernelBootTimeMetrics, "kernel_boot_time", "ms");
- reportMetrics(userspaceBootTimeMetrics, "userspace_boot_time", "ms");
+ BootTimeStats stats =
+ runBootTimeTest(
+ "test_vm_boot_time_debug",
+ (builder) ->
+ builder.setDebugLevel(DEBUG_LEVEL_FULL).setVmOutputCaptured(true));
+ reportMetrics(stats.get(BootTimeMetric.TOTAL), "boot_time", "ms");
+ reportMetrics(stats.get(BootTimeMetric.VM_START), "vm_starting_time", "ms");
+ reportMetrics(stats.get(BootTimeMetric.BOOTLOADER), "bootloader_time", "ms");
+ reportMetrics(stats.get(BootTimeMetric.KERNEL), "kernel_boot_time", "ms");
+ reportMetrics(stats.get(BootTimeMetric.USERSPACE), "userspace_boot_time", "ms");
}
@Test
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index f1da43a..419b250 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -148,8 +148,9 @@
private OptionalLong mPayloadStartedNanoTime = OptionalLong.empty();
private StringBuilder mConsoleOutput = new StringBuilder();
private StringBuilder mLogOutput = new StringBuilder();
+ private boolean mProcessedBootTimeMetrics = false;
- private void processBootEvents(String log) {
+ private void processBootTimeMetrics(String log) {
if (!mVcpuStartedNanoTime.isPresent()) {
mVcpuStartedNanoTime = OptionalLong.of(System.nanoTime());
}
@@ -165,12 +166,13 @@
}
}
- private void logVmOutputAndMonitorBootEvents(
+ private void logVmOutputAndMonitorBootTimeMetrics(
String tag,
InputStream vmOutputStream,
String name,
StringBuilder result,
boolean monitorEvents) {
+ mProcessedBootTimeMetrics = monitorEvents;
new Thread(
() -> {
try {
@@ -180,7 +182,7 @@
String line;
while ((line = reader.readLine()) != null
&& !Thread.interrupted()) {
- if (monitorEvents) processBootEvents(line);
+ if (monitorEvents) processBootTimeMetrics(line);
Log.i(tag, name + ": " + line);
result.append(line + "\n");
}
@@ -191,15 +193,15 @@
.start();
}
- private void logVmOutputAndMonitorBootEvents(
+ private void logVmOutputAndMonitorBootTimeMetrics(
String tag, InputStream vmOutputStream, String name, StringBuilder result) {
- logVmOutputAndMonitorBootEvents(tag, vmOutputStream, name, result, true);
+ logVmOutputAndMonitorBootTimeMetrics(tag, vmOutputStream, name, result, true);
}
/** Copy output from the VM to logcat. This is helpful when things go wrong. */
protected void logVmOutput(
String tag, InputStream vmOutputStream, String name, StringBuilder result) {
- logVmOutputAndMonitorBootEvents(tag, vmOutputStream, name, result, false);
+ logVmOutputAndMonitorBootTimeMetrics(tag, vmOutputStream, name, result, false);
}
public void runToFinish(String logTag, VirtualMachine vm)
@@ -207,7 +209,7 @@
vm.setCallback(mExecutorService, this);
vm.run();
if (vm.getConfig().isVmOutputCaptured()) {
- logVmOutputAndMonitorBootEvents(
+ logVmOutputAndMonitorBootTimeMetrics(
logTag, vm.getConsoleOutput(), "Console", mConsoleOutput);
logVmOutput(logTag, vm.getLogOutput(), "Log", mLogOutput);
}
@@ -238,6 +240,10 @@
return mLogOutput.toString();
}
+ public boolean hasProcessedBootTimeMetrics() {
+ return mProcessedBootTimeMetrics;
+ }
+
protected void forceStop(VirtualMachine vm) {
try {
vm.stop();
@@ -266,12 +272,21 @@
}
}
+ public enum BootTimeMetric {
+ TOTAL,
+ VM_START,
+ BOOTLOADER,
+ KERNEL,
+ USERSPACE,
+ }
+
public static class BootResult {
public final boolean payloadStarted;
public final int deathReason;
public final long apiCallNanoTime;
public final long endToEndNanoTime;
+ public final boolean processedBootTimeMetrics;
public final OptionalLong vcpuStartedNanoTime;
public final OptionalLong kernelStartedNanoTime;
public final OptionalLong initStartedNanoTime;
@@ -285,6 +300,7 @@
int deathReason,
long apiCallNanoTime,
long endToEndNanoTime,
+ boolean processedBootTimeMetrics,
OptionalLong vcpuStartedNanoTime,
OptionalLong kernelStartedNanoTime,
OptionalLong initStartedNanoTime,
@@ -295,6 +311,7 @@
this.payloadStarted = payloadStarted;
this.deathReason = deathReason;
this.endToEndNanoTime = endToEndNanoTime;
+ this.processedBootTimeMetrics = processedBootTimeMetrics;
this.vcpuStartedNanoTime = vcpuStartedNanoTime;
this.kernelStartedNanoTime = kernelStartedNanoTime;
this.initStartedNanoTime = initStartedNanoTime;
@@ -336,6 +353,31 @@
public long getUserspaceElapsedNanoTime() {
return getPayloadStartedNanoTime() - getInitStartedNanoTime();
}
+
+ public boolean hasProcessedBootTimeMetrics() {
+ return processedBootTimeMetrics;
+ }
+
+ public OptionalLong getBootTimeMetricNanoTime(BootTimeMetric metric) {
+ if (metric == BootTimeMetric.TOTAL) {
+ return OptionalLong.of(endToEndNanoTime);
+ }
+
+ if (processedBootTimeMetrics) {
+ switch (metric) {
+ case VM_START:
+ return OptionalLong.of(getVMStartingElapsedNanoTime());
+ case BOOTLOADER:
+ return OptionalLong.of(getBootloaderElapsedNanoTime());
+ case KERNEL:
+ return OptionalLong.of(getKernelElapsedNanoTime());
+ case USERSPACE:
+ return OptionalLong.of(getUserspaceElapsedNanoTime());
+ }
+ }
+
+ return OptionalLong.empty();
+ }
}
public BootResult tryBootVm(String logTag, String vmName)
@@ -366,6 +408,7 @@
deathReason.getNow(VmEventListener.STOP_REASON_INFRASTRUCTURE_ERROR),
apiCallNanoTime,
endTime.getNow(apiCallNanoTime) - apiCallNanoTime,
+ listener.hasProcessedBootTimeMetrics(),
listener.getVcpuStartedNanoTime(),
listener.getKernelStartedNanoTime(),
listener.getInitStartedNanoTime(),