Merge "Set rollback_index of microdroid_kernel to 1" into main
diff --git a/Android.bp b/Android.bp
index 4fa696f..22581b0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -36,6 +36,7 @@
         "release_avf_enable_dice_changes",
         "release_avf_enable_llpvm_changes",
         "release_avf_enable_multi_tenant_microdroid_vm",
+        "release_avf_enable_remote_attestation",
         "release_avf_enable_vendor_modules",
     ],
     properties: [
@@ -55,6 +56,9 @@
         release_avf_enable_multi_tenant_microdroid_vm: {
             cfgs: ["payload_not_root"],
         },
+        release_avf_enable_remote_attestation: {
+            cfgs: ["remote_attestation"],
+        },
         release_avf_enable_vendor_modules: {
             cfgs: ["vendor_modules"],
         },
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 244b192..61de423 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -732,6 +732,7 @@
     strict_boot: bool,
     debug_policy: Option<&mut [u8]>,
     debuggable: bool,
+    kaslr_seed: u64,
 ) -> libfdt::Result<()> {
     if let Some(debug_policy) = debug_policy {
         let backup = Vec::from(fdt.as_slice());
@@ -753,6 +754,7 @@
     if let Some(mut chosen) = fdt.chosen_mut()? {
         empty_or_delete_prop(&mut chosen, cstr!("avf,strict-boot"), strict_boot)?;
         empty_or_delete_prop(&mut chosen, cstr!("avf,new-instance"), new_instance)?;
+        chosen.setprop_inplace(cstr!("kaslr-seed"), &kaslr_seed.to_be_bytes())?;
     };
     if !debuggable {
         if let Some(bootargs) = read_bootargs_from(fdt)? {
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index c6aa309..d39d51c 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -52,6 +52,7 @@
 use vmbase::heap;
 use vmbase::memory::flush;
 use vmbase::memory::MEMORY;
+use vmbase::rand;
 use vmbase::virtio::pci;
 
 const NEXT_BCC_SIZE: usize = GUEST_PAGE_SIZE;
@@ -154,12 +155,24 @@
     })?;
     flush(next_bcc);
 
+    let kaslr_seed = u64::from_ne_bytes(rand::random_array().map_err(|e| {
+        error!("Failed to generated guest KASLR seed: {e}");
+        RebootReason::InternalError
+    })?);
     let strict_boot = true;
-    modify_for_next_stage(fdt, next_bcc, new_instance, strict_boot, debug_policy, debuggable)
-        .map_err(|e| {
-            error!("Failed to configure device tree: {e}");
-            RebootReason::InternalError
-        })?;
+    modify_for_next_stage(
+        fdt,
+        next_bcc,
+        new_instance,
+        strict_boot,
+        debug_policy,
+        debuggable,
+        kaslr_seed,
+    )
+    .map_err(|e| {
+        error!("Failed to configure device tree: {e}");
+        RebootReason::InternalError
+    })?;
 
     info!("Starting payload...");
 
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
index 90ba575..80fdff7 100644
--- a/tests/benchmark/Android.bp
+++ b/tests/benchmark/Android.bp
@@ -28,6 +28,7 @@
     compile_multilib: "64",
     required: ["perf-setup"],
     host_required: ["MicrodroidTestPreparer"],
+    data: [":test_microdroid_vendor_image"],
 }
 
 cc_library_shared {
diff --git a/tests/benchmark/AndroidTest.xml b/tests/benchmark/AndroidTest.xml
index 8c8bfbe..11b17f4 100644
--- a/tests/benchmark/AndroidTest.xml
+++ b/tests/benchmark/AndroidTest.xml
@@ -30,6 +30,14 @@
         <option name="post-push" value="chmod 755 /data/local/tmp/perf-setup.sh;/data/local/tmp/perf-setup.sh" />
         <option name="cleanup" value="true" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/microdroid-bench" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/microdroid-bench" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="test_microdroid_vendor_image.img->/data/local/tmp/microdroid-bench/microdroid_vendor_image.img" />
+    </target_preparer>
     <target_preparer class="com.android.microdroid.test.preparer.DisableMicrodroidDebugPolicyPreparer" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.microdroid.benchmark" />
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 625f26a..1917654 100644
--- a/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
+++ b/tests/benchmark/src/java/com/android/microdroid/benchmark/MicrodroidBenchmarks.java
@@ -38,6 +38,7 @@
 import android.system.virtualmachine.VirtualMachineConfig;
 import android.system.virtualmachine.VirtualMachineException;
 import android.system.Os;
+import android.system.virtualmachine.VirtualMachineManager;
 import android.util.Log;
 
 import com.android.microdroid.test.common.MetricsProcessor;
@@ -260,6 +261,26 @@
     }
 
     @Test
+    public void testMicrodroidDebugBootTime_withVendorPartition() throws Exception {
+        assumeFeatureEnabled(VirtualMachineManager.FEATURE_VENDOR_MODULES);
+
+        File vendorDiskImage =
+                new File("/data/local/tmp/microdroid-bench/microdroid_vendor_image.img");
+        BootTimeStats stats =
+                runBootTimeTest(
+                        "test_vm_boot_time_debug_with_vendor_partition",
+                        (builder) ->
+                                builder.setDebugLevel(DEBUG_LEVEL_FULL)
+                                        .setVmOutputCaptured(true)
+                                        .setVendorDiskImage(vendorDiskImage));
+        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
     public void testMicrodroidImageSize() throws IOException {
         Bundle bundle = new Bundle();
         for (File file : new File(APEX_ETC_FS).listFiles()) {
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 9f03ab7..e2795ec 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
@@ -20,6 +20,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.TruthJUnit.assume;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.app.Instrumentation;
 import android.app.UiAutomation;
 import android.content.Context;
@@ -545,4 +547,12 @@
     protected interface RunTestsAgainstTestService {
         void runTests(ITestService testService, TestResults testResults) throws Exception;
     }
+
+    protected void assumeFeatureEnabled(String featureName) throws Exception {
+        assumeTrue(featureName + " not enabled", isFeatureEnabled(featureName));
+    }
+
+    protected boolean isFeatureEnabled(String featureName) throws Exception {
+        return getVirtualMachineManager().isFeatureEnabled(featureName);
+    }
 }
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 9fe5614..4b9f803 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -2254,12 +2254,4 @@
                 .that(KERNEL_VERSION)
                 .isNotEqualTo("5.4");
     }
-
-    private void assumeFeatureEnabled(String featureName) throws Exception {
-        assumeTrue(featureName + " not enabled", isFeatureEnabled(featureName));
-    }
-
-    private boolean isFeatureEnabled(String featureName) throws Exception {
-        return getVirtualMachineManager().isFeatureEnabled(featureName);
-    }
 }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 6f5a487..645a82b 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -160,10 +160,20 @@
     fn requestCertificate(&self, csr: &[u8]) -> binder::Result<Vec<u8>> {
         check_manage_access()?;
         info!("Received csr. Getting certificate...");
-        request_certificate(csr)
-            .context("Failed to get certificate")
+        if cfg!(remote_attestation) {
+            request_certificate(csr)
+                .context("Failed to get certificate")
+                .with_log()
+                .or_service_specific_exception(-1)
+        } else {
+            Err(Status::new_exception_str(
+                ExceptionCode::UNSUPPORTED_OPERATION,
+                Some(
+                    "requestCertificate is not supported with the remote_attestation feature disabled",
+                ),
+            ))
             .with_log()
-            .or_service_specific_exception(-1)
+        }
     }
 
     fn getAssignableDevices(&self) -> binder::Result<Vec<AssignableDevice>> {
diff --git a/virtualizationservice/src/remote_provisioning.rs b/virtualizationservice/src/remote_provisioning.rs
index 599a614..06f8ad4 100644
--- a/virtualizationservice/src/remote_provisioning.rs
+++ b/virtualizationservice/src/remote_provisioning.rs
@@ -14,17 +14,20 @@
 
 //! IRemotelyProvisionedComponent HAL implementation.
 
+use crate::rkpvm;
 use android_hardware_security_rkp::aidl::android::hardware::security::keymint::{
     DeviceInfo::DeviceInfo,
     IRemotelyProvisionedComponent::{
-        BnRemotelyProvisionedComponent, IRemotelyProvisionedComponent, STATUS_REMOVED,
+        BnRemotelyProvisionedComponent, IRemotelyProvisionedComponent, STATUS_FAILED,
+        STATUS_REMOVED,
     },
     MacedPublicKey::MacedPublicKey,
     ProtectedData::ProtectedData,
     RpcHardwareInfo::{RpcHardwareInfo, CURVE_NONE, MIN_SUPPORTED_NUM_KEYS_IN_CSR},
 };
+use anyhow::Context;
 use avflog::LogResult;
-use binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, Strong};
+use binder::{BinderFeatures, Interface, IntoBinderResult, Result as BinderResult, Status, Strong};
 
 /// Constructs a binder object that implements `IRemotelyProvisionedComponent`.
 pub(crate) fn new_binder() -> Strong<dyn IRemotelyProvisionedComponent> {
@@ -53,7 +56,7 @@
     fn generateEcdsaP256KeyPair(
         &self,
         testMode: bool,
-        _macedPublicKey: &mut MacedPublicKey,
+        macedPublicKey: &mut MacedPublicKey,
     ) -> BinderResult<Vec<u8>> {
         if testMode {
             return Err(Status::new_service_specific_error_str(
@@ -62,8 +65,12 @@
             ))
             .with_log();
         }
-        // TODO(b/274881098): Implement this.
-        Err(Status::new_exception(ExceptionCode::UNSUPPORTED_OPERATION, None)).with_log()
+        let key_pair = rkpvm::generate_ecdsa_p256_key_pair()
+            .context("Failed to generate ECDSA P-256 key pair")
+            .with_log()
+            .or_service_specific_exception(STATUS_FAILED)?;
+        macedPublicKey.macedKey = key_pair.maced_public_key;
+        Ok(key_pair.key_blob)
     }
 
     fn generateCertificateRequest(
@@ -84,10 +91,13 @@
 
     fn generateCertificateRequestV2(
         &self,
-        _keysToSign: &[MacedPublicKey],
-        _challenge: &[u8],
+        keysToSign: &[MacedPublicKey],
+        challenge: &[u8],
     ) -> BinderResult<Vec<u8>> {
-        // TODO(b/274881098): Implement this.
-        Err(Status::new_exception(ExceptionCode::UNSUPPORTED_OPERATION, None)).with_log()
+        // TODO(b/299259624): Validate the MAC of the keys to certify.
+        rkpvm::generate_certificate_request(keysToSign, challenge)
+            .context("Failed to generate certificate request")
+            .with_log()
+            .or_service_specific_exception(STATUS_FAILED)
     }
 }
diff --git a/virtualizationservice/src/rkpvm.rs b/virtualizationservice/src/rkpvm.rs
index dbadd60..80953b5 100644
--- a/virtualizationservice/src/rkpvm.rs
+++ b/virtualizationservice/src/rkpvm.rs
@@ -16,8 +16,9 @@
 //! The RKP VM will be recognized and attested by the RKP server periodically and
 //! serves as a trusted platform to attest a client VM.
 
+use android_hardware_security_rkp::aidl::android::hardware::security::keymint::MacedPublicKey::MacedPublicKey;
 use anyhow::{bail, Context, Result};
-use service_vm_comm::{Request, Response};
+use service_vm_comm::{EcdsaP256KeyPair, GenerateCertificateRequestParams, Request, Response};
 use service_vm_manager::ServiceVm;
 
 pub(crate) fn request_certificate(csr: &[u8]) -> Result<Vec<u8>> {
@@ -31,3 +32,29 @@
         _ => bail!("Incorrect response type"),
     }
 }
+
+pub(crate) fn generate_ecdsa_p256_key_pair() -> Result<EcdsaP256KeyPair> {
+    let mut vm = ServiceVm::start()?;
+    let request = Request::GenerateEcdsaP256KeyPair;
+    match vm.process_request(request).context("Failed to process request")? {
+        Response::GenerateEcdsaP256KeyPair(key_pair) => Ok(key_pair),
+        _ => bail!("Incorrect response type"),
+    }
+}
+
+pub(crate) fn generate_certificate_request(
+    keys_to_sign: &[MacedPublicKey],
+    challenge: &[u8],
+) -> Result<Vec<u8>> {
+    let params = GenerateCertificateRequestParams {
+        keys_to_sign: keys_to_sign.iter().map(|v| v.macedKey.to_vec()).collect(),
+        challenge: challenge.to_vec(),
+    };
+    let request = Request::GenerateCertificateRequest(params);
+
+    let mut vm = ServiceVm::start()?;
+    match vm.process_request(request).context("Failed to process request")? {
+        Response::GenerateCertificateRequest(csr) => Ok(csr),
+        _ => bail!("Incorrect response type"),
+    }
+}