Closed chenxiaolong closed 3 months ago
avbroot does not update PartitionUpdate.estimate_cow_size
. It seems like update_engine uses this estimate and adds a bit of buffer to form the hard limit.
From update_engine logs:
2024-06-21 18:29:59.819830 -0400 E/update_engine( 1217): [ERROR:writer_v2.cpp(601)] No space left on COW device. Required: 837438955, available: 837435392
From payload.bin
's header entry for the system
partition:
estimate_cow_size: Some(
835335997,
),
Yep, that's exactly what it is: https://android.googlesource.com/platform/system/core/+/refs/tags/android-14.0.0_r51/fs_mgr/libsnapshot/partition_cow_creator.cpp#165
Just need to figure out how AOSP computes this value when generating payload.bin
now.
OK, so there's CoW version 2 and 3 in AOSP.
The v2 algorithm is:
estimate = 0
for each block in partition:
allocate buffer of size `LZ4_compressBound()`
compress block with default settings (`LZ4_compress_default()`)
if compressed size < uncompressed size:
estimate += compressed size
else:
estimate += uncompressed size
The v3 algorithm is more complicated and I didn't bother figuring it out. Every OTA I've seen uses v2 + lz4, including the Android 15 betas. We can revisit this later if that changes.
This should be easy enough to implement. It can be snuck into avbroot::format::payload::compress_image()
. We already parallelize other compression operations there based on a multiple of the block size.
The only caveat is that avbroot uses the Rust lz4_flex library, which is a complete reimplementation of lz4, while AOSP's libsnapshot_cow uses the original lz4. The compression ratios should be very close though, so hopefully that won't matter.
The performance impact on the patching process seems to be pretty negligible.
Non-scientific test (husky_beta-ota-ap31.240517.022-8f9fd0f3.zip
with --replace system system.img
on an Intel i9-9900KS):
The only caveat is that avbroot uses the Rust lz4_flex library, which is a complete reimplementation of lz4, while AOSP's libsnapshot_cow uses the original lz4. The compression ratios should be very close though, so hopefully that won't matter.
Time to eat my words. lz4_flex compresses system.img
better than lz4. I guess I'll have avbroot fudge the numbers by 1% to account for that. This will only waste a few megabytes of space during OTA flashing. That'll get returned to the user after rebooting and the CoW snapshots have been merged. And on Pixels, it shouldn't waste any space. The super
partition is a huge 8 GiB, so the CoW snapshots should never spill over into the userdata
partition.
On my Pixel 8 Pro, when modifying
system.img
in a way that causes the size to increase (1282695168 -> 1286025216 bytes = approx +3.2 MiB), update_engine fails to flash the partition.I don't think the
No space left on COW device
is an actual disk space issue. ~These system images are way smaller than the stock OS system images.~ (EDIT: Not true. GrapheneOS'system.img
is actually larger.) There might be apayload.bin
manifest field that avbroot is failing to update.