Add last_update_seconds.
Bug: 211458160
Change-Id: I45eed42c0126cfde3b1b632c3ed90af57bdde455
diff --git a/microdroid/payload/metadata.proto b/microdroid/payload/metadata.proto
index 5ae2158..9e60b38 100644
--- a/microdroid/payload/metadata.proto
+++ b/microdroid/payload/metadata.proto
@@ -38,6 +38,11 @@
// When specified, apex payload should be verified with the public key and root digest.
bytes public_key = 3;
bytes root_digest = 4;
+
+ // Required.
+ // The timestamp in seconds when the APEX was last updated. This should match the value in
+ // apex-info-list.xml.
+ uint64 last_update_seconds = 5;
}
message ApkPayload {
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index aadb71f..cb59e3b 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -332,4 +332,5 @@
pub name: String,
pub public_key: Vec<u8>,
pub root_digest: Vec<u8>,
+ pub last_update_seconds: u64,
}
diff --git a/microdroid_manager/src/payload.rs b/microdroid_manager/src/payload.rs
index b731d33..661af5f 100644
--- a/microdroid_manager/src/payload.rs
+++ b/microdroid_manager/src/payload.rs
@@ -43,7 +43,12 @@
let name = apex.name.clone();
let apex_path = format!("/dev/block/by-name/{}", apex.partition_name);
let result = verify(&apex_path)?;
- Ok(ApexData { name, public_key: result.public_key, root_digest: result.root_digest })
+ Ok(ApexData {
+ name,
+ public_key: result.public_key,
+ root_digest: result.root_digest,
+ last_update_seconds: apex.last_update_seconds,
+ })
})
.collect()
}
@@ -57,6 +62,7 @@
name: data.name.clone(),
public_key: data.public_key.clone(),
root_digest: data.root_digest.clone(),
+ last_update_seconds: data.last_update_seconds,
..Default::default()
})
.collect(),
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 84d3b2f..65adc25 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -31,9 +31,10 @@
use serde::Deserialize;
use serde_xml_rs::from_reader;
use std::collections::HashSet;
-use std::fs::{File, OpenOptions};
+use std::fs::{metadata, File, OpenOptions};
use std::path::{Path, PathBuf};
use std::process::Command;
+use std::time::SystemTime;
use vmconfig::open_parcel_file;
/// The list of APEXes which microdroid requires.
@@ -61,6 +62,10 @@
#[serde(default)]
has_classpath_jar: bool,
+
+ // The field claims to be milliseconds but is actually seconds.
+ #[serde(rename = "lastUpdateMillis")]
+ last_update_seconds: u64,
}
impl ApexInfoList {
@@ -92,14 +97,15 @@
self.list.iter().filter(|info| predicate(info)).map(|info| info.name.clone()).collect()
}
- fn get_path_for(&self, apex_name: &str) -> Result<PathBuf> {
- Ok(self
- .list
+ fn get(&self, apex_name: &str) -> Result<&ApexInfo> {
+ self.list
.iter()
.find(|apex| apex.name == apex_name)
- .ok_or_else(|| anyhow!("{} not found.", apex_name))?
- .path
- .clone())
+ .ok_or_else(|| anyhow!("{} not found.", apex_name))
+ }
+
+ fn get_path_for(&self, apex_name: &str) -> Result<PathBuf> {
+ Ok(self.get(apex_name)?.path.clone())
}
}
@@ -125,10 +131,12 @@
let staged = pm.getStagedApexModuleNames()?;
for apex_info in list.list.iter_mut() {
if staged.contains(&apex_info.name) {
- let staged_apex_info = pm.getStagedApexInfo(&apex_info.name)?;
- if let Some(staged_apex_info) = staged_apex_info {
+ if let Some(staged_apex_info) = pm.getStagedApexInfo(&apex_info.name)? {
apex_info.path = PathBuf::from(staged_apex_info.diskImagePath);
apex_info.has_classpath_jar = staged_apex_info.hasClassPathJars;
+ let metadata = metadata(&apex_info.path)?;
+ apex_info.last_update_seconds =
+ metadata.modified()?.duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
}
}
}
@@ -141,6 +149,7 @@
config_path: &str,
apex_names: &[String],
temporary_directory: &Path,
+ apex_list: &ApexInfoList,
) -> Result<ParcelFileDescriptor> {
let metadata_path = temporary_directory.join("metadata");
let metadata = Metadata {
@@ -148,12 +157,15 @@
apexes: apex_names
.iter()
.enumerate()
- .map(|(i, apex_name)| ApexPayload {
- name: apex_name.clone(),
- partition_name: format!("microdroid-apex-{}", i),
- ..Default::default()
+ .map(|(i, apex_name)| {
+ Ok(ApexPayload {
+ name: apex_name.clone(),
+ partition_name: format!("microdroid-apex-{}", i),
+ last_update_seconds: apex_list.get(apex_name)?.last_update_seconds,
+ ..Default::default()
+ })
})
- .collect(),
+ .collect::<Result<_>>()?,
apk: Some(ApkPayload {
name: "apk".to_owned(),
payload_partition_name: "microdroid-apk".to_owned(),
@@ -212,7 +224,8 @@
let apexes = collect_apex_names(&apex_list, &vm_payload_config.apexes, app_config.debugLevel);
info!("Microdroid payload APEXes: {:?}", apexes);
- let metadata_file = make_metadata_file(&app_config.configPath, &apexes, temporary_directory)?;
+ let metadata_file =
+ make_metadata_file(&app_config.configPath, &apexes, temporary_directory, &apex_list)?;
// put metadata at the first partition
let mut partitions = vec![Partition {
label: "payload-metadata".to_owned(),
@@ -397,11 +410,13 @@
name: "hasnt_classpath".to_string(),
path: PathBuf::from("path0"),
has_classpath_jar: false,
+ last_update_seconds: 12345678,
},
ApexInfo {
name: "has_classpath".to_string(),
path: PathBuf::from("path1"),
has_classpath_jar: true,
+ last_update_seconds: 87654321,
},
],
};