BOARD_GROUP_OEM_PARTITION_LIST := system vendor odm product
BOARD_SUPER_PARTITION_$(device)_DEVICE_SIZE
# BOARD_SUPER_PARTITION_GROUPS defines a list of “updatable groups”. Each updatable group is a group of partitions that share the same pool of free spaces. For each group in BOARD_SUPER_PARTITION_GROUPS, a BOARD_{GROUP}SIZE and BOARD{GROUP}_PARTITION_PARTITION_LIST may be defined.
BOARD_{GROUP}_SIZE: The maximum sum of sizes of all partitions in the group. Must not be empty.
BOARD_{GROUP}_PARTITION_PARTITION_LIST: the list of partitions that belongs to this group. If empty, no partitions belong to this group, and the sum of sizes is effectively 0.
Return yes if the given partition is a logical partition, no otherwise
Yes
getvar super-partition-name
MUST return super for a device launching with logical partitions
Yes
create-logical-partition
Create a logical partition with the given name and size
No
delete-logical-partition
Delete the given logical partition
No
resize-logical-partition
Resize the logical partition to the new size without changing its contents
No
update-super
Similar to flash super, except rather than flashing raw data to the super partition, this will ensure that all partitions within the downloaded image are created
No
getvar max-download-size
Return the maximum size of an image that can be downloaded in bytes in hex
Yes
getvar partition-type
Return file system type: ext4, f2fs, raw
Yes
flash [ ]
Flash the partition through a series of download and flash fastboot protocol commands
//metadata信息在super中的配置信息 typedefstructLpMetadataGeometry { /* 0: Magic signature (LP_METADATA_GEOMETRY_MAGIC). */ uint32_t magic; /* 4: Size of the LpMetadataGeometry struct. */ uint32_t struct_size; /* 8: SHA256 checksum of this struct, with this field set to 0. */ uint8_t checksum[32]; /* 40: Maximum amount of space a single copy of the metadata can use. This * must be a multiple of LP_SECTOR_SIZE. */ uint32_t metadata_max_size; /* 44: Number of copies of the metadata to keep. For A/B devices, this * will be 2. For an A/B/C device, it would be 3, et cetera. For Non-A/B * it will be 1. A backup copy of each slot is kept, so if this is "2", * there will be four copies total. */ uint32_t metadata_slot_count; /* 48: Logical block size. This is the minimal alignment for partition and * extent sizes, and it must be a multiple of LP_SECTOR_SIZE. Note that * this must be equal across all LUNs that comprise the super partition, * and thus this field is stored in the geometry, not per-device. */ uint32_t logical_block_size; } __attribute__((packed)) LpMetadataGeometry;
/* The logical partition metadata has a number of tables; they are described * in the header via the following structure */ // LpMetaDataHeader中对partition/extent/group的描述信息, 用来offset偏移找到对应的数据段填充对应的结构体. typedefstructLpMetadataTableDescriptor { /* 0: Location of the table, relative to end of the metadata header. */ uint32_t offset; // entry_size * num_entries = size of the table /* 4: Number of entries in the table. */ uint32_t num_entries; /* 8: Size of each entry in the table, in bytes. */ uint32_t entry_size; } __attribute__((packed)) LpMetadataTableDescriptor;
//metadata位于物理分区的描述头信息 typedefstructLpMetadataHeader { /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */ uint32_t magic;
/* 4: Version number required to read this metadata. If the version is not * equal to the library version, the metadata should be considered * incompatible. */ uint16_t major_version;
/* 6: Minor version. A library supporting newer features should be able to * read metadata with an older minor version. However, an older library * should not support reading metadata if its minor version is higher. */ uint16_t minor_version;
/* 8: The size of this header struct. */ uint32_t header_size;
/* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as * if this field were set to 0. */ uint8_t header_checksum[32];
/* 44: The total size of all tables. This size is contiguous; tables may not * have gaps in between, and they immediately follow the header. */ uint32_t tables_size;
/* 48: SHA256 checksum of all table contents. */ uint8_t tables_checksum[32];
// 各动态分区的描述信息 typedefstructLpMetadataPartition { char name[36]; /* 36: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */ uint32_t attributes; /* 40: Index of the first extent owned by this partition. The extent will * start at logical sector 0. Gaps between extents are not allowed. */ uint32_t first_extent_index; /* 44: Number of extents in the partition. Every partition must have at * least one extent. */ uint32_t num_extents; /* 48: Group this partition belongs to. */ uint32_t group_index; } __attribute__((packed)) LpMetadataPartition;
/* This struct defines an extent entry in the extent table block. */ // 各动态分区的区间块的描述信息 typedefstructLpMetadataExtent { /* 0: Length of this extent, in 512-byte sectors. */ uint64_t num_sectors; /* 8: Target type for device-mapper (see LP_TARGET_TYPE_* values). */ uint32_t target_type;
/* 12: Contents depends on target_type. * * LINEAR: The sector on the physical partition that this extent maps onto. * ZERO: This field must be 0. */ uint64_t target_data;
/* 20: Contents depends on target_type. * * LINEAR: Must be an index into the block devices table. * ZERO: This field must be 0. */ uint32_t target_source; } __attribute__((packed)) LpMetadataExtent;
typedefstructLpMetadataPartitionGroup { /* 0: Name of this group. Any unused characters must be 0. */ char name[36];
/* 36: Flags (see LP_GROUP_*). */ uint32_t flags;
/* 40: Maximum size in bytes. If 0, the group has no maximum size. */ uint64_t maximum_size; } __attribute__((packed)) LpMetadataPartitionGroup;
/* This struct defines an entry in the block_devices table. There must be at * least one device, and the first device must represent the partition holding * the super metadata. */ typedefstructLpMetadataBlockDevice { /* 0: First usable sector for allocating logical partitions. this will be * the first sector after the initial geometry blocks, followed by the * space consumed by metadata_max_size*metadata_slot_count*2. */ uint64_t first_logical_sector;
/* 8: Alignment for defining partitions or partition extents. For example, * an alignment of 1MiB will require that all partitions have a size evenly * divisible by 1MiB, and that the smallest unit the partition can grow by * is 1MiB. * * Alignment is normally determined at runtime when growing or adding * partitions. If for some reason the alignment cannot be determined, then * this predefined alignment in the geometry is used instead. By default * it is set to 1MiB. */ uint32_t alignment;
/* 12: Alignment offset for "stacked" devices. For example, if the "super" * partition itself is not aligned within the parent block device's * partition table, then we adjust for this in deciding where to place * |first_logical_sector|. * * Similar to |alignment|, this will be derived from the operating system. * If it cannot be determined, it is assumed to be 0. */ uint32_t alignment_offset;
/* 16: Block device size, as specified when the metadata was created. This * can be used to verify the geometry against a target device. */ uint64_t size;
/* 24: Partition name in the GPT. Any unused characters must be 0. */ char partition_name[36];
// Read and validate geometry information from a block device that holds // logical partitions. If the information is corrupted, this will attempt // to read it from a secondary backup location. boolReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry){ if (ReadPrimaryGeometry(fd, geometry)) { returntrue; } returnReadBackupGeometry(fd, geometry); } boolReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry){ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE); if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) { returnfalse; } if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) { returnfalse; } returnParseGeometry(buffer.get(), geometry); } memcpy(geometry, buffer, sizeof(*geometry));
// Parse and validate all metadata at the current position in the given file // descriptor. static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geometry, Reader* reader){ // 填充LpMetadataHeader, 包含了metadata的版本等 std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>(); if (!reader->ReadFully(&metadata->header, sizeof(metadata->header))) { returnnullptr; } if (!ValidateMetadataHeader(metadata->header)) { returnnullptr; } // 填充LpMetadataGeometry metadata->geometry = geometry; LpMetadataHeader& header = metadata->header;
// Read the metadata payload. Allocation is fallible in case the metadata is // corrupt and has some huge value. // 读取LpMetadata中LpMetaDataHeader外剩下的数据, 算一个checksum和header中的checksum比对, 必须是一致的 std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[header.tables_size]); if (!reader->ReadFully(buffer.get(), header.tables_size)) { returnnullptr; } uint8_t checksum[32]; SHA256(buffer.get(), header.tables_size, checksum); if (memcmp(checksum, header.tables_checksum, sizeof(checksum)) != 0) { LERROR << "Logical partition metadata has invalid table checksum."; returnnullptr; }
// ValidateTableSize ensured that |cursor| is valid for the number of // entries in the table. // header中记录了partition 表的信息,包含了offset, 有几个分区,每个分区item的大小 uint8_t* cursor = buffer.get() + header.partitions.offset; for (size_t i = 0; i < header.partitions.num_entries; i++) { LpMetadataPartition partition; memcpy(&partition, cursor, sizeof(partition)); // 一共num_entries个partition, 遍历metadata的partition table, cursor记录了每个partition的头 cursor += header.partitions.entry_size;
cursor = buffer.get() + header.extents.offset; for (size_t i = 0; i < header.extents.num_entries; i++) { LpMetadataExtent extent; memcpy(&extent, cursor, sizeof(extent)); cursor += header.extents.entry_size;
if (extent.target_type == LP_TARGET_TYPE_LINEAR && extent.target_source >= header.block_devices.num_entries) { LERROR << "Logical partition extent has invalid block device."; returnnullptr; }
metadata->extents.push_back(extent); }
cursor = buffer.get() + header.groups.offset; for (size_t i = 0; i < header.groups.num_entries; i++) { LpMetadataPartitionGroup group = {}; memcpy(&group, cursor, sizeof(group)); cursor += header.groups.entry_size;
metadata->groups.push_back(group); }
cursor = buffer.get() + header.block_devices.offset; for (size_t i = 0; i < header.block_devices.num_entries; i++) { LpMetadataBlockDevice device = {}; memcpy(&device, cursor, sizeof(device)); cursor += header.block_devices.entry_size;
metadata->block_devices.push_back(device); }
const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(*metadata.get()); if (!super_device) { LERROR << "Metadata does not specify a super device."; returnnullptr; } return metadata; }
if (!force_check && new_size <= old_size) { returntrue; }
// Figure out how much we need to allocate, and whether our group has // enough space remaining. uint64_t space_needed = new_size - old_size; if (group->maximum_size() > 0) { // 分区组的已用空间 uint64_t group_size = TotalSizeOfGroup(group); if (group_size >= group->maximum_size() || // 分区组的最大空间 group->maximum_size() - group_size < space_needed) { LERROR << "Partition " << partition->name() << " is part of group " << group->name() << " which does not have enough space free (" << space_needed << " requested, " << group_size << " used out of " << group->maximum_size() << ")"; returnfalse; } } returntrue; }
boolMetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size){ uint64_t space_needed = aligned_size - partition->size(); uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE; // 根据已有的extent, 做相邻extent的gap, gap有效即为free的 //The new interval represents the free space starting at the end of //the previous interval, and ending at the start of the next interval. // free_regions->emplace_back(current.device_index, aligned, current.start); std::vector<Interval> free_regions = GetFreeRegions();
// If the last extent in the partition has a size < alignment, then the // difference is unallocatable due to being misaligned. We peek for that // case here to avoid wasting space. if (auto extent = ExtendFinalExtent(partition, free_regions, sectors_needed)) { sectors_needed -= extent->num_sectors(); new_extents.emplace_back(std::move(extent)); } // 从free_regions中查找可以空闲的extent, 给当前正在调整大小的partition使用 for (auto& region : free_regions) { // 分配够了就退出 if (!sectors_needed) { break; } ... uint64_t sectors = std::min(sectors_needed, region.length()); auto extent = std::make_unique<LinearExtent>(sectors, region.device_index, region.start); new_extents.push_back(std::move(extent)); sectors_needed -= sectors; } // Everything succeeded, so commit the new extents. // 将新的extent加到partition对应的extents中 for (auto& extent : new_extents) { partition->AddExtent(std::move(extent)); } returntrue; }
// Assign this early so the extent table can read it. for (constauto& block_device : block_devices_) { metadata->block_devices.emplace_back(block_device); if (auto_slot_suffixing_) { metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED; } }
std::map<std::string, size_t> group_indices; for (constauto& group : groups_) { LpMetadataPartitionGroup out = {}; strncpy(out.name, group->name().c_str(), sizeof(out.name)); out.maximum_size = group->maximum_size();
// Flatten the partition and extent structures into an LpMetadata, which // makes it very easy to validate, serialize, or pass on to device-mapper. for (constauto& partition : partitions_) { LpMetadataPartition part; memset(&part, 0, sizeof(part)); ... strncpy(part.name, partition->name().c_str(), sizeof(part.name)); part.first_extent_index = static_cast<uint32_t>(metadata->extents.size()); part.num_extents = static_cast<uint32_t>(partition->extents().size()); part.attributes = partition->attributes(); if (auto_slot_suffixing_) { part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED; }
auto iter = group_indices.find(partition->group_name()); part.group_index = iter->second;
for (constauto& extent : partition->extents()) { // 保存到metadata的extents字段中 if (!extent->AddTo(metadata.get())) { returnnullptr; } } metadata->partitions.push_back(part); }
/dev/block/by-name/dm-0 (system): dm-linear super <block range 1> /dev/block/by-name/dm-1 (vendor): dm-linear super <block range 2>
1 2 3 4 5 6
/dev/block/by-name/dm-0 (system): dm-linear super <block range 1> dm-linear super <block range 3> /dev/block/by-name/dm-1 (vendor): dm-linear super <block range 2> dm-linear super <block range 4>
structdm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]); InitIo(io, name); io->data_size = ioctl_buffer.size(); io->data_start = sizeof(struct dm_ioctl); io->target_count = static_cast<uint32_t>(table.num_targets()); if (table.readonly()) { io->flags |= DM_READONLY_FLAG; } //Load a table into the 'inactive' slot for the device if (ioctl(fd_, DM_TABLE_LOAD, io)) { returnfalse; }
InitIo(io, name); // 设备处于就绪状态或resume状态, 根据上面传入的io的flag决定. 没有带DM_SUSPEND_FLAG的flag, 是走resume状态 /*If a table is present in the 'inactive' * slot, it will be moved to the active slot, then the old table from the active slot will be _destroyed_. Finally the device is resumed. */ if (ioctl(fd_, DM_DEV_SUSPEND, io)) { returnfalse; } } // 通过ioctl获取dm设备的状态 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) { returnfalse; } uint32_t dev_num = minor(io.dev); //dm-<minor> 设备对应io->name(target_device)绑定的mapped_device *path = "/dev/block/dm-" + std::to_string(dev_num); } // ---> 3. 等待mapped_device dm-<minior>创建完成, 超时销毁
// ==========> 2.1 调用映射表的序列化函数将前面的target_序列化输出到ioctl_buffer中 ioctl_buffer += table.Serialize(); std::string DmTable::Serialize()const{ std::string table; for (constauto& target : targets_) { table += target->Serialize(); } return table; } std::string DmTarget::Serialize()const{ // Create a string containing a dm_target_spec, parameter data, and an // explicit null terminator. std::string data(sizeof(dm_target_spec), '\0'); //构造头部, block_device_ + " " + std::to_string(physical_sector_); // target_data data += GetParameterString(); data.push_back('\0');
// The kernel expects each target to be 8-byte aligned. size_t padding = DM_ALIGN(data.size()) - data.size(); for (size_t i = 0; i < padding; i++) { data.push_back('\0'); }
structdm_target_spec { __u64 sector_start; __u64 length; __s32 status; /* used when reading from kernel only */
/* * Location of the next dm_target_spec. * - When specifying targets on a DM_TABLE_LOAD command, this value is * the number of bytes from the start of the "current" dm_target_spec * to the start of the "next" dm_target_spec. * - When retrieving targets on a DM_TABLE_STATUS command, this value * is the number of bytes from the start of the first dm_target_spec * (that follows the dm_ioctl struct) to the start of the "next" * dm_target_spec. */ __u32 next;