blob: 9c6deae2291d8435858af85b2f4c89e107c1ad6a [file] [log] [blame]
Jooyung Han21e9b922021-06-26 04:14:16 +09001// Copyright 2021, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Payload disk image
16
Jooyung Han44b02ab2021-07-16 03:19:13 +090017use anyhow::{anyhow, Context, Result};
Jooyung Han21e9b922021-06-26 04:14:16 +090018use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
19use microdroid_payload_config::ApexConfig;
Jooyung Han9900f3d2021-07-06 10:27:54 +090020use once_cell::sync::OnceCell;
Jooyung Han44b02ab2021-07-16 03:19:13 +090021use serde::Deserialize;
22use serde_xml_rs::from_reader;
Jooyung Han44b02ab2021-07-16 03:19:13 +090023use std::fs::{File, OpenOptions};
Jooyung Han21e9b922021-06-26 04:14:16 +090024use std::path::{Path, PathBuf};
Jooyung Han21e9b922021-06-26 04:14:16 +090025use vmconfig::{DiskImage, Partition};
26
Jooyung Han44b02ab2021-07-16 03:19:13 +090027const APEX_INFO_LIST_PATH: &str = "/apex/apex-info-list.xml";
28
Jooyung Han73bac242021-07-02 10:25:49 +090029/// Represents the list of APEXes
Jooyung Han44b02ab2021-07-16 03:19:13 +090030#[derive(Debug, Deserialize)]
Jooyung Han9900f3d2021-07-06 10:27:54 +090031struct ApexInfoList {
Jooyung Han44b02ab2021-07-16 03:19:13 +090032 #[serde(rename = "apex-info")]
Jooyung Han73bac242021-07-02 10:25:49 +090033 list: Vec<ApexInfo>,
34}
35
Jooyung Han44b02ab2021-07-16 03:19:13 +090036#[derive(Debug, Deserialize)]
Jooyung Han73bac242021-07-02 10:25:49 +090037struct ApexInfo {
Jooyung Han44b02ab2021-07-16 03:19:13 +090038 #[serde(rename = "moduleName")]
Jooyung Han73bac242021-07-02 10:25:49 +090039 name: String,
Jooyung Han44b02ab2021-07-16 03:19:13 +090040 #[serde(rename = "modulePath")]
Jooyung Han73bac242021-07-02 10:25:49 +090041 path: PathBuf,
42}
43
44impl ApexInfoList {
45 /// Loads ApexInfoList
Jooyung Han9900f3d2021-07-06 10:27:54 +090046 fn load() -> Result<&'static ApexInfoList> {
47 static INSTANCE: OnceCell<ApexInfoList> = OnceCell::new();
48 INSTANCE.get_or_try_init(|| {
Jooyung Han44b02ab2021-07-16 03:19:13 +090049 let apex_info_list = File::open(APEX_INFO_LIST_PATH)
50 .context(format!("Failed to open {}", APEX_INFO_LIST_PATH))?;
51 let apex_info_list: ApexInfoList = from_reader(apex_info_list)
52 .context(format!("Failed to parse {}", APEX_INFO_LIST_PATH))?;
53 Ok(apex_info_list)
Jooyung Han9900f3d2021-07-06 10:27:54 +090054 })
Jooyung Han73bac242021-07-02 10:25:49 +090055 }
56
57 fn get_path_for(&self, apex_name: &str) -> Result<PathBuf> {
58 Ok(self
59 .list
60 .iter()
61 .find(|apex| apex.name == apex_name)
62 .ok_or_else(|| anyhow!("{} not found.", apex_name))?
63 .path
64 .clone())
65 }
Jooyung Han21e9b922021-06-26 04:14:16 +090066}
67
Jooyung Han21e9b922021-06-26 04:14:16 +090068/// Creates a DiskImage with partitions:
69/// metadata: metadata
Jooyung Han95884632021-07-06 22:27:54 +090070/// microdroid-apex-0: apex 0
71/// microdroid-apex-1: apex 1
Jooyung Han21e9b922021-06-26 04:14:16 +090072/// ..
Jooyung Han95884632021-07-06 22:27:54 +090073/// microdroid-apk: apk
Jooyung Han21e9b922021-06-26 04:14:16 +090074/// microdroid-apk-idsig: idsig
Jooyung Han73bac242021-07-02 10:25:49 +090075pub fn make_payload_disk(
Jooyung Han21e9b922021-06-26 04:14:16 +090076 apk_file: PathBuf,
77 idsig_file: PathBuf,
78 config_path: &str,
79 apexes: &[ApexConfig],
80 temporary_directory: &Path,
81) -> Result<DiskImage> {
82 let metadata_path = temporary_directory.join("metadata");
83 let metadata = Metadata {
84 version: 1u32,
85 apexes: apexes
86 .iter()
Jooyung Han35edb8f2021-07-01 16:17:16 +090087 .map(|apex| ApexPayload { name: apex.name.clone(), ..Default::default() })
Jooyung Han21e9b922021-06-26 04:14:16 +090088 .collect(),
89 apk: Some(ApkPayload {
Jooyung Han35edb8f2021-07-01 16:17:16 +090090 name: "apk".to_owned(),
91 payload_partition_name: "microdroid-apk".to_owned(),
92 idsig_partition_name: "microdroid-apk-idsig".to_owned(),
Jooyung Han21e9b922021-06-26 04:14:16 +090093 ..Default::default()
94 })
95 .into(),
96 payload_config_path: format!("/mnt/apk/{}", config_path),
97 ..Default::default()
98 };
99 let mut metadata_file =
100 OpenOptions::new().create_new(true).read(true).write(true).open(&metadata_path)?;
101 microdroid_metadata::write_metadata(&metadata, &mut metadata_file)?;
102
103 // put metadata at the first partition
104 let mut partitions = vec![Partition {
Jooyung Han14e5a8e2021-07-06 20:48:38 +0900105 label: "payload-metadata".to_owned(),
Jooyung Han54f422f2021-07-01 00:37:19 +0900106 paths: vec![metadata_path],
Jooyung Han21e9b922021-06-26 04:14:16 +0900107 writable: false,
108 }];
109
Jooyung Han9900f3d2021-07-06 10:27:54 +0900110 let apex_info_list = ApexInfoList::load()?;
Jooyung Han21e9b922021-06-26 04:14:16 +0900111 for (i, apex) in apexes.iter().enumerate() {
Jooyung Han95884632021-07-06 22:27:54 +0900112 partitions.push(Partition {
113 label: format!("microdroid-apex-{}", i),
114 paths: vec![apex_info_list.get_path_for(&apex.name)?],
115 writable: false,
116 });
Jooyung Han21e9b922021-06-26 04:14:16 +0900117 }
Jooyung Han95884632021-07-06 22:27:54 +0900118 partitions.push(Partition {
119 label: "microdroid-apk".to_owned(),
120 paths: vec![apk_file],
121 writable: false,
122 });
123 partitions.push(Partition {
124 label: "microdroid-apk-idsig".to_owned(),
125 paths: vec![idsig_file],
126 writable: false,
127 });
Jooyung Han21e9b922021-06-26 04:14:16 +0900128
129 Ok(DiskImage { image: None, partitions, writable: false })
130}