Merge changes from topics "b/308759880", "b/313042092" into main

* changes:
  Add APEX info to the DICE chain
  Get apexd to verify manifest data
  Test improvements.
  Parse APEX manifest
diff --git a/libs/apexutil/Android.bp b/libs/apexutil/Android.bp
index f9b72c4..beff58d 100644
--- a/libs/apexutil/Android.bp
+++ b/libs/apexutil/Android.bp
@@ -9,7 +9,9 @@
     srcs: ["src/lib.rs"],
     edition: "2021",
     rustlibs: [
+        "libapex_manifest_rs",
         "liblog_rust",
+        "libprotobuf",
         "libthiserror",
         "libvbmeta_rust",
         "libzip",
@@ -26,7 +28,12 @@
     defaults: ["libapexutil_rust.defaults"],
     prefer_rlib: true,
     test_suites: ["general-tests"],
-    data: ["tests/data/*"],
+    // We're reusing test APEXes from system/apex/apexd
+    data: [
+        ":apex.apexd_test",
+        ":apex.apexd_test_v2_no_pb",
+        ":gen_key_mismatch_with_image_apex",
+    ],
     rustlibs: [
         "libhex",
     ],
diff --git a/libs/apexutil/src/lib.rs b/libs/apexutil/src/lib.rs
index 8a934e2..639135f 100644
--- a/libs/apexutil/src/lib.rs
+++ b/libs/apexutil/src/lib.rs
@@ -14,6 +14,8 @@
 
 //! Routines for handling APEX payload
 
+use apex_manifest::apex_manifest::ApexManifest;
+use protobuf::Message;
 use std::fs::File;
 use std::io::{self, Read};
 use thiserror::Error;
@@ -23,28 +25,32 @@
 
 const APEX_PUBKEY_ENTRY: &str = "apex_pubkey";
 const APEX_PAYLOAD_ENTRY: &str = "apex_payload.img";
+const APEX_MANIFEST_ENTRY: &str = "apex_manifest.pb";
 
 /// Errors from parsing an APEX.
 #[derive(Debug, Error)]
 pub enum ApexParseError {
     /// There was an IO error.
-    #[error("IO error")]
+    #[error("IO error: {0}")]
     Io(#[from] io::Error),
     /// The Zip archive was invalid.
-    #[error("Cannot read zip archive")]
+    #[error("Cannot read zip archive: {0}")]
     InvalidZip(&'static str),
-    /// The apex_pubkey file was missing from the APEX.
-    #[error("APEX doesn't contain apex_pubkey")]
-    PubkeyMissing,
-    /// The apex_payload.img file was missing from the APEX.
-    #[error("APEX doesn't contain apex_payload.img")]
-    PayloadMissing,
+    /// An expected file was missing from the APEX.
+    #[error("APEX doesn't contain {0}")]
+    MissingFile(&'static str),
     /// There was no hashtree descriptor in the APEX payload's VBMeta image.
     #[error("Non-hashtree descriptor found in payload's VBMeta image")]
     DescriptorNotHashtree,
     /// There was an error parsing the APEX payload's VBMeta image.
-    #[error("Could not parse payload's VBMeta image")]
+    #[error("Could not parse payload's VBMeta image: {0}")]
     PayloadVbmetaError(#[from] vbmeta::VbMetaImageParseError),
+    /// Data was missing from the VBMeta
+    #[error("Data missing from VBMeta: {0}")]
+    VbmetaMissingData(&'static str),
+    /// An error occurred parsing the APEX manifest as a protobuf
+    #[error("Error parsing manifest protobuf: {0}")]
+    ManifestProtobufError(#[from] protobuf::Error),
 }
 
 /// Errors from verifying an APEX.
@@ -58,29 +64,44 @@
     PayloadVbmetaError(#[from] vbmeta::VbMetaImageVerificationError),
     /// The APEX payload was not verified with the apex_pubkey.
     #[error("APEX pubkey mismatch")]
-    ApexPubkeyMistmatch,
+    ApexPubkeyMismatch,
 }
 
-/// Verification result holds public key and root digest of apex_payload.img
+/// Information extracted from the APEX during AVB verification.
+#[derive(Debug)]
 pub struct ApexVerificationResult {
+    /// The name of the APEX, from its manifest.
+    pub name: Option<String>,
+    /// The version of the APEX, from its manifest.
+    pub version: Option<i64>,
     /// The public key that verifies the payload signature.
     pub public_key: Vec<u8>,
     /// The root digest of the payload hashtree.
     pub root_digest: Vec<u8>,
 }
 
-/// Verify APEX payload by AVB verification and return public key and root digest
+/// Verify APEX payload by AVB verification and return information about the APEX.
+/// This verifies that the VBMeta is correctly signed by the public key specified in the APEX.
+/// It doesn't verify that that is the correct key, nor does it verify that the payload matches
+/// the signed root hash - that is handled by dm-verity once apexd has mounted the APEX.
 pub fn verify(path: &str) -> Result<ApexVerificationResult, ApexVerificationError> {
     let apex_file = File::open(path).map_err(ApexParseError::Io)?;
-    let (public_key, image_offset, image_size) = get_public_key_and_image_info(&apex_file)?;
+    let ApexZipInfo { public_key, image_offset, image_size, manifest } =
+        get_apex_zip_info(&apex_file)?;
     let vbmeta = VbMetaImage::verify_reader_region(apex_file, image_offset, image_size)?;
     let root_digest = find_root_digest(&vbmeta)?;
-    match vbmeta.public_key() {
-        Some(payload_public_key) if public_key == payload_public_key => {
-            Ok(ApexVerificationResult { public_key, root_digest })
-        }
-        _ => Err(ApexVerificationError::ApexPubkeyMistmatch),
+    let vbmeta_public_key =
+        vbmeta.public_key().ok_or(ApexParseError::VbmetaMissingData("public key"))?;
+    if vbmeta_public_key != public_key {
+        return Err(ApexVerificationError::ApexPubkeyMismatch);
     }
+    let (name, version) = if cfg!(dice_changes) {
+        let ApexManifestInfo { name, version } = decode_manifest(&manifest)?;
+        (Some(name), Some(version))
+    } else {
+        (None, None)
+    };
+    Ok(ApexVerificationResult { name, version, public_key, root_digest })
 }
 
 fn find_root_digest(vbmeta: &VbMetaImage) -> Result<Vec<u8>, ApexParseError> {
@@ -93,46 +114,52 @@
     Err(ApexParseError::DescriptorNotHashtree)
 }
 
-/// Gets the hash of the payload's verified VBMeta image data.
-pub fn get_payload_vbmeta_image_hash(path: &str) -> Result<Vec<u8>, ApexVerificationError> {
-    let apex_file = File::open(path).map_err(ApexParseError::Io)?;
-    let (_, offset, size) = get_public_key_and_image_info(&apex_file)?;
-    let vbmeta = VbMetaImage::verify_reader_region(apex_file, offset, size)?;
-    Ok(vbmeta.hash().ok_or(ApexVerificationError::ApexPubkeyMistmatch)?.to_vec())
+struct ApexZipInfo {
+    public_key: Vec<u8>,
+    image_offset: u64,
+    image_size: u64,
+    manifest: Vec<u8>,
 }
 
-fn get_public_key_and_image_info(apex_file: &File) -> Result<(Vec<u8>, u64, u64), ApexParseError> {
-    let mut z = ZipArchive::new(apex_file).map_err(|err| match err {
-        ZipError::Io(err) => ApexParseError::Io(err),
-        ZipError::InvalidArchive(s) | ZipError::UnsupportedArchive(s) => {
-            ApexParseError::InvalidZip(s)
-        }
-        ZipError::FileNotFound => unreachable!(),
-    })?;
+fn get_apex_zip_info(apex_file: &File) -> Result<ApexZipInfo, ApexParseError> {
+    let mut z = ZipArchive::new(apex_file).map_err(|err| from_zip_error(err, "?"))?;
 
     let mut public_key = Vec::new();
     z.by_name(APEX_PUBKEY_ENTRY)
-        .map_err(|err| match err {
-            ZipError::Io(err) => ApexParseError::Io(err),
-            ZipError::FileNotFound => ApexParseError::PubkeyMissing,
-            ZipError::InvalidArchive(s) | ZipError::UnsupportedArchive(s) => {
-                ApexParseError::InvalidZip(s)
-            }
-        })?
+        .map_err(|err| from_zip_error(err, APEX_PUBKEY_ENTRY))?
         .read_to_end(&mut public_key)?;
 
     let (image_offset, image_size) = z
         .by_name(APEX_PAYLOAD_ENTRY)
         .map(|f| (f.data_start(), f.size()))
-        .map_err(|err| match err {
-            ZipError::Io(err) => ApexParseError::Io(err),
-            ZipError::FileNotFound => ApexParseError::PayloadMissing,
-            ZipError::InvalidArchive(s) | ZipError::UnsupportedArchive(s) => {
-                ApexParseError::InvalidZip(s)
-            }
-        })?;
+        .map_err(|err| from_zip_error(err, APEX_PAYLOAD_ENTRY))?;
 
-    Ok((public_key, image_offset, image_size))
+    let mut manifest = Vec::new();
+    z.by_name(APEX_MANIFEST_ENTRY)
+        .map_err(|err| from_zip_error(err, APEX_MANIFEST_ENTRY))?
+        .read_to_end(&mut manifest)?;
+
+    Ok(ApexZipInfo { public_key, image_offset, image_size, manifest })
+}
+
+struct ApexManifestInfo {
+    name: String,
+    version: i64,
+}
+
+fn decode_manifest(mut manifest: &[u8]) -> Result<ApexManifestInfo, ApexParseError> {
+    let manifest = ApexManifest::parse_from_reader(&mut manifest)?;
+    Ok(ApexManifestInfo { name: manifest.name, version: manifest.version })
+}
+
+fn from_zip_error(err: ZipError, name: &'static str) -> ApexParseError {
+    match err {
+        ZipError::Io(err) => ApexParseError::Io(err),
+        ZipError::InvalidArchive(s) | ZipError::UnsupportedArchive(s) => {
+            ApexParseError::InvalidZip(s)
+        }
+        ZipError::FileNotFound => ApexParseError::MissingFile(name),
+    }
 }
 
 #[cfg(test)]
@@ -141,20 +168,68 @@
 
     #[test]
     fn apex_verification_returns_valid_result() {
-        let res = verify("tests/data/test.apex").unwrap();
-        // The expected hex is generated when we ran the method the first time.
+        let res = verify("apex.apexd_test.apex").unwrap();
+        let (expected_name, expected_version) = if cfg!(dice_changes) {
+            (Some("com.android.apex.test_package"), Some(1))
+        } else {
+            (None, None)
+        };
+        assert_eq!(res.name.as_deref(), expected_name);
+        assert_eq!(res.version, expected_version);
+        // The expected hex values were generated when we ran the method the first time.
         assert_eq!(
             hex::encode(res.root_digest),
-            "fe11ab17da0a3a738b54bdc3a13f6139cbdf91ec32f001f8d4bbbf8938e04e39"
+            "54265da77ae1fd619e39809ad99fedc576bb20c0c7a8002190fa64438436299f"
+        );
+        assert_eq!(
+            hex::encode(res.public_key),
+            "\
+            00001000963a5527aaf0145b3bb5f899a05034ccc76dafdd671dbf4e42c04df2eeba15\
+            6c884816d7d08ef8d834d4adc27979afed9eaf406694d0d600f0b6d31e3ab85da47d27\
+            9c223a1630e02332d920587617ea766a136057a3a3232a7c42f83fb3763e853be4026c\
+            067524a95fcbfcc6caadfb553210bb5385f5adc5caeb0e3f6a9aa56af88d8899d962eb\
+            807864feabeeacdd868697935fb4cc4843957e0d90ee4293c715c4e5b970e6545a17d1\
+            735f814c7d4dbdeaac97275a84f292e3715c158d38eb00eebd010dd2fa56595c0e5627\
+            06c7a94e566912f993e5e35c04b2a314d1bce1ceb10de6c50f8101ddb6ee993fc79959\
+            2e79ee73b77741ee5c076c89343684344a6d080e5529a046d506d104bf32903e39c363\
+            b020fee9d87e7c6ffdad120b630386e958416ac156bc2d7301836c79e926e8f185a640\
+            be05135e17018c88dde02cd7bd49655e9e9dff7f965fb8e68217236c18d23b6d7e7632\
+            184acb95b088598601c809d5e66c19f5e06b5e5ff1bbae7e3142959d9380db2d4a25c8\
+            757975232ea311016e830703a6023b0986e885f2eda066517fce09f33f359b6ef7cc5a\
+            2fdaced74257661bad184a653ea2d80d1af68de5821c06a472635f0276dc42d699f588\
+            ea6c46189ca1ad544bbd4951a766bc4119b0ea671cb16556762721723bf1db47c83c76\
+            a7cc2fd3b6029efec9908d9d4640294f6ea46f6e1a3195e9252c393e35698911a7c496\
+            138dc2dd8d9dcb470ae1c6d2224d13b160fb3ae4bc235f6133c2ff5f9232fb89adfdba\
+            48dcc47cf29a22cd47dcec0b1a179f352c9848a8e04ac37f35777a24312c821febc591\
+            84c8cdefc88e50b4d6bc9530ca743f4284c9773677d38527e6e8020fe367f0f16a6c49\
+            9a7f2da95ec6471f7382e5c0da98b531702cb55a560de7cafc7b6111aae0f896fb1fed\
+            d4997a954c6c083ef1fd3bb13fef3f95022523fb1fbe7f4a49e12e54a5206f95daa316\
+            ac009b7bee4039f769fd28033db6013df841c86d8345d44418fbc9f669e4ee3294b2ff\
+            29d048f53d768c0a41f9a280f0229d9912e8b2fb734617a9947be973ed1dc7bdeac9e2\
+            6028d59317098a44bacdb3b10ccde6ef02f7c94124461032a033701ce523b13142658c\
+            265385198903ccf227ad5ae88ec31e586cd8f855641fd2646dba8053d0d0924f132505\
+            8141f1c7433aa9686f48e3f3a972b56776eaf8bf22a740d1aea2ef473184d697de1dab\
+            9b62a227611c7500b11dea2e5eb8051807c0d1f2fe032acfd7701c017e629f99c74de5\
+            da4c2a542f17b9833beb14442aa7c2990b828473376ea03fdb4a650b88e821fe5026e8\
+            ffb7002d095c9877ee3a98a4488ed3287e9be4942a223f4e32bc26c2ebd02eec20dc82\
+            7493b44f4efaf9b2e175d4de2b07c32d6d359e234c9e50ef905ffa7f6907c313a3c9f4\
+            40d1efd5ec7cbeef06dcfd649f4c8219ad"
         );
     }
 
     #[test]
-    fn payload_vbmeta_has_valid_image_hash() {
-        let result = get_payload_vbmeta_image_hash("tests/data/test.apex").unwrap();
-        assert_eq!(
-            hex::encode(result),
-            "296e32a76544de9da01713e471403ab4667705ad527bb4f1fac0cf61e7ce122d"
-        );
+    fn apex_no_manifest_fails_verification() {
+        match verify("apex.apexd_test_v2_no_pb.apex").unwrap_err() {
+            ApexVerificationError::ParseError(ApexParseError::MissingFile(_)) => (),
+            e => panic!("Unexpected error {e}"),
+        }
+    }
+
+    #[test]
+    fn apex_signature_mismatch_fails_verification() {
+        match verify("apex.apexd_test_wrong_public_key.apex").unwrap_err() {
+            ApexVerificationError::ApexPubkeyMismatch => (),
+            e => panic!("Unexpected error {e}"),
+        }
     }
 }
diff --git a/libs/apexutil/tests/data/README.md b/libs/apexutil/tests/data/README.md
deleted file mode 100644
index 82ebec6..0000000
--- a/libs/apexutil/tests/data/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Test data
-
-- test.apex: copied from system/apexshim/prebuilts/x86/com.android.apex.cts.shim.v1.apex
\ No newline at end of file
diff --git a/libs/apexutil/tests/data/test.apex b/libs/apexutil/tests/data/test.apex
deleted file mode 100644
index fd79365..0000000
--- a/libs/apexutil/tests/data/test.apex
+++ /dev/null
Binary files differ
diff --git a/microdroid/payload/metadata.proto b/microdroid/payload/metadata.proto
index 6b999af..b03d466 100644
--- a/microdroid/payload/metadata.proto
+++ b/microdroid/payload/metadata.proto
@@ -37,14 +37,18 @@
 }
 
 message ApexPayload {
+  // Next id: 9
+
   // Required.
   string name = 1;
   string partition_name = 2;
 
   // Optional.
-  // When specified, apex payload should be verified with the public key and root digest.
+  // When specified, apex payload should be verified against these values.
   bytes public_key = 3;
   bytes root_digest = 4;
+  int64 manifest_version = 7;
+  string manifest_name = 8;
 
   // Required.
   // The timestamp in seconds when the APEX was last updated. This should match the value in
diff --git a/microdroid_manager/src/dice.rs b/microdroid_manager/src/dice.rs
index 6b0775a..e6ddfb9 100644
--- a/microdroid_manager/src/dice.rs
+++ b/microdroid_manager/src/dice.rs
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 use crate::dice_driver::DiceDriver;
-use crate::instance::ApkData;
+use crate::instance::{ApexData, ApkData};
 use crate::{is_debuggable, MicrodroidData};
 use anyhow::{bail, Context, Result};
 use ciborium::{cbor, Value};
@@ -26,24 +26,23 @@
 /// Perform an open DICE derivation for the payload.
 pub fn dice_derivation(
     dice: DiceDriver,
-    verified_data: &MicrodroidData,
+    instance_data: &MicrodroidData,
     payload_metadata: &PayloadMetadata,
 ) -> Result<OwnedDiceArtifacts> {
-    let subcomponents = build_subcomponent_list(verified_data);
-
+    let subcomponents = build_subcomponent_list(instance_data);
     let config_descriptor = format_payload_config_descriptor(payload_metadata, &subcomponents)
         .context("Building config descriptor")?;
 
     // Calculate compound digests of code and authorities
     let mut code_hash_ctx = Sha512::new();
     let mut authority_hash_ctx = Sha512::new();
-    code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
-    authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
-    for extra_apk in &verified_data.extra_apks_data {
+    code_hash_ctx.update(instance_data.apk_data.root_hash.as_ref());
+    authority_hash_ctx.update(instance_data.apk_data.pubkey.as_ref());
+    for extra_apk in &instance_data.extra_apks_data {
         code_hash_ctx.update(extra_apk.root_hash.as_ref());
         authority_hash_ctx.update(extra_apk.pubkey.as_ref());
     }
-    for apex in &verified_data.apex_data {
+    for apex in &instance_data.apex_data {
         code_hash_ctx.update(apex.root_digest.as_ref());
         authority_hash_ctx.update(apex.public_key.as_ref());
     }
@@ -54,7 +53,7 @@
     let debuggable = is_debuggable()?;
 
     // Send the details to diced
-    let hidden = verified_data.salt.clone().try_into().unwrap();
+    let hidden = instance_data.salt.clone().try_into().unwrap();
     dice.derive(code_hash, &config_descriptor, authority_hash, debuggable, hidden)
 }
 
@@ -85,17 +84,29 @@
                 Box::new(sha512(&apk.pubkey)),
         }
     }
+
+    fn for_apex(apex: &'a ApexData) -> Self {
+        // Note that this is only reachable if the dice_changes flag is on, in which case
+        // the manifest data will always be present.
+        Self {
+            name: format!("apex:{}", apex.manifest_name.as_ref().unwrap()),
+            version: apex.manifest_version.unwrap() as u64,
+            code_hash: &apex.root_digest,
+            authority_hash: Box::new(sha512(&apex.public_key)),
+        }
+    }
 }
 
-fn build_subcomponent_list(verified_data: &MicrodroidData) -> Vec<Subcomponent> {
+fn build_subcomponent_list(instance_data: &MicrodroidData) -> Vec<Subcomponent> {
     if !cfg!(dice_changes) {
         return vec![];
     }
 
-    once(&verified_data.apk_data)
-        .chain(&verified_data.extra_apks_data)
-        .map(Subcomponent::for_apk)
-        .collect()
+    let apks = once(&instance_data.apk_data)
+        .chain(&instance_data.extra_apks_data)
+        .map(Subcomponent::for_apk);
+    let apexes = instance_data.apex_data.iter().map(Subcomponent::for_apex);
+    apks.chain(apexes).collect()
 }
 
 // Returns a configuration descriptor of the given payload. See vm_config.cddl for a definition
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index 6c9e245..b0fc03d 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -304,6 +304,8 @@
 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
 pub struct ApexData {
     pub name: String,
+    pub manifest_name: Option<String>,
+    pub manifest_version: Option<i64>,
     pub public_key: Vec<u8>,
     pub root_digest: Vec<u8>,
     pub last_update_seconds: u64,
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 1b41e58..9e167a4 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -246,20 +246,20 @@
     }
 
     // Verify the payload before using it.
-    let verified_data = verify_payload(&metadata, saved_data.as_ref())
+    let extracted_data = verify_payload(&metadata, saved_data.as_ref())
         .context("Payload verification failed")
         .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
 
     // In case identity is ignored (by debug policy), we should reuse existing payload data, even
     // when the payload is changed. This is to keep the derived secret same as before.
-    let verified_data = if let Some(saved_data) = saved_data {
+    let instance_data = if let Some(saved_data) = saved_data {
         if !is_verified_boot() {
-            if saved_data != verified_data {
+            if saved_data != extracted_data {
                 info!("Detected an update of the payload, but continue (regarding debug policy)")
             }
         } else {
             ensure!(
-                saved_data == verified_data,
+                saved_data == extracted_data,
                 MicrodroidError::PayloadChanged(String::from(
                     "Detected an update of the payload which isn't supported yet."
                 ))
@@ -270,9 +270,9 @@
     } else {
         info!("Saving verified data.");
         instance
-            .write_microdroid_data(&verified_data, &dice)
+            .write_microdroid_data(&extracted_data, &dice)
             .context("Failed to write identity data")?;
-        verified_data
+        extracted_data
     };
 
     let payload_metadata = metadata.payload.ok_or_else(|| {
@@ -281,7 +281,7 @@
 
     // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
     info!("DICE derivation for payload");
-    let dice_artifacts = dice_derivation(dice, &verified_data, &payload_metadata)?;
+    let dice_artifacts = dice_derivation(dice, &instance_data, &payload_metadata)?;
     let vm_secret = VmSecret::new(dice_artifacts).context("Failed to create VM secrets")?;
 
     if cfg!(dice_changes) {
@@ -326,10 +326,10 @@
         .ok_or_else(|| MicrodroidError::PayloadInvalidConfig("No task in VM config".to_string()))?;
 
     ensure!(
-        config.extra_apks.len() == verified_data.extra_apks_data.len(),
+        config.extra_apks.len() == instance_data.extra_apks_data.len(),
         "config expects {} extra apks, but found {}",
         config.extra_apks.len(),
-        verified_data.extra_apks_data.len()
+        instance_data.extra_apks_data.len()
     );
     mount_extra_apks(&config, &mut zipfuse)?;
 
diff --git a/microdroid_manager/src/payload.rs b/microdroid_manager/src/payload.rs
index a553ce4..98fe24b 100644
--- a/microdroid_manager/src/payload.rs
+++ b/microdroid_manager/src/payload.rs
@@ -17,8 +17,7 @@
 use crate::instance::ApexData;
 use crate::ioutil::wait_for_file;
 use anyhow::Result;
-use apexutil::verify;
-use log::info;
+use log::{info, warn};
 use microdroid_metadata::{read_metadata, ApexPayload, Metadata};
 use std::time::Duration;
 
@@ -38,13 +37,19 @@
         .apexes
         .iter()
         .map(|apex| {
-            let name = apex.name.clone();
             let apex_path = format!("/dev/block/by-name/{}", apex.partition_name);
-            let result = verify(&apex_path)?;
+            let extracted = apexutil::verify(&apex_path)?;
+            if let Some(manifest_name) = &extracted.name {
+                if &apex.name != manifest_name {
+                    warn!("Apex named {} is named {} in its manifest", apex.name, manifest_name);
+                }
+            };
             Ok(ApexData {
-                name,
-                public_key: result.public_key,
-                root_digest: result.root_digest,
+                name: apex.name.clone(),
+                manifest_name: extracted.name,
+                manifest_version: extracted.version,
+                public_key: extracted.public_key,
+                root_digest: extracted.root_digest,
                 last_update_seconds: apex.last_update_seconds,
                 is_factory: apex.is_factory,
             })
@@ -61,6 +66,8 @@
                 name: data.name.clone(),
                 public_key: data.public_key.clone(),
                 root_digest: data.root_digest.clone(),
+                manifest_name: data.manifest_name.clone().unwrap_or_default(),
+                manifest_version: data.manifest_version.unwrap_or_default(),
                 last_update_seconds: data.last_update_seconds,
                 is_factory: data.is_factory,
                 ..Default::default()