virtualizationservice: lazy-load ApexInfoList
Loading ApexInfoList can't be used to initialize VirtualizationService
because when it fails VirtualizationService enters into infinite loop
due to service restart.
Now it is loaded lazily.
Bug: 192892281
Test: MicrodroidHostTestCases
Change-Id: I3c082d200549c348ff8fa03ff25ca73f9fb694cd
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index d3dc289..18e7de5 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -16,9 +16,10 @@
use crate::composite::align_to_partition_size;
-use anyhow::{anyhow, Result};
+use anyhow::{anyhow, bail, Result};
use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
use microdroid_payload_config::ApexConfig;
+use once_cell::sync::OnceCell;
use regex::Regex;
use std::fs;
use std::fs::OpenOptions;
@@ -29,7 +30,7 @@
/// Represents the list of APEXes
#[derive(Debug)]
-pub struct ApexInfoList {
+struct ApexInfoList {
list: Vec<ApexInfo>,
}
@@ -41,30 +42,38 @@
impl ApexInfoList {
/// Loads ApexInfoList
- pub fn load() -> Result<ApexInfoList> {
- // TODO(b/191601801): look up /apex/apex-info-list.xml instead of apexservice
- // Each APEX prints the line:
- // Module: <...> Version: <...> VersionName: <...> Path: <...> IsActive: <...> IsFactory: <...>
- // We only care about "Module:" and "Path:" tagged values for now.
- let info_pattern = Regex::new(r"^Module: (?P<name>[^ ]*) .* Path: (?P<path>[^ ]*) .*$")?;
- let output = Command::new("cmd")
- .arg("-w")
- .arg("apexservice")
- .arg("getActivePackages")
- .output()
- .expect("failed to execute apexservice cmd");
- let list = BufReader::new(output.stdout.as_slice())
- .lines()
- .map(|line| -> Result<ApexInfo> {
- let line = line?;
- let captures =
- info_pattern.captures(&line).ok_or_else(|| anyhow!("can't parse: {}", line))?;
- let name = captures.name("name").unwrap();
- let path = captures.name("path").unwrap();
- Ok(ApexInfo { name: name.as_str().to_owned(), path: path.as_str().into() })
- })
- .collect::<Result<Vec<ApexInfo>>>()?;
- Ok(ApexInfoList { list })
+ fn load() -> Result<&'static ApexInfoList> {
+ static INSTANCE: OnceCell<ApexInfoList> = OnceCell::new();
+ INSTANCE.get_or_try_init(|| {
+ // TODO(b/191601801): look up /apex/apex-info-list.xml instead of apexservice
+ // Each APEX prints the line:
+ // Module: <...> Version: <...> VersionName: <...> Path: <...> IsActive: <...> IsFactory: <...>
+ // We only care about "Module:" and "Path:" tagged values for now.
+ let info_pattern =
+ Regex::new(r"^Module: (?P<name>[^ ]*) .* Path: (?P<path>[^ ]*) .*$")?;
+ let output = Command::new("cmd")
+ .arg("-w")
+ .arg("apexservice")
+ .arg("getActivePackages")
+ .output()
+ .expect("failed to execute apexservice cmd");
+ let list = BufReader::new(output.stdout.as_slice())
+ .lines()
+ .map(|line| -> Result<ApexInfo> {
+ let line = line?;
+ let captures = info_pattern
+ .captures(&line)
+ .ok_or_else(|| anyhow!("can't parse: {}", line))?;
+ let name = captures.name("name").unwrap();
+ let path = captures.name("path").unwrap();
+ Ok(ApexInfo { name: name.as_str().to_owned(), path: path.as_str().into() })
+ })
+ .collect::<Result<Vec<ApexInfo>>>()?;
+ if list.is_empty() {
+ bail!("failed to load apex info: empty");
+ }
+ Ok(ApexInfoList { list })
+ })
}
fn get_path_for(&self, apex_name: &str) -> Result<PathBuf> {
@@ -120,7 +129,6 @@
/// microdroid-apk: [apk, zero filler]
/// microdroid-apk-idsig: idsig
pub fn make_payload_disk(
- apex_info_list: &ApexInfoList,
apk_file: PathBuf,
idsig_file: PathBuf,
config_path: &str,
@@ -155,6 +163,7 @@
writable: false,
}];
+ let apex_info_list = ApexInfoList::load()?;
let mut filler_count = 0;
for (i, apex) in apexes.iter().enumerate() {
partitions.push(make_partition(