Merge "[apkverify] Move HashAlgorithm to algorithms"
diff --git a/.prebuilt_info/prebuilt_info_pvmfw_pvmfw_img.asciipb b/.prebuilt_info/prebuilt_info_pvmfw_pvmfw_img.asciipb
index ba1e6b9..984625e 100644
--- a/.prebuilt_info/prebuilt_info_pvmfw_pvmfw_img.asciipb
+++ b/.prebuilt_info/prebuilt_info_pvmfw_pvmfw_img.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "9107967"
+ build_id: "9110780"
target: "u-boot_pvmfw"
source_file: "pvmfw.img"
}
diff --git a/apex/Android.bp b/apex/Android.bp
index fade6c5..52f4384 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -69,6 +69,7 @@
"microdroid.json",
"microdroid_bootloader",
"microdroid_bootloader.avbpubkey",
+ "microdroid_kernel",
],
file_contexts: ":com.android.virt-file_contexts",
canned_fs_config: "canned_fs_config",
diff --git a/apex/sign_virt_apex.py b/apex/sign_virt_apex.py
index 6863b0c..c8cb07d 100644
--- a/apex/sign_virt_apex.py
+++ b/apex/sign_virt_apex.py
@@ -378,9 +378,9 @@
# re-sign bootloader, boot.img, vendor_boot.img, and init_boot.img
Async(AddHashFooter, args, key, files['bootloader'], wait=[replace_f])
- boot_img_f = Async(AddHashFooter, args, key, files['boot.img'])
- vendor_boot_img_f = Async(AddHashFooter, args, key, files['vendor_boot.img'])
- init_boot_img_f = Async(AddHashFooter, args, key, files['init_boot.img'])
+ Async(AddHashFooter, args, key, files['boot.img'])
+ Async(AddHashFooter, args, key, files['vendor_boot.img'])
+ Async(AddHashFooter, args, key, files['init_boot.img'])
# re-sign super.img
# 1. unpack super.img
@@ -392,11 +392,10 @@
partitions = {"system_a": system_a_img, "vendor_a": vendor_a_img}
Async(MakeSuperImage, args, partitions, files['super.img'], wait=[system_a_f, vendor_a_f])
- # re-generate vbmeta from re-signed {boot, vendor_boot, init_boot, system_a, vendor_a}.img
+ # re-generate vbmeta from re-signed {system_a, vendor_a}.img
Async(MakeVbmetaImage, args, key, files['vbmeta.img'],
- images=[files['boot.img'], files['vendor_boot.img'],
- files['init_boot.img'], system_a_img, vendor_a_img],
- wait=[boot_img_f, vendor_boot_img_f, init_boot_img_f, system_a_f, vendor_a_f])
+ images=[system_a_img, vendor_a_img],
+ wait=[system_a_f, vendor_a_f])
# Re-sign bootconfigs and the uboot_env with the same key
bootconfig_sign_key = key
diff --git a/compos/common/compos_client.rs b/compos/common/compos_client.rs
index 49396d7..7327df7 100644
--- a/compos/common/compos_client.rs
+++ b/compos/common/compos_client.rs
@@ -23,7 +23,7 @@
};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
IVirtualizationService::IVirtualizationService,
- VirtualMachineAppConfig::{DebugLevel::DebugLevel, VirtualMachineAppConfig},
+ VirtualMachineAppConfig::{DebugLevel::DebugLevel, Payload::Payload, VirtualMachineAppConfig},
VirtualMachineConfig::VirtualMachineConfig,
};
use anyhow::{bail, Context, Result};
@@ -122,7 +122,7 @@
apk: Some(apk_fd),
idsig: Some(idsig_fd),
instanceImage: Some(instance_fd),
- configPath: config_path,
+ payload: Payload::ConfigPath(config_path),
debugLevel: debug_level,
extraIdsigs: extra_idsigs,
protectedVm: protected_vm,
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
index 4ecd942..63a3f43 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -222,7 +222,7 @@
/* package */ VirtualMachineAppConfig toParcel() throws FileNotFoundException {
VirtualMachineAppConfig parcel = new VirtualMachineAppConfig();
parcel.apk = ParcelFileDescriptor.open(new File(mApkPath), MODE_READ_ONLY);
- parcel.configPath = mPayloadConfigPath;
+ parcel.payload = VirtualMachineAppConfig.Payload.configPath(mPayloadConfigPath);
switch (mDebugLevel) {
case NONE:
parcel.debugLevel = VirtualMachineAppConfig.DebugLevel.NONE;
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 7b28ad2..10e5858 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -70,7 +70,7 @@
"apexd",
"atrace",
"debuggerd",
- "diced.microdroid",
+ "dice-service.microdroid",
"linker",
"linkerconfig",
"servicemanager.microdroid",
@@ -195,7 +195,6 @@
partition_name: "vendor",
use_avb: true,
deps: [
- "android.hardware.security.dice-service.microdroid",
"microdroid_fstab",
"microdroid_precompiled_sepolicy.plat_sepolicy_and_mapping.sha256",
"microdroid_vendor_manifest",
@@ -508,10 +507,7 @@
private_key: ":microdroid_sign_key",
partitions: [
"microdroid_vendor",
- "microdroid_vendor_boot",
"microdroid",
- "microdroid_boot",
- "microdroid_init_boot",
],
}
@@ -573,3 +569,37 @@
name: "microdroid_bootconfig_normal_src",
srcs: ["bootconfig.normal"],
}
+
+avb_add_hash_footer {
+ name: "microdroid_kernel_signed",
+ src: "empty_kernel",
+ filename: "microdroid_kernel",
+ partition_name: "bootloader",
+ private_key: ":microdroid_sign_key",
+ salt: bootloader_salt,
+ enabled: false,
+ arch: {
+ arm64: {
+ src: ":microdroid_kernel_prebuilts-5.15-arm64",
+ enabled: true,
+ },
+ x86_64: {
+ src: ":microdroid_kernel_prebuilts-5.15-x86_64",
+ enabled: true,
+ },
+ },
+}
+
+prebuilt_etc {
+ name: "microdroid_kernel",
+ src: "empty_kernel",
+ relative_install_path: "fs",
+ arch: {
+ arm64: {
+ src: ":microdroid_kernel_signed",
+ },
+ x86_64: {
+ src: ":microdroid_kernel_signed",
+ },
+ },
+}
diff --git a/microdroid/dice/Android.bp b/microdroid/dice/Android.bp
index 8026581..859533e 100644
--- a/microdroid/dice/Android.bp
+++ b/microdroid/dice/Android.bp
@@ -3,27 +3,24 @@
}
rust_binary {
- name: "android.hardware.security.dice-service.microdroid",
+ name: "dice-service.microdroid",
srcs: ["service.rs"],
- relative_install_path: "hw",
- vendor: true,
prefer_rlib: true,
rustlibs: [
"android.hardware.security.dice-V1-rust",
+ "android.security.dice-rust",
"libandroid_logger",
"libanyhow",
"libbinder_rs",
"libbyteorder",
+ "libdiced",
"libdiced_open_dice_cbor",
"libdiced_sample_inputs",
- "libdiced_vendor",
+ "libdiced_utils",
"liblibc",
"liblog_rust",
"libserde",
],
- init_rc: ["android.hardware.security.dice-service.microdroid.rc"],
- vintf_fragments: [
- "android.hardware.security.dice-service.microdroid.xml",
- ],
+ init_rc: ["dice-service.microdroid.rc"],
bootstrap: true,
}
diff --git a/microdroid/dice/android.hardware.security.dice-service.microdroid.rc b/microdroid/dice/android.hardware.security.dice-service.microdroid.rc
deleted file mode 100644
index 7d9d441..0000000
--- a/microdroid/dice/android.hardware.security.dice-service.microdroid.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service vendor.dice-microdroid /vendor/bin/hw/android.hardware.security.dice-service.microdroid
- user diced
- group diced
diff --git a/microdroid/dice/android.hardware.security.dice-service.microdroid.xml b/microdroid/dice/android.hardware.security.dice-service.microdroid.xml
deleted file mode 100644
index cf6c482..0000000
--- a/microdroid/dice/android.hardware.security.dice-service.microdroid.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<manifest version="1.0" type="device">
- <hal format="aidl">
- <name>android.hardware.security.dice</name>
- <fqname>IDiceDevice/default</fqname>
- </hal>
-</manifest>
diff --git a/microdroid/dice/dice-service.microdroid.rc b/microdroid/dice/dice-service.microdroid.rc
new file mode 100644
index 0000000..5bcb049
--- /dev/null
+++ b/microdroid/dice/dice-service.microdroid.rc
@@ -0,0 +1,3 @@
+service dice-microdroid /system/bin/dice-service.microdroid
+ user diced
+ group diced
diff --git a/microdroid/dice/service.rs b/microdroid/dice/service.rs
index 8199c7c..2c19481 100644
--- a/microdroid/dice/service.rs
+++ b/microdroid/dice/service.rs
@@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//! Main entry point for the microdroid IDiceDevice HAL implementation.
+//! Main entry point for the microdroid DICE service implementation.
-use anyhow::{bail, Error, Result};
-use byteorder::{NativeEndian, ReadBytesExt};
-use diced::{
- dice,
- hal_node::{DiceArtifacts, DiceDevice, ResidentHal, UpdatableDiceArtifacts},
+use android_hardware_security_dice::aidl::android::hardware::security::dice::{
+ Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
+ Signature::Signature,
};
+use anyhow::{bail, ensure, Context, Error, Result};
+use byteorder::{NativeEndian, ReadBytesExt};
+use dice::{ContextImpl, OpenDiceCborContext};
+use diced::{dice, DiceMaintenance, DiceNode, DiceNodeImpl};
+use diced_utils::make_bcc_handover;
use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
use serde::{Deserialize, Serialize};
use std::fs;
@@ -28,10 +31,11 @@
use std::path::{Path, PathBuf};
use std::ptr::null_mut;
use std::slice;
-use std::sync::Arc;
+use std::sync::{Arc, RwLock};
const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
-const DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default";
+const DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
+const DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
/// Artifacts that are mapped into the process address space from the driver.
struct MappedDriverArtifacts<'a> {
@@ -99,19 +103,6 @@
}
}
-impl DiceArtifacts for MappedDriverArtifacts<'_> {
- fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
- self.cdi_attest
- }
- fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
- self.cdi_seal
- }
- fn bcc(&self) -> Vec<u8> {
- // The BCC only contains public information so it's fine to copy.
- self.bcc.to_vec()
- }
-}
-
/// Artifacts that are kept in the process address space after the artifacts
/// from the driver have been consumed.
#[derive(Clone, Serialize, Deserialize)]
@@ -121,81 +112,169 @@
bcc: Vec<u8>,
}
-impl DiceArtifacts for RawArtifacts {
- fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
- &self.cdi_attest
- }
- fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
- &self.cdi_seal
- }
- fn bcc(&self) -> Vec<u8> {
- // The BCC only contains public information so it's fine to copy.
- self.bcc.clone()
- }
-}
-
#[derive(Clone, Serialize, Deserialize)]
-enum DriverArtifactManager {
+enum UpdatableArtifacts {
Invalid,
Driver(PathBuf),
Updated(RawArtifacts),
}
-impl DriverArtifactManager {
- fn new(driver_path: &Path) -> Self {
- if driver_path.exists() {
- log::info!("Using DICE values from driver");
- Self::Driver(driver_path.to_path_buf())
- } else if Path::new(AVF_STRICT_BOOT).exists() {
- log::error!("Strict boot requires DICE value from driver but none were found");
- Self::Invalid
- } else {
- log::warn!("Using sample DICE values");
- let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
- .expect("Failed to create sample dice artifacts.");
- Self::Updated(RawArtifacts {
- cdi_attest: cdi_attest[..].try_into().unwrap(),
- cdi_seal: cdi_seal[..].try_into().unwrap(),
- bcc,
- })
- }
- }
-}
-
-impl UpdatableDiceArtifacts for DriverArtifactManager {
- fn with_artifacts<F, T>(&self, f: F) -> Result<T>
- where
- F: FnOnce(&dyn DiceArtifacts) -> Result<T>,
- {
+impl UpdatableArtifacts {
+ fn get(
+ &self,
+ input_values: &BinderInputValues,
+ ) -> Result<(dice::CdiAttest, dice::CdiSeal, Vec<u8>)> {
+ let input_values: diced_utils::InputValues = input_values.into();
match self {
Self::Invalid => bail!("No DICE artifacts available."),
- Self::Driver(driver_path) => f(&MappedDriverArtifacts::new(driver_path.as_path())?),
- Self::Updated(raw_artifacts) => f(raw_artifacts),
+ Self::Driver(driver_path) => {
+ let artifacts = MappedDriverArtifacts::new(driver_path.as_path())?;
+ dice::OpenDiceCborContext::new().bcc_main_flow(
+ artifacts.cdi_attest,
+ artifacts.cdi_seal,
+ artifacts.bcc,
+ &input_values,
+ )
+ }
+ Self::Updated(artifacts) => dice::OpenDiceCborContext::new().bcc_main_flow(
+ &artifacts.cdi_attest,
+ &artifacts.cdi_seal,
+ &artifacts.bcc,
+ &input_values,
+ ),
}
+ .context("Deriving artifacts")
}
- fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> {
+
+ fn update(self, inputs: &BinderInputValues) -> Result<Self> {
if let Self::Invalid = self {
bail!("Cannot update invalid DICE artifacts.");
}
- if let Self::Driver(driver_path) = self {
- // Writing to the device wipes the artifcates. The string is ignored
+ let (cdi_attest, cdi_seal, bcc) =
+ self.get(inputs).context("Failed to get update artifacts.")?;
+ if let Self::Driver(ref driver_path) = self {
+ // Writing to the device wipes the artifacts. The string is ignored
// by the driver but included for documentation.
fs::write(driver_path, "wipe")
.map_err(|error| Error::new(error).context("Wiping driver"))?;
}
Ok(Self::Updated(RawArtifacts {
- cdi_attest: *new_artifacts.cdi_attest(),
- cdi_seal: *new_artifacts.cdi_seal(),
- bcc: new_artifacts.bcc(),
+ cdi_attest: cdi_attest[..].try_into().unwrap(),
+ cdi_seal: cdi_seal[..].try_into().unwrap(),
+ bcc,
}))
}
}
+struct ArtifactManager {
+ artifacts: RwLock<UpdatableArtifacts>,
+}
+
+impl ArtifactManager {
+ fn new(driver_path: &Path) -> Self {
+ Self {
+ artifacts: RwLock::new(if driver_path.exists() {
+ log::info!("Using DICE values from driver");
+ UpdatableArtifacts::Driver(driver_path.to_path_buf())
+ } else if Path::new(AVF_STRICT_BOOT).exists() {
+ log::error!("Strict boot requires DICE value from driver but none were found");
+ UpdatableArtifacts::Invalid
+ } else {
+ log::warn!("Using sample DICE values");
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
+ .expect("Failed to create sample dice artifacts.");
+ UpdatableArtifacts::Updated(RawArtifacts {
+ cdi_attest: cdi_attest[..].try_into().unwrap(),
+ cdi_seal: cdi_seal[..].try_into().unwrap(),
+ bcc,
+ })
+ }),
+ }
+ }
+}
+
+impl DiceNodeImpl for ArtifactManager {
+ fn sign(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ message: &[u8],
+ ) -> Result<Signature> {
+ ensure!(input_values.is_empty(), "Extra input values not supported");
+ let artifacts = self.artifacts.read().unwrap().clone();
+ let (cdi_attest, _, _) =
+ artifacts.get(&client).context("Failed to get signing artifacts.")?;
+ let mut dice = OpenDiceCborContext::new();
+ let seed = dice
+ .derive_cdi_private_key_seed(
+ cdi_attest[..].try_into().context("Failed to convert cdi_attest.")?,
+ )
+ .context("Failed to derive seed from cdi_attest.")?;
+ let (_public_key, private_key) = dice
+ .keypair_from_seed(seed[..].try_into().context("Failed to convert seed.")?)
+ .context("Failed to derive keypair from seed.")?;
+ let signature = dice
+ .sign(message, private_key[..].try_into().context("Failed to convert private_key.")?)
+ .context("Failed to sign.")?;
+ Ok(Signature { data: signature })
+ }
+
+ fn get_attestation_chain(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<Bcc> {
+ ensure!(input_values.is_empty(), "Extra input values not supported");
+ let artifacts = self.artifacts.read().unwrap().clone();
+ let (_, _, bcc) =
+ artifacts.get(&client).context("Failed to get attestation chain artifacts.")?;
+ Ok(Bcc { data: bcc })
+ }
+
+ fn derive(
+ &self,
+ client: BinderInputValues,
+ input_values: &[BinderInputValues],
+ ) -> Result<BccHandover> {
+ ensure!(input_values.is_empty(), "Extra input values not supported");
+ let artifacts = self.artifacts.read().unwrap().clone();
+ let (cdi_attest, cdi_seal, bcc) =
+ artifacts.get(&client).context("Failed to get attestation chain artifacts.")?;
+ make_bcc_handover(
+ &cdi_attest
+ .to_vec()
+ .as_slice()
+ .try_into()
+ .context("Trying to convert cdi_attest to sized array.")?,
+ &cdi_seal
+ .to_vec()
+ .as_slice()
+ .try_into()
+ .context("Trying to convert cdi_seal to sized array.")?,
+ &bcc,
+ )
+ .context("Trying to construct BccHandover.")
+ }
+
+ fn demote(
+ &self,
+ _client: BinderInputValues,
+ _input_values: &[BinderInputValues],
+ ) -> Result<()> {
+ bail!("Demote not supported.");
+ }
+
+ fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
+ ensure!(input_values.len() == 1, "Can only demote_self one level.");
+ let mut artifacts = self.artifacts.write().unwrap();
+ *artifacts = (*artifacts).clone().update(&input_values[0])?;
+ Ok(())
+ }
+}
+
fn main() {
android_logger::init_once(
- android_logger::Config::default()
- .with_tag("android.hardware.security.dice")
- .with_min_level(log::Level::Debug),
+ android_logger::Config::default().with_tag("dice").with_min_level(log::Level::Debug),
);
// Redirect panic messages to logcat.
panic::set_hook(Box::new(|panic_info| {
@@ -203,22 +282,21 @@
}));
// Saying hi.
- log::info!("android.hardware.security.dice is starting.");
+ log::info!("DICE service is starting.");
- let hal_impl = Arc::new(
- unsafe {
- // Safety: ResidentHal cannot be used in multi threaded processes.
- // This service does not start a thread pool. The main thread is the only thread
- // joining the thread pool, thereby keeping the process single threaded.
- ResidentHal::new(DriverArtifactManager::new(Path::new("/dev/open-dice0")))
- }
- .expect("Failed to create ResidentHal implementation."),
- );
+ let node_impl = Arc::new(ArtifactManager::new(Path::new("/dev/open-dice0")));
- let hal = DiceDevice::new_as_binder(hal_impl).expect("Failed to construct hal service.");
+ let node = DiceNode::new_as_binder(node_impl.clone())
+ .expect("Failed to create IDiceNode service instance.");
- binder::add_service(DICE_HAL_SERVICE_NAME, hal.as_binder())
- .expect("Failed to register IDiceDevice Service");
+ let maintenance = DiceMaintenance::new_as_binder(node_impl)
+ .expect("Failed to create IDiceMaintenance service instance.");
+
+ binder::add_service(DICE_NODE_SERVICE_NAME, node.as_binder())
+ .expect("Failed to register IDiceNode Service");
+
+ binder::add_service(DICE_MAINTENANCE_SERVICE_NAME, maintenance.as_binder())
+ .expect("Failed to register IDiceMaintenance Service");
log::info!("Joining thread pool now.");
binder::ProcessState::join_thread_pool();
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 4e36726..47002c9 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -67,8 +67,7 @@
start servicemanager
- start vendor.dice-microdroid
- start diced
+ start dice-microdroid
on init
mkdir /mnt/apk 0755 system system
diff --git a/microdroid/microdroid.json b/microdroid/microdroid.json
index f02dcbf..00cedc8 100644
--- a/microdroid/microdroid.json
+++ b/microdroid/microdroid.json
@@ -1,21 +1,9 @@
{
- "bootloader": "/apex/com.android.virt/etc/fs/microdroid_bootloader",
+ "kernel": "/apex/com.android.virt/etc/fs/microdroid_kernel",
"disks": [
{
"partitions": [
{
- "label": "boot_a",
- "path": "/apex/com.android.virt/etc/fs/microdroid_boot.img"
- },
- {
- "label": "init_boot_a",
- "path": "/apex/com.android.virt/etc/fs/microdroid_init_boot.img"
- },
- {
- "label": "vendor_boot_a",
- "path": "/apex/com.android.virt/etc/fs/microdroid_vendor_boot.img"
- },
- {
"label": "vbmeta_a",
"path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta.img"
},
@@ -25,16 +13,6 @@
}
],
"writable": false
- },
- {
- "partitions": [
- {
- "label": "uboot_env",
- "path": "/apex/com.android.virt/etc/fs/uboot_env.img",
- "writable": false
- }
- ],
- "writable": true
}
],
"memory_mib": 256,
diff --git a/microdroid/payload/metadata.cc b/microdroid/payload/metadata.cc
index 07083e9..fd07bdd 100644
--- a/microdroid/payload/metadata.cc
+++ b/microdroid/payload/metadata.cc
@@ -40,7 +40,7 @@
}
size = be32toh(*reinterpret_cast<uint32_t*>(content.data()));
if (content.size() < length_prefix_bytes + size) {
- return Error() << "Invalid metadata: size(" << size << ") mimatches to the content size("
+ return Error() << "Invalid metadata: size(" << size << ") doesn't match content size("
<< content.size() - length_prefix_bytes << ")";
}
content = content.substr(length_prefix_bytes, size);
diff --git a/microdroid/payload/metadata.proto b/microdroid/payload/metadata.proto
index 2e92f55..229d03f 100644
--- a/microdroid/payload/metadata.proto
+++ b/microdroid/payload/metadata.proto
@@ -26,7 +26,11 @@
ApkPayload apk = 3;
- string payload_config_path = 4;
+ oneof payload {
+ // Path to JSON config file inside the APK.
+ string config_path = 4;
+ PayloadConfig config = 5;
+ }
}
message ApexPayload {
@@ -58,3 +62,18 @@
string idsig_partition_name = 3;
}
+
+message PayloadConfig {
+ // Required.
+ // Path to the payload binary file inside the APK.
+ string payload_binary_path = 1;
+
+ // Required.
+ // Whether tombstones from crashes inside the VM should be exported to the host.
+ bool export_tombstones = 2;
+
+ // Optional.
+ // Arguments to be passed to the payload.
+ // TODO(b/249064104): Remove this
+ repeated string args = 3;
+}
diff --git a/microdroid/payload/metadata/src/lib.rs b/microdroid/payload/metadata/src/lib.rs
index eb9d90d..bfbec60 100644
--- a/microdroid/payload/metadata/src/lib.rs
+++ b/microdroid/payload/metadata/src/lib.rs
@@ -23,7 +23,9 @@
use std::io::Read;
use std::io::Write;
-pub use microdroid_metadata::metadata::{ApexPayload, ApkPayload, Metadata};
+pub use microdroid_metadata::metadata::{
+ ApexPayload, ApkPayload, Metadata, Metadata_oneof_payload as PayloadMetadata, PayloadConfig,
+};
/// Reads a metadata from a reader
pub fn read_metadata<T: Read>(mut r: T) -> Result<Metadata> {
diff --git a/microdroid/payload/mk_payload.cc b/microdroid/payload/mk_payload.cc
index 4dbcabf..d31333f 100644
--- a/microdroid/payload/mk_payload.cc
+++ b/microdroid/payload/mk_payload.cc
@@ -181,7 +181,7 @@
}
if (config.payload_config_path.has_value()) {
- *metadata.mutable_payload_config_path() = config.payload_config_path.value();
+ *metadata.mutable_config_path() = config.payload_config_path.value();
}
std::ofstream out(filename);
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 30521f6..90cabb6 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -34,7 +34,7 @@
use glob::glob;
use itertools::sorted;
use log::{error, info};
-use microdroid_metadata::{write_metadata, Metadata};
+use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
use openssl::sha::Sha512;
use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
@@ -301,9 +301,14 @@
verified_data
};
+ let payload_config_path = match metadata.payload {
+ Some(PayloadMetadata::config_path(p)) => p,
+ _ => bail!("Unsupported payload config"),
+ };
+
// To minimize the exposure to untrusted data, derive dice profile as soon as possible.
info!("DICE derivation for payload");
- dice_derivation(&verified_data, &metadata.payload_config_path)?;
+ dice_derivation(&verified_data, &payload_config_path)?;
// Before reading a file from the APK, start zipfuse
let noexec = false;
@@ -316,11 +321,11 @@
.context("Failed to run zipfuse")?;
ensure!(
- !metadata.payload_config_path.is_empty(),
+ !payload_config_path.is_empty(),
MicrodroidError::InvalidConfig("No payload_config_path in metadata".to_string())
);
- let config = load_config(Path::new(&metadata.payload_config_path))?;
+ let config = load_config(Path::new(&payload_config_path))?;
let task = config
.task
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 5bcafd5..57a3df0 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -42,3 +42,17 @@
},
},
}
+
+bootimg {
+ name: "pvmfw_img",
+ stem: "pvmfw.img",
+ kernel_prebuilt: ":pvmfw_bin",
+ header_version: "3",
+ partition_name: "pvmfw",
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+}
diff --git a/pvmfw/pvmfw.img b/pvmfw/pvmfw.img
index 7f32a9a..bacf213 100644
--- a/pvmfw/pvmfw.img
+++ b/pvmfw/pvmfw.img
Binary files differ
diff --git a/tests/benchmark/AndroidTest.xml b/tests/benchmark/AndroidTest.xml
index e908077..4949d22 100644
--- a/tests/benchmark/AndroidTest.xml
+++ b/tests/benchmark/AndroidTest.xml
@@ -21,6 +21,10 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="MicrodroidBenchmarkApp.apk" />
</target_preparer>
+ <!-- Need root to access /proc/$pid/smaps when measuring memory usage. -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="true" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option
name="run-command"
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 5dcd77b..a1dee6d 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
@@ -282,7 +282,9 @@
}
private long getKernelStartedNanoTime() {
- return kernelStartedNanoTime.getAsLong();
+ // pvmfw emits log at the end which is used to estimate the kernelStart time.
+ // In case of no pvmfw run(non-protected mode), use vCPU started time instead.
+ return kernelStartedNanoTime.orElse(vcpuStartedNanoTime.getAsLong());
}
private long getInitStartedNanoTime() {
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
index c9cfd72..7a71254 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
@@ -59,6 +59,7 @@
import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
@@ -359,7 +360,7 @@
JSONObject config = new JSONObject(FileUtil.readStringFromFile(microdroidConfigFile));
// Replace paths so that the config uses re-signed images from TEST_ROOT
- config.put("bootloader", config.getString("bootloader").replace(VIRT_APEX, TEST_ROOT));
+ config.put("kernel", config.getString("kernel").replace(VIRT_APEX, TEST_ROOT));
JSONArray disks = config.getJSONArray("disks");
for (int diskIndex = 0; diskIndex < disks.length(); diskIndex++) {
JSONObject disk = disks.getJSONObject(diskIndex);
@@ -371,14 +372,16 @@
}
// Add partitions to the second disk
- final String vbmetaPath = TEST_ROOT + "etc/fs/microdroid_vbmeta_bootconfig.img";
- final String bootconfigPath = TEST_ROOT + "etc/fs/microdroid_bootconfig.full_debuggable";
- disks.getJSONObject(1)
- .getJSONArray("partitions")
- .put(newPartition("vbmeta", vbmetaPath))
- .put(newPartition("bootconfig", bootconfigPath))
- .put(newPartition("vm-instance", instanceImgPath));
-
+ final String initrdPath = TEST_ROOT + "etc/microdroid_initrd_full_debuggable.img";
+ config.put("initrd", initrdPath);
+ // Add instance image as a partition in disks[1]
+ disks.put(
+ new JSONObject()
+ .put("writable", true)
+ .put(
+ "partitions",
+ new JSONArray()
+ .put(newPartition("vm-instance", instanceImgPath))));
// Add payload image disk with partitions:
// - payload-metadata
// - apexes: com.android.os.statsd, com.android.adbd, [sharedlib apex](optional)
@@ -438,7 +441,10 @@
assertThat(getDevice().pullFileContents(consolePath), containsString("pvmfw boot failed"));
}
+ // TODO(b/245277660): Resigning the system/vendor image changes the vbmeta hash.
+ // So, unless vbmeta related bootconfigs are updated the following test will fail
@Test
+ @Ignore("b/245277660")
@CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-6"})
public void testBootSucceedsWhenNonProtectedVmStartsWithImagesSignedWithDifferentKey()
throws Exception {
@@ -457,7 +463,7 @@
@Test
@CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-6"})
- public void testBootFailsWhenBootloaderAndVbMetaAreSignedWithDifferentKeys() throws Exception {
+ public void testBootFailsWhenVbMetaDigestDoesNotMatchBootconfig() throws Exception {
// Sign everything with key1 except vbmeta
File key = findTestFile("test.com.android.virt.pem");
File key2 = findTestFile("test2.com.android.virt.pem");
@@ -469,34 +475,11 @@
String cid =
runMicrodroidWithResignedImages(
key, keyOverrides, isProtected, daemonize, consolePath);
- // Wail for a while so that bootloader prints errors to console
+ // Wait so that init can print errors to console (time in cuttlefish >> in real device)
assertThatEventually(
- 10000,
+ 100000,
() -> getDevice().pullFileContents(consolePath),
- containsString("Public key was rejected"));
- shutdownMicrodroid(getDevice(), cid);
- }
-
- @Test
- @CddTest(requirements = {"9.17/C-2-2", "9.17/C-2-6"})
- public void testBootSucceedsWhenBootloaderAndVbmetaHaveSameSigningKeys() throws Exception {
- // Sign everything with key1 except bootloader and vbmeta
- File key = findTestFile("test.com.android.virt.pem");
- File key2 = findTestFile("test2.com.android.virt.pem");
- Map<String, File> keyOverrides =
- Map.of(
- "microdroid_bootloader", key2,
- "microdroid_vbmeta.img", key2,
- "microdroid_vbmeta_bootconfig.img", key2);
- boolean isProtected = false; // Not interested in pvwfw
- boolean daemonize = true; // Bootloader should succeed.
- // To be able to stop it, it should be a daemon.
- String consolePath = TEST_ROOT + "console";
- String cid =
- runMicrodroidWithResignedImages(
- key, keyOverrides, isProtected, daemonize, consolePath);
- // Adb connection to the microdroid means that boot succeeded.
- adbConnectToMicrodroid(getDevice(), cid);
+ containsString("init: [libfs_avb]Failed to verify vbmeta digest"));
shutdownMicrodroid(getDevice(), cid);
}
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 c2060cb..4b40293 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -451,36 +451,6 @@
"9.17/C-1-1",
"9.17/C-2-7"
})
- public void bootFailsWhenUBootAvbDataIsCompromised()
- throws VirtualMachineException, InterruptedException, IOException {
- if (mProtectedVm) {
- assertThatBootFailsAfterCompromisingPartition(U_BOOT_AVB_PARTITION_UUID);
- } else {
- // non-protected VM shouldn't have u-boot avb data
- assertThatPartitionIsMissing(U_BOOT_AVB_PARTITION_UUID);
- }
- }
-
- @Test
- @CddTest(requirements = {
- "9.17/C-1-1",
- "9.17/C-2-7"
- })
- public void bootFailsWhenUBootEnvDataIsCompromised()
- throws VirtualMachineException, InterruptedException, IOException {
- if (mProtectedVm) {
- assertThatBootFailsAfterCompromisingPartition(U_BOOT_ENV_PARTITION_UUID);
- } else {
- // non-protected VM shouldn't have u-boot env data
- assertThatPartitionIsMissing(U_BOOT_ENV_PARTITION_UUID);
- }
- }
-
- @Test
- @CddTest(requirements = {
- "9.17/C-1-1",
- "9.17/C-2-7"
- })
public void bootFailsWhenPvmFwDataIsCompromised()
throws VirtualMachineException, InterruptedException, IOException {
if (mProtectedVm) {
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index cf5398d..9b0a658 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -15,6 +15,8 @@
*/
package android.system.virtualizationservice;
+import android.system.virtualizationservice.VirtualMachinePayloadConfig;
+
/** Configuration for running an App in a VM */
parcelable VirtualMachineAppConfig {
/** Name of VM */
@@ -32,8 +34,20 @@
/** instance.img that has per-instance data */
ParcelFileDescriptor instanceImage;
- /** Path to a configuration in an APK. This is the actual configuration for a VM. */
- @utf8InCpp String configPath;
+ union Payload {
+ /**
+ * Path to a JSON file in an APK containing the configuration.
+ */
+ @utf8InCpp String configPath;
+
+ /**
+ * Configuration provided explicitly.
+ */
+ VirtualMachinePayloadConfig payloadConfig;
+ }
+
+ /** Detailed configuration for the VM, specifying how the payload will be run. */
+ Payload payload;
enum DebugLevel {
/** Not debuggable at all */
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
new file mode 100644
index 0000000..0c83349
--- /dev/null
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package android.system.virtualizationservice;
+
+parcelable VirtualMachinePayloadConfig {
+ /**
+ * Path to the payload executable code in an APK. The code is in the form of a .so with a
+ * defined entry point; inside the VM this file is loaded and the entry function invoked.
+ */
+ @utf8InCpp String payloadPath;
+
+ /**
+ * Whether to export tombstones (VM crash details) from the VM to the host.
+ */
+ boolean exportTombstones;
+
+ /**
+ * Command-line style arguments to be passed to the payload when it is executed.
+ * TODO(b/249064104): Remove this
+ */
+ @utf8InCpp String[] args;
+}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 3b75df9..22418b9 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -29,9 +29,10 @@
IVirtualizationService::IVirtualizationService,
Partition::Partition,
PartitionType::PartitionType,
- VirtualMachineAppConfig::VirtualMachineAppConfig,
+ VirtualMachineAppConfig::{VirtualMachineAppConfig, Payload::Payload},
VirtualMachineConfig::VirtualMachineConfig,
VirtualMachineDebugInfo::VirtualMachineDebugInfo,
+ VirtualMachinePayloadConfig::VirtualMachinePayloadConfig,
VirtualMachineRawConfig::VirtualMachineRawConfig,
VirtualMachineState::VirtualMachineState,
};
@@ -49,7 +50,7 @@
use disk::QcowFile;
use apkverify::{HashAlgorithm, V4Signature};
use log::{debug, error, info, warn};
-use microdroid_payload_config::VmPayloadConfig;
+use microdroid_payload_config::{VmPayloadConfig, OsConfig, Task, TaskType};
use rustutils::system_properties;
use semver::VersionReq;
use std::convert::TryInto;
@@ -85,6 +86,8 @@
const CHUNK_RECV_MAX_LEN: usize = 1024;
+const MICRODROID_OS_NAME: &str = "microdroid";
+
/// Implementation of `IVirtualizationService`, the entry point of the AIDL service.
#[derive(Debug, Default)]
pub struct VirtualizationService {
@@ -376,15 +379,10 @@
let config = match config {
VirtualMachineConfig::AppConfig(config) => BorrowedOrOwned::Owned(
load_app_config(config, &temporary_directory).map_err(|e| {
- error!("Failed to load app config from {}: {:?}", &config.configPath, e);
*is_protected = config.protectedVm;
- Status::new_service_specific_error_str(
- -1,
- Some(format!(
- "Failed to load app config from {}: {:?}",
- &config.configPath, e
- )),
- )
+ let message = format!("Failed to load app config: {:?}", e);
+ error!("{}", message);
+ Status::new_service_specific_error_str(-1, Some(message))
})?,
),
VirtualMachineConfig::RawConfig(config) => BorrowedOrOwned::Borrowed(config),
@@ -604,16 +602,18 @@
let apk_file = clone_file(config.apk.as_ref().unwrap())?;
let idsig_file = clone_file(config.idsig.as_ref().unwrap())?;
let instance_file = clone_file(config.instanceImage.as_ref().unwrap())?;
- let config_path = &config.configPath;
- let mut apk_zip = ZipArchive::new(&apk_file)?;
- let config_file = apk_zip.by_name(config_path)?;
- let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
+ let vm_payload_config = match &config.payload {
+ Payload::ConfigPath(config_path) => {
+ load_vm_payload_config_from_file(&apk_file, config_path.as_str())
+ .with_context(|| format!("Couldn't read config from {}", config_path))?
+ }
+ Payload::PayloadConfig(payload_config) => create_vm_payload_config(payload_config),
+ };
- let os_name = &vm_payload_config.os.name;
-
- // For now, the only supported "os" value is "microdroid"
- if os_name != "microdroid" {
+ // For now, the only supported OS is Microdroid
+ let os_name = vm_payload_config.os.name.as_str();
+ if os_name != MICRODROID_OS_NAME {
bail!("Unknown OS \"{}\"", os_name);
}
@@ -632,22 +632,46 @@
vm_config.numCpus = config.numCpus;
vm_config.taskProfiles = config.taskProfiles.clone();
- // Microdroid requires an additional payload disk image and the bootconfig partition.
- if os_name == "microdroid" {
- add_microdroid_images(
- config,
- temporary_directory,
- apk_file,
- idsig_file,
- instance_file,
- &vm_payload_config,
- &mut vm_config,
- )?;
- }
+ // Microdroid requires an additional init ramdisk & payload disk image
+ add_microdroid_images(
+ config,
+ temporary_directory,
+ apk_file,
+ idsig_file,
+ instance_file,
+ &vm_payload_config,
+ &mut vm_config,
+ )?;
Ok(vm_config)
}
+fn load_vm_payload_config_from_file(apk_file: &File, config_path: &str) -> Result<VmPayloadConfig> {
+ let mut apk_zip = ZipArchive::new(apk_file)?;
+ let config_file = apk_zip.by_name(config_path)?;
+ Ok(serde_json::from_reader(config_file)?)
+}
+
+fn create_vm_payload_config(payload_config: &VirtualMachinePayloadConfig) -> VmPayloadConfig {
+ // There isn't an actual config file. Construct a synthetic VmPayloadConfig from the explicit
+ // parameters we've been given. Microdroid will do something equivalent inside the VM using the
+ // payload config that we send it via the metadata file.
+ let task = Task {
+ type_: TaskType::MicrodroidLauncher,
+ command: payload_config.payloadPath.clone(),
+ args: payload_config.args.clone(),
+ };
+ VmPayloadConfig {
+ os: OsConfig { name: MICRODROID_OS_NAME.to_owned() },
+ task: Some(task),
+ apexes: vec![],
+ extra_apks: vec![],
+ prefer_staged: false,
+ export_tombstones: payload_config.exportTombstones,
+ enable_authfs: false,
+ }
+}
+
/// Generates a unique filename to use for a composite disk image.
fn make_composite_image_filenames(
temporary_directory: &Path,
diff --git a/virtualizationservice/src/atom.rs b/virtualizationservice/src/atom.rs
index 3b29d19..eabb4cc 100644
--- a/virtualizationservice/src/atom.rs
+++ b/virtualizationservice/src/atom.rs
@@ -16,23 +16,47 @@
use crate::aidl::clone_file;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
- DeathReason::DeathReason, IVirtualMachine::IVirtualMachine,
- VirtualMachineAppConfig::VirtualMachineAppConfig, VirtualMachineConfig::VirtualMachineConfig,
+ DeathReason::DeathReason,
+ IVirtualMachine::IVirtualMachine,
+ VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
+ VirtualMachineConfig::VirtualMachineConfig,
};
use android_system_virtualizationservice::binder::{Status, Strong};
use anyhow::{anyhow, Result};
-use binder::ThreadState;
+use binder::{ParcelFileDescriptor, ThreadState};
use log::{trace, warn};
use microdroid_payload_config::VmPayloadConfig;
use statslog_virtualization_rust::{vm_booted, vm_creation_requested, vm_exited};
use std::time::{Duration, SystemTime};
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"))?;
+fn get_apex_list(config: &VirtualMachineAppConfig) -> String {
+ match &config.payload {
+ Payload::PayloadConfig(_) => String::new(),
+ Payload::ConfigPath(config_path) => {
+ let vm_payload_config = get_vm_payload_config(&config.apk, config_path);
+ if let Ok(vm_payload_config) = vm_payload_config {
+ vm_payload_config
+ .apexes
+ .iter()
+ .map(|x| x.name.clone())
+ .collect::<Vec<String>>()
+ .join(":")
+ } else {
+ "INFO: Can't get VmPayloadConfig".to_owned()
+ }
+ }
+ }
+}
+
+fn get_vm_payload_config(
+ apk_fd: &Option<ParcelFileDescriptor>,
+ config_path: &str,
+) -> Result<VmPayloadConfig> {
+ let apk = apk_fd.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 config_file = apk_zip.by_name(config_path)?;
let vm_payload_config: VmPayloadConfig = serde_json::from_reader(config_file)?;
Ok(vm_payload_config)
}
@@ -63,38 +87,22 @@
}
}
- let vm_identifier;
- let config_type;
- let num_cpus;
- let memory_mib;
- let apexes;
- match config {
- VirtualMachineConfig::AppConfig(config) => {
- vm_identifier = &config.name;
- config_type = vm_creation_requested::ConfigType::VirtualMachineAppConfig;
- num_cpus = config.numCpus;
- 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) => {
- vm_identifier = &config.name;
- config_type = vm_creation_requested::ConfigType::VirtualMachineRawConfig;
- num_cpus = config.numCpus;
- memory_mib = config.memoryMib;
- apexes = String::new();
- }
- }
+ let (vm_identifier, config_type, num_cpus, memory_mib, apexes) = match config {
+ VirtualMachineConfig::AppConfig(config) => (
+ &config.name,
+ vm_creation_requested::ConfigType::VirtualMachineAppConfig,
+ config.numCpus,
+ config.memoryMib,
+ get_apex_list(config),
+ ),
+ VirtualMachineConfig::RawConfig(config) => (
+ &config.name,
+ vm_creation_requested::ConfigType::VirtualMachineRawConfig,
+ config.numCpus,
+ config.memoryMib,
+ String::new(),
+ ),
+ };
let vm_creation_requested = vm_creation_requested::VmCreationRequested {
uid: ThreadState::get_calling_uid() as i32,
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 675ca50..3efd7ac 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -15,14 +15,16 @@
//! Payload disk image
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
- DiskImage::DiskImage, Partition::Partition, VirtualMachineAppConfig::DebugLevel::DebugLevel,
- VirtualMachineAppConfig::VirtualMachineAppConfig,
+ DiskImage::DiskImage,
+ Partition::Partition,
+ VirtualMachineAppConfig::DebugLevel::DebugLevel,
+ VirtualMachineAppConfig::{Payload::Payload, VirtualMachineAppConfig},
VirtualMachineRawConfig::VirtualMachineRawConfig,
};
use anyhow::{anyhow, bail, Context, Result};
use binder::{wait_for_interface, ParcelFileDescriptor};
use log::{info, warn};
-use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
+use microdroid_metadata::{ApexPayload, ApkPayload, Metadata, PayloadConfig, PayloadMetadata};
use microdroid_payload_config::{ApexConfig, VmPayloadConfig};
use once_cell::sync::OnceCell;
use packagemanager_aidl::aidl::android::content::pm::IPackageManagerNative::IPackageManagerNative;
@@ -156,11 +158,22 @@
}
fn make_metadata_file(
- config_path: &str,
+ app_config: &VirtualMachineAppConfig,
apex_infos: &[&ApexInfo],
temporary_directory: &Path,
) -> Result<ParcelFileDescriptor> {
- let metadata_path = temporary_directory.join("metadata");
+ let payload_metadata = match &app_config.payload {
+ Payload::PayloadConfig(payload_config) => PayloadMetadata::config(PayloadConfig {
+ payload_binary_path: payload_config.payloadPath.clone(),
+ export_tombstones: payload_config.exportTombstones,
+ args: payload_config.args.clone().into(),
+ ..Default::default()
+ }),
+ Payload::ConfigPath(config_path) => {
+ PayloadMetadata::config_path(format!("/mnt/apk/{}", config_path))
+ }
+ };
+
let metadata = Metadata {
version: 1,
apexes: apex_infos
@@ -183,11 +196,12 @@
..Default::default()
})
.into(),
- payload_config_path: format!("/mnt/apk/{}", config_path),
+ payload: Some(payload_metadata),
..Default::default()
};
// Write metadata to file.
+ let metadata_path = temporary_directory.join("metadata");
let mut metadata_file = OpenOptions::new()
.create_new(true)
.read(true)
@@ -235,8 +249,7 @@
collect_apex_infos(&apex_list, &vm_payload_config.apexes, app_config.debugLevel);
info!("Microdroid payload APEXes: {:?}", apex_infos.iter().map(|ai| &ai.name));
- let metadata_file =
- make_metadata_file(&app_config.configPath, &apex_infos, temporary_directory)?;
+ let metadata_file = make_metadata_file(app_config, &apex_infos, temporary_directory)?;
// put metadata at the first partition
let mut partitions = vec![Partition {
label: "payload-metadata".to_owned(),
@@ -360,6 +373,21 @@
vm_payload_config: &VmPayloadConfig,
vm_config: &mut VirtualMachineRawConfig,
) -> Result<()> {
+ let debug_suffix = match config.debugLevel {
+ DebugLevel::NONE => "normal",
+ DebugLevel::APP_ONLY => "app_debuggable",
+ DebugLevel::FULL => "full_debuggable",
+ _ => return Err(anyhow!("unsupported debug level: {:?}", config.debugLevel)),
+ };
+ let initrd = format!("/apex/com.android.virt/etc/microdroid_initrd_{}.img", debug_suffix);
+ vm_config.initrd = Some(open_parcel_file(Path::new(&initrd), false)?);
+
+ let instance_img = Partition {
+ label: "vm-instance".to_owned(),
+ image: Some(ParcelFileDescriptor::new(instance_file)),
+ writable: true,
+ };
+ vm_config.disks.push(DiskImage { image: None, partitions: vec![instance_img], writable: true });
vm_config.disks.push(make_payload_disk(
config,
apk_file,
@@ -368,34 +396,6 @@
temporary_directory,
)?);
- vm_config.disks[1].partitions.push(Partition {
- label: "vbmeta".to_owned(),
- image: Some(open_parcel_file(
- Path::new("/apex/com.android.virt/etc/fs/microdroid_vbmeta_bootconfig.img"),
- false,
- )?),
- writable: false,
- });
- let bootconfig_image = "/apex/com.android.virt/etc/fs/microdroid_bootconfig.".to_owned()
- + match config.debugLevel {
- DebugLevel::NONE => "normal",
- DebugLevel::APP_ONLY => "app_debuggable",
- DebugLevel::FULL => "full_debuggable",
- _ => return Err(anyhow!("unsupported debug level: {:?}", config.debugLevel)),
- };
- vm_config.disks[1].partitions.push(Partition {
- label: "bootconfig".to_owned(),
- image: Some(open_parcel_file(Path::new(&bootconfig_image), false)?),
- writable: false,
- });
-
- // instance image is at the second partition in the second disk.
- vm_config.disks[1].partitions.push(Partition {
- label: "vm-instance".to_owned(),
- image: Some(ParcelFileDescriptor::new(instance_file)),
- writable: true,
- });
-
Ok(())
}
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 0845897..21cc74b 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -48,7 +48,7 @@
instance: PathBuf,
/// Path to VM config JSON within APK (e.g. assets/vm_config.json)
- config_path: String,
+ config_path: Option<String>,
/// Name of VM
#[clap(long)]
@@ -205,7 +205,7 @@
&apk,
&idsig,
&instance,
- &config_path,
+ config_path.as_deref().unwrap_or(""),
daemonize,
console.as_deref(),
log.as_deref(),
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 44e15f9..c524c59 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -16,9 +16,10 @@
use crate::create_partition::command_create_partition;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
- IVirtualizationService::IVirtualizationService, PartitionType::PartitionType,
- VirtualMachineAppConfig::DebugLevel::DebugLevel,
- VirtualMachineAppConfig::VirtualMachineAppConfig, VirtualMachineConfig::VirtualMachineConfig,
+ IVirtualizationService::IVirtualizationService,
+ PartitionType::PartitionType,
+ VirtualMachineAppConfig::{DebugLevel::DebugLevel, Payload::Payload, VirtualMachineAppConfig},
+ VirtualMachineConfig::VirtualMachineConfig,
VirtualMachineState::VirtualMachineState,
};
use anyhow::{bail, Context, Error};
@@ -96,7 +97,7 @@
idsig: idsig_fd.into(),
extraIdsigs: extra_idsig_fds,
instanceImage: open_parcel_file(instance, true /* writable */)?.into(),
- configPath: config_path.to_owned(),
+ payload: Payload::ConfigPath(config_path.to_owned()),
debugLevel: debug_level,
protectedVm: protected,
memoryMib: mem.unwrap_or(0) as i32, // 0 means use the VM default