Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit be3eedc

Browse files
committed
feat(avb): generate care_map.pb for hashtree partitions and fix DLKM build.prop handling
This commit adds automatic care_map.pb generation for AVB hashtree-enabled partitions and fixes build.prop handling for DLKM partitions. Changes: - Add _generate_care_map() method to generate care_map.pb during AVB rebuild - Identifies hashtree-enabled partitions from stock AVB profile - Creates care_map.txt with partition extents (4KB block granularity) - Converts to care_map.pb using care_map_generator tool - Includes proper error handling and cleanup - Fix build.prop copy for DLKM partitions (system_dlkm, vendor_dlkm, odm_dlkm, product_dlkm) - Add missing partition mappings - Create parent directories before copying to prevent FileNotFoundError - Integrate care_map generation into AVB rebuild workflow - Called after vbmeta image rebuild to ensure partition images exist
1 parent 3efaad4 commit be3eedc

1 file changed

Lines changed: 92 additions & 1 deletion

File tree

src/core/packer.py

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,7 @@ def pack_ota_payload(self) -> None:
10161016
self._sync_partition_info_from_stock_avb(profile)
10171017
self._apply_avb_to_custom_images(current_partitions)
10181018
self._rebuild_vbmeta_images(current_partitions)
1019+
self._generate_care_map()
10191020

10201021
self._generate_meta_info()
10211022
self._copy_build_props()
@@ -1530,6 +1531,90 @@ def _verify_avb_images(self) -> None:
15301531
self.shell.run(cmd, env=self._avb_env())
15311532
self.logger.info("AVB verification succeeded for vbmeta chain.")
15321533

1534+
def _generate_care_map(self) -> None:
1535+
"""Generate care_map.pb for AVB hashtree-enabled partitions.
1536+
1537+
Identifies partitions with AVB hashtree enabled from the stock AVB profile
1538+
and generates META/care_map.pb using the care_map_generator tool.
1539+
"""
1540+
profile = self._collect_stock_avb_profile()
1541+
if not profile:
1542+
self.logger.info("Skipping care_map generation: stock AVB profile unavailable.")
1543+
return
1544+
1545+
care_map_gen = self.ota_tools_dir / "bin" / "care_map_generator"
1546+
if not care_map_gen.exists():
1547+
self.logger.warning("care_map_generator not found, skipping care_map.pb generation.")
1548+
return
1549+
1550+
# Partitions that should be included in care_map (hashtree-enabled partitions)
1551+
# These are typically the large dynamic partitions with dm-verity
1552+
hashtree_parts = cast(set[str], profile.get("hashtree_parts", set()))
1553+
if not hashtree_parts:
1554+
self.logger.info("No hashtree partitions found, skipping care_map generation.")
1555+
return
1556+
1557+
# Build care_map text content
1558+
# Format:
1559+
# /partition_name
1560+
# extent_start,extent_end
1561+
# Where extents represent the ranges that need to be checked during OTA
1562+
care_map_lines: List[str] = []
1563+
for part in sorted(hashtree_parts):
1564+
image = self.images_out / f"{part}.img"
1565+
if not image.exists():
1566+
self.logger.debug("Skipping %s: image not found", part)
1567+
continue
1568+
1569+
# Add partition entry
1570+
care_map_lines.append(f"/{part}")
1571+
1572+
# Calculate image extents (in 4K blocks for care_map)
1573+
# The care_map format uses block numbers (typically 4KB blocks)
1574+
image_size = image.stat().st_size
1575+
block_size = 4096
1576+
num_blocks = (image_size + block_size - 1) // block_size
1577+
1578+
# Add extent covering the entire image
1579+
# Format: start_block,end_block (exclusive)
1580+
care_map_lines.append(f"0,{num_blocks}")
1581+
1582+
self.logger.debug("Added %s to care_map (%d blocks)", part, num_blocks)
1583+
1584+
if not care_map_lines:
1585+
self.logger.info("No valid partitions for care_map, skipping generation.")
1586+
return
1587+
1588+
# Write intermediate text file
1589+
care_map_txt = self.meta_out / "care_map.txt"
1590+
self.meta_out.mkdir(parents=True, exist_ok=True)
1591+
care_map_txt.write_text("\n".join(care_map_lines) + "\n", encoding="utf-8")
1592+
1593+
# Generate care_map.pb using care_map_generator
1594+
care_map_pb = self.meta_out / "care_map.pb"
1595+
cmd = [
1596+
str(care_map_gen),
1597+
str(care_map_txt),
1598+
str(care_map_pb),
1599+
]
1600+
1601+
try:
1602+
self.shell.run(cmd, env=self._avb_env())
1603+
self.logger.info(
1604+
"Generated care_map.pb with partitions: %s",
1605+
", ".join(sorted(hashtree_parts))
1606+
)
1607+
except subprocess.CalledProcessError as e:
1608+
self.logger.warning("Failed to generate care_map.pb: %s", e)
1609+
# Don't fail the build if care_map generation fails
1610+
# Clean up the text file if pb generation failed
1611+
if care_map_txt.exists():
1612+
care_map_txt.unlink()
1613+
else:
1614+
# Clean up intermediate text file after successful generation
1615+
if care_map_txt.exists():
1616+
care_map_txt.unlink()
1617+
15331618
def _build_avb_misc_lines_from_stock(self, partition_list: List[str]) -> List[str]:
15341619
"""Infer AVB-related misc_info lines from stock images."""
15351620
profile = self._collect_stock_avb_profile()
@@ -1737,11 +1822,17 @@ def _copy_build_props(self) -> None:
17371822
"system_ext": "SYSTEM_EXT",
17381823
"vendor": "VENDOR",
17391824
"odm": "ODM",
1825+
"system_dlkm": "SYSTEM_DLKM",
1826+
"vendor_dlkm": "VENDOR_DLKM",
1827+
"odm_dlkm": "ODM_DLKM",
1828+
"product_dlkm": "PRODUCT_DLKM",
17401829
}
17411830
for part_lower, part_upper in mapping.items():
17421831
src_prop: Optional[Path] = self.ctx.get_target_prop_file(part_lower)
17431832
if src_prop and src_prop.exists():
1744-
shutil.copy2(src_prop, self.product_out / part_upper / "build.prop")
1833+
dest_dir = self.product_out / part_upper
1834+
dest_dir.mkdir(parents=True, exist_ok=True)
1835+
shutil.copy2(src_prop, dest_dir / "build.prop")
17451836
else:
17461837
self.logger.warning(f"build.prop for {part_lower} not found.")
17471838

0 commit comments

Comments
 (0)