mirror of
https://github.com/chenxiaolong/avbroot.git
synced 2026-07-03 14:05:11 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf5ef13e47 | |||
| 5fada419cb | |||
| eeea9f41b4 | |||
| 0bebf120c6 | |||
| 264c602fdb | |||
| 343e2e279c | |||
| 59ca759262 |
@@ -7,6 +7,12 @@
|
||||
to update the actual links at the bottom of the file.
|
||||
-->
|
||||
|
||||
### Version 3.6.0
|
||||
|
||||
* Add support for gzip compression when computing CoW size estimates ([Issue #332], [PR #333])
|
||||
* This allows `--replace` to successfully replace dynamic partitions on legacy devices, like the Pixel 4a 5G
|
||||
* Minor code cleanup ([PR #334], [PR #335])
|
||||
|
||||
### Version 3.5.0
|
||||
|
||||
* Update all dependencies ([PR #329])
|
||||
@@ -236,6 +242,7 @@ Behind-the-scenes changes:
|
||||
[Issue #306]: https://github.com/chenxiaolong/avbroot/issues/306
|
||||
[Issue #310]: https://github.com/chenxiaolong/avbroot/issues/310
|
||||
[Issue #328]: https://github.com/chenxiaolong/avbroot/issues/328
|
||||
[Issue #332]: https://github.com/chenxiaolong/avbroot/issues/332
|
||||
[PR #130]: https://github.com/chenxiaolong/avbroot/pull/130
|
||||
[PR #132]: https://github.com/chenxiaolong/avbroot/pull/132
|
||||
[PR #133]: https://github.com/chenxiaolong/avbroot/pull/133
|
||||
@@ -333,3 +340,6 @@ Behind-the-scenes changes:
|
||||
[PR #323]: https://github.com/chenxiaolong/avbroot/pull/323
|
||||
[PR #329]: https://github.com/chenxiaolong/avbroot/pull/329
|
||||
[PR #331]: https://github.com/chenxiaolong/avbroot/pull/331
|
||||
[PR #333]: https://github.com/chenxiaolong/avbroot/pull/333
|
||||
[PR #334]: https://github.com/chenxiaolong/avbroot/pull/334
|
||||
[PR #335]: https://github.com/chenxiaolong/avbroot/pull/335
|
||||
|
||||
Generated
+21
-5
@@ -8,6 +8,12 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
@@ -109,7 +115,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "avbroot"
|
||||
version = "3.5.0"
|
||||
version = "3.6.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_matches",
|
||||
@@ -132,6 +138,7 @@ dependencies = [
|
||||
"liblzma",
|
||||
"lz4_flex",
|
||||
"memchr",
|
||||
"miniz_oxide 0.8.0",
|
||||
"num-bigint-dig",
|
||||
"num-traits",
|
||||
"phf",
|
||||
@@ -541,7 +548,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "e2e"
|
||||
version = "3.5.0"
|
||||
version = "3.6.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"avbroot",
|
||||
@@ -613,7 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -635,7 +642,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fuzz"
|
||||
version = "3.5.0"
|
||||
version = "3.6.0"
|
||||
dependencies = [
|
||||
"avbroot",
|
||||
"honggfuzz",
|
||||
@@ -953,6 +960,15 @@ dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
@@ -2050,7 +2066,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "3.5.0"
|
||||
version = "3.6.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ members = ["avbroot", "e2e", "fuzz", "xtask"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "3.5.0"
|
||||
version = "3.6.0"
|
||||
license = "GPL-3.0-only"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/chenxiaolong/avbroot"
|
||||
|
||||
@@ -27,6 +27,7 @@ hex = { version = "0.4.3", features = ["serde"] }
|
||||
liblzma = "0.3.0"
|
||||
lz4_flex = "0.11.1"
|
||||
memchr = "2.6.0"
|
||||
miniz_oxide = "0.8.0"
|
||||
num-bigint-dig = "0.8.4"
|
||||
num-traits = "0.2.16"
|
||||
phf = { version = "0.11.2", features = ["macros"] }
|
||||
|
||||
+4
-37
@@ -37,39 +37,6 @@ pub enum Command {
|
||||
MagiskInfo(boot::MagiskInfoCli),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||
pub enum LogLevel {
|
||||
Trace,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl LogLevel {
|
||||
fn as_level(self) -> Level {
|
||||
match self {
|
||||
Self::Trace => Level::TRACE,
|
||||
Self::Debug => Level::DEBUG,
|
||||
Self::Info => Level::INFO,
|
||||
Self::Warn => Level::WARN,
|
||||
Self::Error => Level::ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LogLevel {
|
||||
fn default() -> Self {
|
||||
Self::Info
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LogLevel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.to_possible_value().ok_or(fmt::Error)?.get_name())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||
pub enum LogFormat {
|
||||
Short,
|
||||
@@ -96,8 +63,8 @@ pub struct Cli {
|
||||
pub command: Command,
|
||||
|
||||
/// Lowest log message severity to output.
|
||||
#[arg(long, global = true, value_name = "LEVEL", default_value_t)]
|
||||
pub log_level: LogLevel,
|
||||
#[arg(long, global = true, value_name = "LEVEL", default_value_t = Level::INFO)]
|
||||
pub log_level: Level,
|
||||
|
||||
/// Output format for log messages.
|
||||
#[arg(long, global = true, value_name = "FORMAT", default_value_t)]
|
||||
@@ -124,11 +91,11 @@ impl FormatTime for ShortUptime {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_logging(log_level: LogLevel, log_format: LogFormat) {
|
||||
pub fn init_logging(log_level: Level, log_format: LogFormat) {
|
||||
let builder = tracing_subscriber::fmt()
|
||||
.with_writer(io::stderr)
|
||||
.with_ansi(io::stderr().is_terminal())
|
||||
.with_max_level(log_level.as_level());
|
||||
.with_max_level(log_level);
|
||||
|
||||
match log_format {
|
||||
LogFormat::Short => {
|
||||
|
||||
+21
-20
@@ -34,7 +34,7 @@ use crate::{
|
||||
avb::{self, Descriptor, Header},
|
||||
ota::{self, SigningWriter, ZipEntry},
|
||||
padding,
|
||||
payload::{self, PayloadHeader, PayloadWriter},
|
||||
payload::{self, PayloadHeader, PayloadWriter, VabcAlgo},
|
||||
},
|
||||
patch::{
|
||||
boot::{
|
||||
@@ -676,12 +676,11 @@ pub fn compress_image(
|
||||
// Otherwise, compress the entire image. If VABC is enabled, we need to
|
||||
// update the CoW size estimate or else the CoW block device may run out of
|
||||
// space during flashing.
|
||||
let need_cow = partition.estimate_cow_size.is_some();
|
||||
if need_cow {
|
||||
let vabc_algo = if partition.estimate_cow_size.is_some() {
|
||||
info!("Needs updated CoW size estimate: {name}");
|
||||
|
||||
// Only CoW v2 + lz4 seems to exist in the wild currently, so that is
|
||||
// all we support.
|
||||
// Only CoW v2 seems to exist in the wild currently, so that is all we
|
||||
// support.
|
||||
let Some(dpm) = &header.manifest.dynamic_partition_metadata else {
|
||||
bail!("Dynamic partition metadata is missing");
|
||||
};
|
||||
@@ -696,13 +695,17 @@ pub fn compress_image(
|
||||
}
|
||||
|
||||
let compression = dpm.vabc_compression_param();
|
||||
if compression != "lz4" {
|
||||
let Some(vabc_algo) = VabcAlgo::new(compression) else {
|
||||
bail!("Unsupported VABC compression: {compression}");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some(vabc_algo)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (partition_info, operations, cow_estimate) =
|
||||
payload::compress_image(&*file, &writer, name, block_size, need_cow, cancel_signal)?;
|
||||
payload::compress_image(&*file, &writer, name, block_size, vabc_algo, cancel_signal)?;
|
||||
|
||||
partition.new_partition_info = Some(partition_info);
|
||||
partition.operations = operations;
|
||||
@@ -726,15 +729,13 @@ fn patch_ota_payload(
|
||||
cert_ota: &Certificate,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<(String, u64)> {
|
||||
let header = PayloadHeader::from_reader(payload.reopen_boxed()?)
|
||||
let mut header = PayloadHeader::from_reader(payload.reopen_boxed()?)
|
||||
.context("Failed to load OTA payload header")?;
|
||||
if !header.is_full_ota() {
|
||||
bail!("Payload is a delta OTA, not a full OTA");
|
||||
}
|
||||
|
||||
let header = Mutex::new(header);
|
||||
let mut header_locked = header.lock().unwrap();
|
||||
let all_partitions = header_locked
|
||||
let all_partitions = header
|
||||
.manifest
|
||||
.partitions
|
||||
.iter()
|
||||
@@ -752,7 +753,7 @@ fn patch_ota_payload(
|
||||
// Determine what images need to be patched. For simplicity, we pre-read all
|
||||
// vbmeta images since they're tiny. They're discarded later if the they
|
||||
// don't need to be modified.
|
||||
let required_images = RequiredImages::new(&header_locked.manifest);
|
||||
let required_images = RequiredImages::new(&header.manifest);
|
||||
let vbmeta_images = required_images.iter_vbmeta().collect::<HashSet<_>>();
|
||||
|
||||
// The set of source images to be inserted into the new payload, replacing
|
||||
@@ -764,7 +765,7 @@ fn patch_ota_payload(
|
||||
payload,
|
||||
&required_images,
|
||||
external_images,
|
||||
&header_locked,
|
||||
&header,
|
||||
cancel_signal,
|
||||
)?;
|
||||
|
||||
@@ -806,7 +807,7 @@ fn patch_ota_payload(
|
||||
&mut vbmeta_order,
|
||||
clear_vbmeta_flags,
|
||||
key_avb,
|
||||
header_locked.manifest.block_size().into(),
|
||||
header.manifest.block_size().into(),
|
||||
)?;
|
||||
|
||||
// Unmodified vbmeta images no longer need to be kept around either.
|
||||
@@ -818,7 +819,7 @@ fn patch_ota_payload(
|
||||
let modified_operations = compress_image(
|
||||
&name,
|
||||
&mut input_file.file,
|
||||
&mut header_locked,
|
||||
&mut header,
|
||||
// We can only perform the optimization of avoiding
|
||||
// recompression if the image came from the original payload.
|
||||
if name == system_target && !external_images.contains_key(&name) {
|
||||
@@ -836,7 +837,7 @@ fn patch_ota_payload(
|
||||
|
||||
info!("Generating new OTA payload");
|
||||
|
||||
let mut payload_writer = PayloadWriter::new(writer, header_locked.clone(), key_ota.clone())
|
||||
let mut payload_writer = PayloadWriter::new(writer, header.clone(), key_ota.clone())
|
||||
.context("Failed to write payload header")?;
|
||||
let mut orig_payload_reader = payload.reopen_boxed().context("Failed to open payload")?;
|
||||
|
||||
@@ -854,7 +855,7 @@ fn patch_ota_payload(
|
||||
|
||||
let pi = payload_writer.partition_index().unwrap();
|
||||
let oi = payload_writer.operation_index().unwrap();
|
||||
let orig_partition = &header_locked.manifest.partitions[pi];
|
||||
let orig_partition = &header.manifest.partitions[pi];
|
||||
let orig_operation = &orig_partition.operations[oi];
|
||||
let data_offset = orig_operation
|
||||
.data_offset
|
||||
@@ -884,7 +885,7 @@ fn patch_ota_payload(
|
||||
|
||||
// Otherwise, copy from the original payload.
|
||||
let data_offset = data_offset
|
||||
.checked_add(header_locked.blob_offset)
|
||||
.checked_add(header.blob_offset)
|
||||
.ok_or_else(|| anyhow!("data_offset overflow in partition #{pi} operation #{oi}"))?;
|
||||
|
||||
orig_payload_reader
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt,
|
||||
io::{self, Cursor, Read, Seek, SeekFrom, Write},
|
||||
ops::Range,
|
||||
sync::atomic::AtomicBool,
|
||||
@@ -887,19 +888,50 @@ fn compress_chunk(raw_data: &[u8], cancel_signal: &AtomicBool) -> Result<(Vec<u8
|
||||
Ok((data, digest_compressed))
|
||||
}
|
||||
|
||||
fn compress_cow_size(mut raw_data: &[u8], block_size: u32) -> u64 {
|
||||
let mut total = 0;
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub enum VabcAlgo {
|
||||
Lz4,
|
||||
Gzip,
|
||||
}
|
||||
|
||||
while !raw_data.is_empty() {
|
||||
let n = raw_data.len().min(block_size as usize);
|
||||
let compressed = lz4_flex::block::compress(&raw_data[..n]);
|
||||
|
||||
total += compressed.len().min(n) as u64;
|
||||
|
||||
raw_data = &raw_data[n..];
|
||||
impl VabcAlgo {
|
||||
pub fn new(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
"lz4" => Some(Self::Lz4),
|
||||
"gz" => Some(Self::Gzip),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
total
|
||||
fn compressed_size(&self, mut raw_data: &[u8], block_size: u32) -> u64 {
|
||||
let mut total = 0;
|
||||
|
||||
while !raw_data.is_empty() {
|
||||
let n = raw_data.len().min(block_size as usize);
|
||||
let compressed = match self {
|
||||
Self::Lz4 => lz4_flex::block::compress(&raw_data[..n]),
|
||||
// We use the miniz_oxide backend for flate2, but flate2 doesn't
|
||||
// expose a nice function for compressing to a vec, so just use
|
||||
// miniz_oxide directly.
|
||||
Self::Gzip => miniz_oxide::deflate::compress_to_vec_zlib(&raw_data[..n], 9),
|
||||
};
|
||||
|
||||
total += compressed.len().min(n) as u64;
|
||||
|
||||
raw_data = &raw_data[n..];
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VabcAlgo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Lz4 => f.write_str("lz4"),
|
||||
Self::Gzip => f.write_str("gz"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compress the image and return the corresponding information to insert into
|
||||
@@ -910,18 +942,18 @@ fn compress_cow_size(mut raw_data: &[u8], block_size: u32) -> u64 {
|
||||
/// update [`InstallOperation::data_offset`] in each operation manually because
|
||||
/// the initial values are relative to 0.
|
||||
///
|
||||
/// If `need_cow_estimate` is true, the VABC CoW v2 + lz4 size estimate will be
|
||||
/// computed. The caller must update [`PartitionUpdate::estimate_cow_size`] with
|
||||
/// this value or else update_engine may fail to flash the partition due to
|
||||
/// running out of space on the CoW block device. CoW v2 + other algorithms and
|
||||
/// also CoW v3 are currently unsupported because there currently are no known
|
||||
/// OTAs that use those configurations.
|
||||
/// If `vabc_algo` is set, the VABC CoW v2 size estimate will be computed. The
|
||||
/// caller must update [`PartitionUpdate::estimate_cow_size`] with this value or
|
||||
/// else update_engine may fail to flash the partition due to running out of
|
||||
/// space on the CoW block device. CoW v2 + other algorithms and also CoW v3 are
|
||||
/// currently unsupported because there currently are no known OTAs that use
|
||||
/// those configurations.
|
||||
pub fn compress_image(
|
||||
input: &(dyn ReadSeekReopen + Sync),
|
||||
output: &(dyn WriteSeekReopen + Sync),
|
||||
partition_name: &str,
|
||||
block_size: u32,
|
||||
need_cow_estimate: bool,
|
||||
vabc_algo: Option<VabcAlgo>,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<(PartitionInfo, Vec<InstallOperation>, Option<u64>)> {
|
||||
const CHUNK_SIZE: u64 = 2 * 1024 * 1024;
|
||||
@@ -980,8 +1012,8 @@ pub fn compress_image(
|
||||
.map(
|
||||
|(raw_offset, raw_data)| -> Result<(Vec<u8>, InstallOperation, u64)> {
|
||||
let (data, digest_compressed) = compress_chunk(&raw_data, cancel_signal)?;
|
||||
let cow_size = if need_cow_estimate {
|
||||
compress_cow_size(&raw_data, block_size)
|
||||
let cow_size = if let Some(algo) = vabc_algo {
|
||||
algo.compressed_size(&raw_data, block_size)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
@@ -1028,11 +1060,25 @@ pub fn compress_image(
|
||||
hash: Some(digest_uncompressed.as_ref().to_vec()),
|
||||
};
|
||||
|
||||
let cow_estimate = if need_cow_estimate {
|
||||
// Because lz4_flex compresses better than official lz4.
|
||||
let fudge = cow_estimate / 100;
|
||||
let cow_estimate = if vabc_algo.is_some() {
|
||||
// lz4_flex and miniz_oxide usually compress better than the lz4 and
|
||||
// zlib implementations used by libsnapshot_cow. Make up for this by
|
||||
// adding percentage-based overhead.
|
||||
cow_estimate += cow_estimate / 100;
|
||||
|
||||
Some(cow_estimate + fudge)
|
||||
// We also need to account for constant overhead, especially with
|
||||
// smaller partitions. We can match what delta_generator normally adds
|
||||
// in CowWriterV2::InitPos() exactly. Since we only ever create full
|
||||
// OTAs, we can assume that all CoW operations are kCowReplaceOp.
|
||||
|
||||
// sizeof(CowHeader).
|
||||
cow_estimate += 38;
|
||||
// header_.buffer_size (equal to BUFFER_REGION_DEFAULT_SIZE).
|
||||
cow_estimate += 2 * 1024 * 1024;
|
||||
// CowOptions::cluster_ops * sizeof(CowOperationV2).
|
||||
cow_estimate += 200 * 20;
|
||||
|
||||
Some(cow_estimate)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
+20
-8
@@ -12,6 +12,9 @@ security_patch_level = "2024-01-01"
|
||||
# Google Pixel 7 Pro
|
||||
# What's unique: init_boot (boot v4) + vendor_boot (vendor v4)
|
||||
|
||||
[profile.pixel_v4_gki]
|
||||
vabc_algo = "Lz4"
|
||||
|
||||
[profile.pixel_v4_gki.partitions.boot]
|
||||
avb.signed = true
|
||||
data.type = "boot"
|
||||
@@ -46,12 +49,15 @@ data.version = "vendor_v4"
|
||||
data.ramdisks = [["otacerts", "first_stage", "dsu_key_dir"]]
|
||||
|
||||
[profile.pixel_v4_gki.hashes]
|
||||
original = "6b140c378d21eae2fa4fc581bce13a689b21bd32f5fba865698d1fd322f2f8c6"
|
||||
patched = "a68b3a44c0cf015a225f92837c05fd0dec6e159584c5880eff30d12daa7123ff"
|
||||
original = "c00f891f941f3dddb28966f7b07f3acea773bee104dace82b37c2d1341f09422"
|
||||
patched = "ce9d8ee97828d233809742a5d3f23aa27b042675b1935ca9e3df0592c55788fd"
|
||||
|
||||
# Google Pixel 6a
|
||||
# What's unique: boot (boot v4, no ramdisk) + vendor_boot (vendor v4, 2 ramdisks)
|
||||
|
||||
[profile.pixel_v4_non_gki]
|
||||
vabc_algo = "Lz4"
|
||||
|
||||
[profile.pixel_v4_non_gki.partitions.boot]
|
||||
avb.signed = true
|
||||
data.type = "boot"
|
||||
@@ -80,12 +86,15 @@ data.version = "vendor_v4"
|
||||
data.ramdisks = [["init", "otacerts", "first_stage", "dsu_key_dir"], ["dlkm"]]
|
||||
|
||||
[profile.pixel_v4_non_gki.hashes]
|
||||
original = "31963e6f81986c6686111f50e36b89e4d85ee5c02bc8e5ecd560528bc98d6fe7"
|
||||
patched = "a13173a006ad94b25db682bb14fde2e36891417727d6541bdf5f9bca57d26751"
|
||||
original = "4d692bc777b568b0626d3c08d2e6f83f1b472db5ad903486daaec6a78d0cc26e"
|
||||
patched = "e27673e4f30933710c11d51f0e73849068cbe9bc9f54e6076bdd93f9a5c8ea0a"
|
||||
|
||||
# Google Pixel 4a 5G
|
||||
# What's unique: boot (boot v3) + vendor_boot (vendor v3)
|
||||
|
||||
[profile.pixel_v3]
|
||||
vabc_algo = "Lz4"
|
||||
|
||||
[profile.pixel_v3.partitions.boot]
|
||||
avb.signed = true
|
||||
data.type = "boot"
|
||||
@@ -115,12 +124,15 @@ data.version = "vendor_v3"
|
||||
data.ramdisks = [["otacerts", "first_stage", "dsu_key_dir"]]
|
||||
|
||||
[profile.pixel_v3.hashes]
|
||||
original = "e684aacb54464098c1b8e3f499efe35dff10ea792e89d71a83404620d0108b3e"
|
||||
patched = "49e810ae76154bccf2dc7d810b9eec19d23a5b8fa32381469660488d0a25121b"
|
||||
original = "f432dc7931520feb238474aa707dd5299747562ffe6129f3f763b5f11ac473ab"
|
||||
patched = "3850a2e73bd783a1ec4a70c59f37d2374e017c20df7ab4b591182b14d187c18e"
|
||||
|
||||
# Google Pixel 4a
|
||||
# What's unique: boot (boot v2)
|
||||
|
||||
[profile.pixel_v2]
|
||||
vabc_algo = "Gzip"
|
||||
|
||||
[profile.pixel_v2.partitions.boot]
|
||||
avb.signed = false
|
||||
data.type = "boot"
|
||||
@@ -144,5 +156,5 @@ data.type = "vbmeta"
|
||||
data.deps = ["system"]
|
||||
|
||||
[profile.pixel_v2.hashes]
|
||||
original = "ee9568797d9195985f14753b89949d8ebb08c8863a32eceeeec6e8d94661b1cf"
|
||||
patched = "e413f1f87ee5ba53d402edad03b0df8af451b5b0323202a9d32b8327d433d340"
|
||||
original = "1b45235b58054009cc496f6c3ee11d3dc16ed5c388c861761e26a6fce83103a0"
|
||||
patched = "193b2dc70dd465d686f35c7b7f74d2cc1b06a55e48cf5c2e4df0f667e03032fc"
|
||||
|
||||
+4
-3
@@ -5,8 +5,9 @@
|
||||
|
||||
use std::{ffi::OsString, path::PathBuf};
|
||||
|
||||
use avbroot::cli::args::{LogFormat, LogLevel};
|
||||
use avbroot::cli::args::LogFormat;
|
||||
use clap::{Args, Parser, Subcommand, ValueEnum};
|
||||
use tracing::Level;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct ProfileGroup {
|
||||
@@ -69,8 +70,8 @@ pub struct Cli {
|
||||
pub command: Command,
|
||||
|
||||
/// Lowest log message severity to output.
|
||||
#[arg(long, global = true, value_name = "LEVEL", default_value_t)]
|
||||
pub log_level: LogLevel,
|
||||
#[arg(long, global = true, value_name = "LEVEL", default_value_t = Level::INFO)]
|
||||
pub log_level: Level,
|
||||
|
||||
/// Output format for log messages.
|
||||
#[arg(long, global = true, value_name = "FORMAT", default_value_t = LogFormat::Medium)]
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
use std::{collections::BTreeMap, fs, path::Path};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use avbroot::format::payload::VabcAlgo;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use toml_edit::DocumentMut;
|
||||
|
||||
@@ -109,6 +110,7 @@ pub struct Partition {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Profile {
|
||||
pub vabc_algo: Option<VabcAlgo>,
|
||||
pub partitions: BTreeMap<String, Partition>,
|
||||
pub hashes: Hashes,
|
||||
}
|
||||
|
||||
+11
-9
@@ -577,6 +577,7 @@ fn create_payload(
|
||||
partitions: &BTreeMap<String, Partition>,
|
||||
inputs: &BTreeMap<String, PSeekFile>,
|
||||
ota_info: &OtaInfo,
|
||||
profile: &Profile,
|
||||
key_ota: &RsaSigningKey,
|
||||
cancel_signal: &AtomicBool,
|
||||
) -> Result<(String, u64)> {
|
||||
@@ -594,14 +595,14 @@ fn create_payload(
|
||||
.map(PSeekFile::new)
|
||||
.with_context(|| format!("Failed to create temp file for: {name}"))?;
|
||||
|
||||
let (partition_info, operations, cow_estimate) = payload::compress_image(
|
||||
file,
|
||||
&writer,
|
||||
name,
|
||||
4096,
|
||||
dynamic_partitions_names.contains(name),
|
||||
cancel_signal,
|
||||
)?;
|
||||
let vabc_algo = if dynamic_partitions_names.contains(name) {
|
||||
profile.vabc_algo
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (partition_info, operations, cow_estimate) =
|
||||
payload::compress_image(file, &writer, name, 4096, vabc_algo, cancel_signal)?;
|
||||
|
||||
compressed.insert(name, writer);
|
||||
|
||||
@@ -645,7 +646,7 @@ fn create_payload(
|
||||
}],
|
||||
snapshot_enabled: Some(true),
|
||||
vabc_enabled: Some(true),
|
||||
vabc_compression_param: Some("lz4".to_owned()),
|
||||
vabc_compression_param: profile.vabc_algo.map(|a| a.to_string()),
|
||||
cow_version: Some(2),
|
||||
vabc_feature_set: None,
|
||||
}),
|
||||
@@ -746,6 +747,7 @@ fn create_ota(
|
||||
&profile.partitions,
|
||||
&inputs,
|
||||
ota_info,
|
||||
profile,
|
||||
key_ota,
|
||||
cancel_signal,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user