1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "liblp/builder.h"
18
19 #include <string.h>
20
21 #include <algorithm>
22
23 #include <android-base/unique_fd.h>
24
25 #include "liblp/liblp.h"
26 #include "liblp/property_fetcher.h"
27 #include "reader.h"
28 #include "utility.h"
29
30 namespace android {
31 namespace fs_mgr {
32
AddTo(LpMetadata * out) const33 bool LinearExtent::AddTo(LpMetadata* out) const {
34 if (device_index_ >= out->block_devices.size()) {
35 LERROR << "Extent references unknown block device.";
36 return false;
37 }
38 out->extents.emplace_back(
39 LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_, device_index_});
40 return true;
41 }
42
OverlapsWith(const LinearExtent & other) const43 bool LinearExtent::OverlapsWith(const LinearExtent& other) const {
44 if (device_index_ != other.device_index()) {
45 return false;
46 }
47 return physical_sector() < other.end_sector() && other.physical_sector() < end_sector();
48 }
49
OverlapsWith(const Interval & interval) const50 bool LinearExtent::OverlapsWith(const Interval& interval) const {
51 if (device_index_ != interval.device_index) {
52 return false;
53 }
54 return physical_sector() < interval.end && interval.start < end_sector();
55 }
56
AsInterval() const57 Interval LinearExtent::AsInterval() const {
58 return Interval(device_index(), physical_sector(), end_sector());
59 }
60
AddTo(LpMetadata * out) const61 bool ZeroExtent::AddTo(LpMetadata* out) const {
62 out->extents.emplace_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0, 0});
63 return true;
64 }
65
Partition(std::string_view name,std::string_view group_name,uint32_t attributes)66 Partition::Partition(std::string_view name, std::string_view group_name, uint32_t attributes)
67 : name_(name), group_name_(group_name), attributes_(attributes), size_(0) {}
68
AddExtent(std::unique_ptr<Extent> && extent)69 void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
70 size_ += extent->num_sectors() * LP_SECTOR_SIZE;
71
72 if (LinearExtent* new_extent = extent->AsLinearExtent()) {
73 if (!extents_.empty() && extents_.back()->AsLinearExtent()) {
74 LinearExtent* prev_extent = extents_.back()->AsLinearExtent();
75 if (prev_extent->end_sector() == new_extent->physical_sector() &&
76 prev_extent->device_index() == new_extent->device_index()) {
77 // If the previous extent can be merged into this new one, do so
78 // to avoid creating unnecessary extents.
79 extent = std::make_unique<LinearExtent>(
80 prev_extent->num_sectors() + new_extent->num_sectors(),
81 prev_extent->device_index(), prev_extent->physical_sector());
82 extents_.pop_back();
83 }
84 }
85 }
86 extents_.push_back(std::move(extent));
87 }
88
RemoveExtents()89 void Partition::RemoveExtents() {
90 size_ = 0;
91 extents_.clear();
92 }
93
ShrinkTo(uint64_t aligned_size)94 void Partition::ShrinkTo(uint64_t aligned_size) {
95 if (aligned_size == 0) {
96 RemoveExtents();
97 return;
98 }
99
100 // Remove or shrink extents of any kind until the total partition size is
101 // equal to the requested size.
102 uint64_t sectors_to_remove = (size_ - aligned_size) / LP_SECTOR_SIZE;
103 while (sectors_to_remove) {
104 Extent* extent = extents_.back().get();
105 if (extent->num_sectors() > sectors_to_remove) {
106 size_ -= sectors_to_remove * LP_SECTOR_SIZE;
107 extent->set_num_sectors(extent->num_sectors() - sectors_to_remove);
108 break;
109 }
110 size_ -= (extent->num_sectors() * LP_SECTOR_SIZE);
111 sectors_to_remove -= extent->num_sectors();
112 extents_.pop_back();
113 }
114 DCHECK(size_ == aligned_size);
115 }
116
GetBeginningExtents(uint64_t aligned_size) const117 Partition Partition::GetBeginningExtents(uint64_t aligned_size) const {
118 Partition p(name_, group_name_, attributes_);
119 for (const auto& extent : extents_) {
120 auto le = extent->AsLinearExtent();
121 if (le) {
122 p.AddExtent(std::make_unique<LinearExtent>(*le));
123 } else {
124 p.AddExtent(std::make_unique<ZeroExtent>(extent->num_sectors()));
125 }
126 }
127 p.ShrinkTo(aligned_size);
128 return p;
129 }
130
BytesOnDisk() const131 uint64_t Partition::BytesOnDisk() const {
132 uint64_t sectors = 0;
133 for (const auto& extent : extents_) {
134 if (!extent->AsLinearExtent()) {
135 continue;
136 }
137 sectors += extent->num_sectors();
138 }
139 return sectors * LP_SECTOR_SIZE;
140 }
141
New(const IPartitionOpener & opener,const std::string & super_partition,uint32_t slot_number)142 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& opener,
143 const std::string& super_partition,
144 uint32_t slot_number) {
145 std::unique_ptr<LpMetadata> metadata = ReadMetadata(opener, super_partition, slot_number);
146 if (!metadata) {
147 return nullptr;
148 }
149 return New(*metadata.get(), &opener);
150 }
151
New(const std::string & super_partition,uint32_t slot_number)152 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
153 uint32_t slot_number) {
154 return New(PartitionOpener(), super_partition, slot_number);
155 }
156
New(const std::vector<BlockDeviceInfo> & block_devices,const std::string & super_partition,uint32_t metadata_max_size,uint32_t metadata_slot_count)157 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(
158 const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition,
159 uint32_t metadata_max_size, uint32_t metadata_slot_count) {
160 std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
161 if (!builder->Init(block_devices, super_partition, metadata_max_size, metadata_slot_count)) {
162 return nullptr;
163 }
164 return builder;
165 }
166
New(const LpMetadata & metadata,const IPartitionOpener * opener)167 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata,
168 const IPartitionOpener* opener) {
169 std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
170 if (!builder->Init(metadata)) {
171 return nullptr;
172 }
173 if (opener) {
174 for (size_t i = 0; i < builder->block_devices_.size(); i++) {
175 std::string partition_name = builder->GetBlockDevicePartitionName(i);
176 BlockDeviceInfo device_info;
177 if (opener->GetInfo(partition_name, &device_info)) {
178 builder->UpdateBlockDeviceInfo(i, device_info);
179 }
180 }
181 }
182 return builder;
183 }
184
NewForUpdate(const IPartitionOpener & opener,const std::string & source_partition,uint32_t source_slot_number,uint32_t target_slot_number,bool always_keep_source_slot)185 std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener,
186 const std::string& source_partition,
187 uint32_t source_slot_number,
188 uint32_t target_slot_number,
189 bool always_keep_source_slot) {
190 auto metadata = ReadMetadata(opener, source_partition, source_slot_number);
191 if (!metadata) {
192 return nullptr;
193 }
194
195 // On retrofit DAP devices, modify the metadata so that it is suitable for being written
196 // to the target slot later. We detect retrofit DAP devices by checking the super partition
197 // name and system properties.
198 // See comments for UpdateMetadataForOtherSuper.
199 auto super_device = GetMetadataSuperBlockDevice(*metadata.get());
200 if (android::fs_mgr::GetBlockDevicePartitionName(*super_device) != "super" &&
201 IsRetrofitDynamicPartitionsDevice()) {
202 if (!UpdateMetadataForOtherSuper(metadata.get(), source_slot_number, target_slot_number)) {
203 return nullptr;
204 }
205 }
206
207 if (IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false)) {
208 if (always_keep_source_slot) {
209 // always_keep_source_slot implies the target build does not support snapshots.
210 // Clear unsupported attributes.
211 SetMetadataHeaderV0(metadata.get());
212 } else {
213 // !always_keep_source_slot implies the target build supports snapshots. Do snapshot
214 // updates.
215 if (!UpdateMetadataForInPlaceSnapshot(metadata.get(), source_slot_number,
216 target_slot_number)) {
217 return nullptr;
218 }
219 }
220 }
221
222 return New(*metadata.get(), &opener);
223 }
224
225 // For retrofit DAP devices, there are (conceptually) two super partitions. We'll need to translate
226 // block device and group names to update their slot suffixes.
227 // (On the other hand, On non-retrofit DAP devices there is only one location for metadata: the
228 // super partition. update_engine will remove and resize partitions as needed.)
UpdateMetadataForOtherSuper(LpMetadata * metadata,uint32_t source_slot_number,uint32_t target_slot_number)229 bool MetadataBuilder::UpdateMetadataForOtherSuper(LpMetadata* metadata, uint32_t source_slot_number,
230 uint32_t target_slot_number) {
231 // Clear partitions and extents, since they have no meaning on the target
232 // slot. We also clear groups since they are re-added during OTA.
233 metadata->partitions.clear();
234 metadata->extents.clear();
235 metadata->groups.clear();
236
237 std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number);
238 std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number);
239
240 // Translate block devices.
241 auto source_block_devices = std::move(metadata->block_devices);
242 for (const auto& source_block_device : source_block_devices) {
243 std::string partition_name =
244 android::fs_mgr::GetBlockDevicePartitionName(source_block_device);
245 std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
246 if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
247 // This should never happen. It means that the source metadata
248 // refers to a target or unknown block device.
249 LERROR << "Invalid block device for slot " << source_slot_suffix << ": "
250 << partition_name;
251 return false;
252 }
253 std::string new_name =
254 partition_name.substr(0, partition_name.size() - slot_suffix.size()) +
255 target_slot_suffix;
256
257 auto new_device = source_block_device;
258 if (!UpdateBlockDevicePartitionName(&new_device, new_name)) {
259 LERROR << "Partition name too long: " << new_name;
260 return false;
261 }
262 metadata->block_devices.emplace_back(new_device);
263 }
264
265 return true;
266 }
267
MetadataBuilder()268 MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
269 memset(&geometry_, 0, sizeof(geometry_));
270 geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
271 geometry_.struct_size = sizeof(geometry_);
272
273 memset(&header_, 0, sizeof(header_));
274 header_.magic = LP_METADATA_HEADER_MAGIC;
275 header_.major_version = LP_METADATA_MAJOR_VERSION;
276 header_.minor_version = LP_METADATA_MINOR_VERSION_MIN;
277 header_.header_size = sizeof(LpMetadataHeaderV1_0);
278 header_.partitions.entry_size = sizeof(LpMetadataPartition);
279 header_.extents.entry_size = sizeof(LpMetadataExtent);
280 header_.groups.entry_size = sizeof(LpMetadataPartitionGroup);
281 header_.block_devices.entry_size = sizeof(LpMetadataBlockDevice);
282 }
283
Init(const LpMetadata & metadata)284 bool MetadataBuilder::Init(const LpMetadata& metadata) {
285 geometry_ = metadata.geometry;
286 block_devices_ = metadata.block_devices;
287
288 // Bump the version as necessary to copy any newer fields.
289 if (metadata.header.minor_version >= LP_METADATA_VERSION_FOR_EXPANDED_HEADER) {
290 RequireExpandedMetadataHeader();
291 header_.flags = metadata.header.flags;
292 }
293
294 for (const auto& group : metadata.groups) {
295 std::string group_name = GetPartitionGroupName(group);
296 if (!AddGroup(group_name, group.maximum_size)) {
297 return false;
298 }
299 }
300
301 for (const auto& partition : metadata.partitions) {
302 std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]);
303 Partition* builder =
304 AddPartition(GetPartitionName(partition), group_name, partition.attributes);
305 if (!builder) {
306 return false;
307 }
308 ImportExtents(builder, metadata, partition);
309 }
310 return true;
311 }
312
ImportExtents(Partition * dest,const LpMetadata & metadata,const LpMetadataPartition & source)313 void MetadataBuilder::ImportExtents(Partition* dest, const LpMetadata& metadata,
314 const LpMetadataPartition& source) {
315 for (size_t i = 0; i < source.num_extents; i++) {
316 const LpMetadataExtent& extent = metadata.extents[source.first_extent_index + i];
317 if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
318 auto copy = std::make_unique<LinearExtent>(extent.num_sectors, extent.target_source,
319 extent.target_data);
320 dest->AddExtent(std::move(copy));
321 } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
322 auto copy = std::make_unique<ZeroExtent>(extent.num_sectors);
323 dest->AddExtent(std::move(copy));
324 }
325 }
326 }
327
VerifyDeviceProperties(const BlockDeviceInfo & device_info)328 static bool VerifyDeviceProperties(const BlockDeviceInfo& device_info) {
329 if (device_info.logical_block_size == 0) {
330 LERROR << "Block device " << device_info.partition_name
331 << " logical block size must not be zero.";
332 return false;
333 }
334 if (device_info.logical_block_size % LP_SECTOR_SIZE != 0) {
335 LERROR << "Block device " << device_info.partition_name
336 << " logical block size must be a multiple of 512.";
337 return false;
338 }
339 if (device_info.size % device_info.logical_block_size != 0) {
340 LERROR << "Block device " << device_info.partition_name
341 << " size must be a multiple of its block size.";
342 return false;
343 }
344 if (device_info.alignment_offset % LP_SECTOR_SIZE != 0) {
345 LERROR << "Block device " << device_info.partition_name
346 << " alignment offset is not sector-aligned.";
347 return false;
348 }
349 if (device_info.alignment % LP_SECTOR_SIZE != 0) {
350 LERROR << "Block device " << device_info.partition_name
351 << " partition alignment is not sector-aligned.";
352 return false;
353 }
354 if (device_info.alignment_offset > device_info.alignment) {
355 LERROR << "Block device " << device_info.partition_name
356 << " partition alignment offset is greater than its alignment.";
357 return false;
358 }
359 return true;
360 }
361
Init(const std::vector<BlockDeviceInfo> & block_devices,const std::string & super_partition,uint32_t metadata_max_size,uint32_t metadata_slot_count)362 bool MetadataBuilder::Init(const std::vector<BlockDeviceInfo>& block_devices,
363 const std::string& super_partition, uint32_t metadata_max_size,
364 uint32_t metadata_slot_count) {
365 if (metadata_max_size < sizeof(LpMetadataHeader)) {
366 LERROR << "Invalid metadata maximum size.";
367 return false;
368 }
369 if (metadata_slot_count == 0) {
370 LERROR << "Invalid metadata slot count.";
371 return false;
372 }
373 if (block_devices.empty()) {
374 LERROR << "No block devices were specified.";
375 return false;
376 }
377
378 // Align the metadata size up to the nearest sector.
379 metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
380
381 // Validate and build the block device list.
382 uint32_t logical_block_size = 0;
383 for (const auto& device_info : block_devices) {
384 if (!VerifyDeviceProperties(device_info)) {
385 return false;
386 }
387
388 if (!logical_block_size) {
389 logical_block_size = device_info.logical_block_size;
390 }
391 if (logical_block_size != device_info.logical_block_size) {
392 LERROR << "All partitions must have the same logical block size.";
393 return false;
394 }
395
396 LpMetadataBlockDevice out = {};
397 out.alignment = device_info.alignment;
398 out.alignment_offset = device_info.alignment_offset;
399 out.size = device_info.size;
400 if (device_info.partition_name.size() > sizeof(out.partition_name)) {
401 LERROR << "Partition name " << device_info.partition_name << " exceeds maximum length.";
402 return false;
403 }
404 strncpy(out.partition_name, device_info.partition_name.c_str(), sizeof(out.partition_name));
405
406 // In the case of the super partition, this field will be adjusted
407 // later. For all partitions, the first 512 bytes are considered
408 // untouched to be compatible code that looks for an MBR. Thus we
409 // start counting free sectors at sector 1, not 0.
410 uint64_t free_area_start = LP_SECTOR_SIZE;
411 if (out.alignment || out.alignment_offset) {
412 free_area_start = AlignTo(free_area_start, out.alignment, out.alignment_offset);
413 } else {
414 free_area_start = AlignTo(free_area_start, logical_block_size);
415 }
416 out.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
417
418 // There must be one logical block of space available.
419 uint64_t minimum_size = out.first_logical_sector * LP_SECTOR_SIZE + logical_block_size;
420 if (device_info.size < minimum_size) {
421 LERROR << "Block device " << device_info.partition_name
422 << " is too small to hold any logical partitions.";
423 return false;
424 }
425
426 // The "root" of the super partition is always listed first.
427 if (device_info.partition_name == super_partition) {
428 block_devices_.emplace(block_devices_.begin(), out);
429 } else {
430 block_devices_.emplace_back(out);
431 }
432 }
433 if (GetBlockDevicePartitionName(0) != super_partition) {
434 LERROR << "No super partition was specified.";
435 return false;
436 }
437
438 LpMetadataBlockDevice& super = block_devices_[0];
439
440 // We reserve a geometry block (4KB) plus space for each copy of the
441 // maximum size of a metadata blob. Then, we double that space since
442 // we store a backup copy of everything.
443 uint64_t total_reserved = GetTotalMetadataSize(metadata_max_size, metadata_slot_count);
444 if (super.size < total_reserved) {
445 LERROR << "Attempting to create metadata on a block device that is too small.";
446 return false;
447 }
448
449 // Compute the first free sector, factoring in alignment.
450 uint64_t free_area_start = total_reserved;
451 if (super.alignment || super.alignment_offset) {
452 free_area_start = AlignTo(free_area_start, super.alignment, super.alignment_offset);
453 } else {
454 free_area_start = AlignTo(free_area_start, logical_block_size);
455 }
456 super.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
457
458 // There must be one logical block of free space remaining (enough for one partition).
459 uint64_t minimum_disk_size = (super.first_logical_sector * LP_SECTOR_SIZE) + logical_block_size;
460 if (super.size < minimum_disk_size) {
461 LERROR << "Device must be at least " << minimum_disk_size << " bytes, only has "
462 << super.size;
463 return false;
464 }
465
466 geometry_.metadata_max_size = metadata_max_size;
467 geometry_.metadata_slot_count = metadata_slot_count;
468 geometry_.logical_block_size = logical_block_size;
469
470 if (!AddGroup(std::string(kDefaultGroup), 0)) {
471 return false;
472 }
473 return true;
474 }
475
AddGroup(std::string_view group_name,uint64_t maximum_size)476 bool MetadataBuilder::AddGroup(std::string_view group_name, uint64_t maximum_size) {
477 if (FindGroup(group_name)) {
478 LERROR << "Group already exists: " << group_name;
479 return false;
480 }
481 groups_.push_back(std::make_unique<PartitionGroup>(group_name, maximum_size));
482 return true;
483 }
484
AddPartition(const std::string & name,uint32_t attributes)485 Partition* MetadataBuilder::AddPartition(const std::string& name, uint32_t attributes) {
486 return AddPartition(name, kDefaultGroup, attributes);
487 }
488
AddPartition(std::string_view name,std::string_view group_name,uint32_t attributes)489 Partition* MetadataBuilder::AddPartition(std::string_view name, std::string_view group_name,
490 uint32_t attributes) {
491 if (name.empty()) {
492 LERROR << "Partition must have a non-empty name.";
493 return nullptr;
494 }
495 if (FindPartition(name)) {
496 LERROR << "Attempting to create duplication partition with name: " << name;
497 return nullptr;
498 }
499 if (!FindGroup(group_name)) {
500 LERROR << "Could not find partition group: " << group_name;
501 return nullptr;
502 }
503 partitions_.push_back(std::make_unique<Partition>(name, group_name, attributes));
504 return partitions_.back().get();
505 }
506
FindPartition(std::string_view name)507 Partition* MetadataBuilder::FindPartition(std::string_view name) {
508 for (const auto& partition : partitions_) {
509 if (partition->name() == name) {
510 return partition.get();
511 }
512 }
513 return nullptr;
514 }
515
FindGroup(std::string_view group_name)516 PartitionGroup* MetadataBuilder::FindGroup(std::string_view group_name) {
517 for (const auto& group : groups_) {
518 if (group->name() == group_name) {
519 return group.get();
520 }
521 }
522 return nullptr;
523 }
524
TotalSizeOfGroup(PartitionGroup * group) const525 uint64_t MetadataBuilder::TotalSizeOfGroup(PartitionGroup* group) const {
526 uint64_t total = 0;
527 for (const auto& partition : partitions_) {
528 if (partition->group_name() != group->name()) {
529 continue;
530 }
531 total += partition->BytesOnDisk();
532 }
533 return total;
534 }
535
RemovePartition(std::string_view name)536 void MetadataBuilder::RemovePartition(std::string_view name) {
537 for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) {
538 if ((*iter)->name() == name) {
539 partitions_.erase(iter);
540 return;
541 }
542 }
543 }
544
ExtentsToFreeList(const std::vector<Interval> & extents,std::vector<Interval> * free_regions) const545 void MetadataBuilder::ExtentsToFreeList(const std::vector<Interval>& extents,
546 std::vector<Interval>* free_regions) const {
547 // Convert the extent list into a list of gaps between the extents; i.e.,
548 // the list of ranges that are free on the disk.
549 for (size_t i = 1; i < extents.size(); i++) {
550 const Interval& previous = extents[i - 1];
551 const Interval& current = extents[i];
552 DCHECK(previous.device_index == current.device_index);
553
554 uint64_t aligned = AlignSector(block_devices_[current.device_index], previous.end);
555 if (aligned >= current.start) {
556 // There is no gap between these two extents, try the next one.
557 // Note that we check with >= instead of >, since alignment may
558 // bump the ending sector past the beginning of the next extent.
559 continue;
560 }
561
562 // The new interval represents the free space starting at the end of
563 // the previous interval, and ending at the start of the next interval.
564 free_regions->emplace_back(current.device_index, aligned, current.start);
565 }
566 }
567
GetFreeRegions() const568 auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> {
569 std::vector<Interval> free_regions;
570
571 // Collect all extents in the partition table, per-device, then sort them
572 // by starting sector.
573 std::vector<std::vector<Interval>> device_extents(block_devices_.size());
574 for (const auto& partition : partitions_) {
575 for (const auto& extent : partition->extents()) {
576 LinearExtent* linear = extent->AsLinearExtent();
577 if (!linear) {
578 continue;
579 }
580 CHECK(linear->device_index() < device_extents.size());
581 auto& extents = device_extents[linear->device_index()];
582 extents.emplace_back(linear->device_index(), linear->physical_sector(),
583 linear->physical_sector() + extent->num_sectors());
584 }
585 }
586
587 // Add 0-length intervals for the first and last sectors. This will cause
588 // ExtentToFreeList() to treat the space in between as available.
589 for (size_t i = 0; i < device_extents.size(); i++) {
590 auto& extents = device_extents[i];
591 const auto& block_device = block_devices_[i];
592
593 uint64_t first_sector = block_device.first_logical_sector;
594 uint64_t last_sector = block_device.size / LP_SECTOR_SIZE;
595 extents.emplace_back(i, first_sector, first_sector);
596 extents.emplace_back(i, last_sector, last_sector);
597
598 std::sort(extents.begin(), extents.end());
599 ExtentsToFreeList(extents, &free_regions);
600 }
601 return free_regions;
602 }
603
ValidatePartitionSizeChange(Partition * partition,uint64_t old_size,uint64_t new_size,bool force_check)604 bool MetadataBuilder::ValidatePartitionSizeChange(Partition* partition, uint64_t old_size,
605 uint64_t new_size, bool force_check) {
606 PartitionGroup* group = FindGroup(partition->group_name());
607 CHECK(group);
608
609 if (!force_check && new_size <= old_size) {
610 return true;
611 }
612
613 // Figure out how much we need to allocate, and whether our group has
614 // enough space remaining.
615 uint64_t space_needed = new_size - old_size;
616 if (group->maximum_size() > 0) {
617 uint64_t group_size = TotalSizeOfGroup(group);
618 if (group_size >= group->maximum_size() ||
619 group->maximum_size() - group_size < space_needed) {
620 LERROR << "Partition " << partition->name() << " is part of group " << group->name()
621 << " which does not have enough space free (" << space_needed << " requested, "
622 << group_size << " used out of " << group->maximum_size() << ")";
623 return false;
624 }
625 }
626 return true;
627 }
628
Intersect(const Interval & a,const Interval & b)629 Interval Interval::Intersect(const Interval& a, const Interval& b) {
630 Interval ret = a;
631 if (a.device_index != b.device_index) {
632 ret.start = ret.end = a.start; // set length to 0 to indicate no intersection.
633 return ret;
634 }
635 ret.start = std::max(a.start, b.start);
636 ret.end = std::max(ret.start, std::min(a.end, b.end));
637 return ret;
638 }
639
Intersect(const std::vector<Interval> & a,const std::vector<Interval> & b)640 std::vector<Interval> Interval::Intersect(const std::vector<Interval>& a,
641 const std::vector<Interval>& b) {
642 std::vector<Interval> ret;
643 for (const Interval& a_interval : a) {
644 for (const Interval& b_interval : b) {
645 auto intersect = Intersect(a_interval, b_interval);
646 if (intersect.length() > 0) ret.emplace_back(std::move(intersect));
647 }
648 }
649 return ret;
650 }
651
AsExtent() const652 std::unique_ptr<Extent> Interval::AsExtent() const {
653 return std::make_unique<LinearExtent>(length(), device_index, start);
654 }
655
GrowPartition(Partition * partition,uint64_t aligned_size,const std::vector<Interval> & free_region_hint)656 bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size,
657 const std::vector<Interval>& free_region_hint) {
658 uint64_t space_needed = aligned_size - partition->size();
659 uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
660 DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
661
662 std::vector<Interval> free_regions = GetFreeRegions();
663 if (!free_region_hint.empty())
664 free_regions = Interval::Intersect(free_regions, free_region_hint);
665
666 const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
667 CHECK_NE(sectors_per_block, 0);
668 CHECK(sectors_needed % sectors_per_block == 0);
669
670 if (IsABDevice() && ShouldHalveSuper() && GetPartitionSlotSuffix(partition->name()) == "_b") {
671 // Allocate "a" partitions top-down and "b" partitions bottom-up, to
672 // minimize fragmentation during OTA.
673 free_regions = PrioritizeSecondHalfOfSuper(free_regions);
674 }
675
676 // Note we store new extents in a temporary vector, and only commit them
677 // if we are guaranteed enough free space.
678 std::vector<std::unique_ptr<LinearExtent>> new_extents;
679
680 // If the last extent in the partition has a size < alignment, then the
681 // difference is unallocatable due to being misaligned. We peek for that
682 // case here to avoid wasting space.
683 if (auto extent = ExtendFinalExtent(partition, free_regions, sectors_needed)) {
684 sectors_needed -= extent->num_sectors();
685 new_extents.emplace_back(std::move(extent));
686 }
687
688 for (auto& region : free_regions) {
689 // Note: this comes first, since we may enter the loop not needing any
690 // more sectors.
691 if (!sectors_needed) {
692 break;
693 }
694
695 if (region.length() % sectors_per_block != 0) {
696 // This should never happen, because it would imply that we
697 // once allocated an extent that was not a multiple of the
698 // block size. That extent would be rejected by DM_TABLE_LOAD.
699 LERROR << "Region " << region.start << ".." << region.end
700 << " is not a multiple of the block size, " << sectors_per_block;
701
702 // If for some reason the final region is mis-sized we still want
703 // to be able to grow partitions. So just to be safe, round the
704 // region down to the nearest block.
705 region.end = region.start + (region.length() / sectors_per_block) * sectors_per_block;
706 if (!region.length()) {
707 continue;
708 }
709 }
710
711 uint64_t sectors = std::min(sectors_needed, region.length());
712 CHECK(sectors % sectors_per_block == 0);
713
714 auto extent = std::make_unique<LinearExtent>(sectors, region.device_index, region.start);
715 new_extents.push_back(std::move(extent));
716 sectors_needed -= sectors;
717 }
718 if (sectors_needed) {
719 LERROR << "Not enough free space to expand partition: " << partition->name();
720 return false;
721 }
722
723 // Everything succeeded, so commit the new extents.
724 for (auto& extent : new_extents) {
725 partition->AddExtent(std::move(extent));
726 }
727 return true;
728 }
729
PrioritizeSecondHalfOfSuper(const std::vector<Interval> & free_list)730 std::vector<Interval> MetadataBuilder::PrioritizeSecondHalfOfSuper(
731 const std::vector<Interval>& free_list) {
732 const auto& super = block_devices_[0];
733 uint64_t first_sector = super.first_logical_sector;
734 uint64_t last_sector = super.size / LP_SECTOR_SIZE;
735 uint64_t midpoint = first_sector + (last_sector - first_sector) / 2;
736
737 // Choose an aligned sector for the midpoint. This could lead to one half
738 // being slightly larger than the other, but this will not restrict the
739 // size of partitions (it might lead to one extra extent if "B" overflows).
740 midpoint = AlignSector(super, midpoint);
741
742 std::vector<Interval> first_half;
743 std::vector<Interval> second_half;
744 for (const auto& region : free_list) {
745 // Note: deprioritze if not the main super partition. Even though we
746 // don't call this for retrofit devices, we will allow adding additional
747 // block devices on non-retrofit devices.
748 if (region.device_index != 0 || region.end <= midpoint) {
749 first_half.emplace_back(region);
750 continue;
751 }
752 if (region.start < midpoint && region.end > midpoint) {
753 // Split this into two regions.
754 first_half.emplace_back(region.device_index, region.start, midpoint);
755 second_half.emplace_back(region.device_index, midpoint, region.end);
756 } else {
757 second_half.emplace_back(region);
758 }
759 }
760 second_half.insert(second_half.end(), first_half.begin(), first_half.end());
761 return second_half;
762 }
763
ExtendFinalExtent(Partition * partition,const std::vector<Interval> & free_list,uint64_t sectors_needed) const764 std::unique_ptr<LinearExtent> MetadataBuilder::ExtendFinalExtent(
765 Partition* partition, const std::vector<Interval>& free_list,
766 uint64_t sectors_needed) const {
767 if (partition->extents().empty()) {
768 return nullptr;
769 }
770 LinearExtent* extent = partition->extents().back()->AsLinearExtent();
771 if (!extent) {
772 return nullptr;
773 }
774
775 // If the sector ends where the next aligned chunk begins, then there's
776 // no missing gap to try and allocate.
777 const auto& block_device = block_devices_[extent->device_index()];
778 uint64_t next_aligned_sector = AlignSector(block_device, extent->end_sector());
779 if (extent->end_sector() == next_aligned_sector) {
780 return nullptr;
781 }
782
783 uint64_t num_sectors = std::min(next_aligned_sector - extent->end_sector(), sectors_needed);
784 auto new_extent = std::make_unique<LinearExtent>(num_sectors, extent->device_index(),
785 extent->end_sector());
786 if (IsAnyRegionAllocated(*new_extent.get()) ||
787 IsAnyRegionCovered(free_list, *new_extent.get())) {
788 LERROR << "Misaligned region " << new_extent->physical_sector() << ".."
789 << new_extent->end_sector() << " was allocated or marked allocatable.";
790 return nullptr;
791 }
792 return new_extent;
793 }
794
IsAnyRegionCovered(const std::vector<Interval> & regions,const LinearExtent & candidate) const795 bool MetadataBuilder::IsAnyRegionCovered(const std::vector<Interval>& regions,
796 const LinearExtent& candidate) const {
797 for (const auto& region : regions) {
798 if (candidate.OverlapsWith(region)) {
799 return true;
800 }
801 }
802 return false;
803 }
804
IsAnyRegionAllocated(const LinearExtent & candidate) const805 bool MetadataBuilder::IsAnyRegionAllocated(const LinearExtent& candidate) const {
806 for (const auto& partition : partitions_) {
807 for (const auto& extent : partition->extents()) {
808 LinearExtent* linear = extent->AsLinearExtent();
809 if (!linear) {
810 continue;
811 }
812 if (linear->OverlapsWith(candidate)) {
813 return true;
814 }
815 }
816 }
817 return false;
818 }
819
ShrinkPartition(Partition * partition,uint64_t aligned_size)820 void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_size) {
821 partition->ShrinkTo(aligned_size);
822 }
823
Export()824 std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
825 if (!ValidatePartitionGroups()) {
826 return nullptr;
827 }
828
829 std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
830 metadata->header = header_;
831 metadata->geometry = geometry_;
832
833 // Assign this early so the extent table can read it.
834 for (const auto& block_device : block_devices_) {
835 metadata->block_devices.emplace_back(block_device);
836 if (auto_slot_suffixing_) {
837 metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED;
838 }
839 }
840
841 std::map<std::string, size_t> group_indices;
842 for (const auto& group : groups_) {
843 LpMetadataPartitionGroup out = {};
844
845 if (group->name().size() > sizeof(out.name)) {
846 LERROR << "Partition group name is too long: " << group->name();
847 return nullptr;
848 }
849 if (auto_slot_suffixing_ && group->name() != kDefaultGroup) {
850 out.flags |= LP_GROUP_SLOT_SUFFIXED;
851 }
852 strncpy(out.name, group->name().c_str(), sizeof(out.name));
853 out.maximum_size = group->maximum_size();
854
855 group_indices[group->name()] = metadata->groups.size();
856 metadata->groups.push_back(out);
857 }
858
859 // Flatten the partition and extent structures into an LpMetadata, which
860 // makes it very easy to validate, serialize, or pass on to device-mapper.
861 for (const auto& partition : partitions_) {
862 LpMetadataPartition part;
863 memset(&part, 0, sizeof(part));
864
865 if (partition->name().size() > sizeof(part.name)) {
866 LERROR << "Partition name is too long: " << partition->name();
867 return nullptr;
868 }
869 if (partition->attributes() & ~(LP_PARTITION_ATTRIBUTE_MASK)) {
870 LERROR << "Partition " << partition->name() << " has unsupported attribute.";
871 return nullptr;
872 }
873
874 if (partition->attributes() & LP_PARTITION_ATTRIBUTE_MASK_V1) {
875 static const uint16_t kMinVersion = LP_METADATA_VERSION_FOR_UPDATED_ATTR;
876 metadata->header.minor_version = std::max(metadata->header.minor_version, kMinVersion);
877 }
878
879 strncpy(part.name, partition->name().c_str(), sizeof(part.name));
880 part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
881 part.num_extents = static_cast<uint32_t>(partition->extents().size());
882 part.attributes = partition->attributes();
883 if (auto_slot_suffixing_) {
884 part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED;
885 }
886
887 auto iter = group_indices.find(partition->group_name());
888 if (iter == group_indices.end()) {
889 LERROR << "Partition " << partition->name() << " is a member of unknown group "
890 << partition->group_name();
891 return nullptr;
892 }
893 part.group_index = iter->second;
894
895 for (const auto& extent : partition->extents()) {
896 if (!extent->AddTo(metadata.get())) {
897 return nullptr;
898 }
899 }
900 metadata->partitions.push_back(part);
901 }
902
903 metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size());
904 metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size());
905 metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size());
906 metadata->header.block_devices.num_entries =
907 static_cast<uint32_t>(metadata->block_devices.size());
908 return metadata;
909 }
910
RequireExpandedMetadataHeader()911 void MetadataBuilder::RequireExpandedMetadataHeader() {
912 if (header_.minor_version >= LP_METADATA_VERSION_FOR_EXPANDED_HEADER) {
913 return;
914 }
915 header_.minor_version = LP_METADATA_VERSION_FOR_EXPANDED_HEADER;
916 header_.header_size = sizeof(LpMetadataHeaderV1_2);
917 }
918
AllocatableSpace() const919 uint64_t MetadataBuilder::AllocatableSpace() const {
920 uint64_t total_size = 0;
921 for (const auto& block_device : block_devices_) {
922 total_size += block_device.size - (block_device.first_logical_sector * LP_SECTOR_SIZE);
923 }
924 return total_size;
925 }
926
UsedSpace() const927 uint64_t MetadataBuilder::UsedSpace() const {
928 uint64_t size = 0;
929 for (const auto& partition : partitions_) {
930 size += partition->size();
931 }
932 return size;
933 }
934
AlignSector(const LpMetadataBlockDevice & block_device,uint64_t sector) const935 uint64_t MetadataBuilder::AlignSector(const LpMetadataBlockDevice& block_device,
936 uint64_t sector) const {
937 // Note: when reading alignment info from the Kernel, we don't assume it
938 // is aligned to the sector size, so we round up to the nearest sector.
939 uint64_t lba = sector * LP_SECTOR_SIZE;
940 uint64_t aligned = AlignTo(lba, block_device.alignment, block_device.alignment_offset);
941 return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
942 }
943
FindBlockDeviceByName(const std::string & partition_name,uint32_t * index) const944 bool MetadataBuilder::FindBlockDeviceByName(const std::string& partition_name,
945 uint32_t* index) const {
946 for (size_t i = 0; i < block_devices_.size(); i++) {
947 if (GetBlockDevicePartitionName(i) == partition_name) {
948 *index = i;
949 return true;
950 }
951 }
952 return false;
953 }
954
HasBlockDevice(const std::string & partition_name) const955 bool MetadataBuilder::HasBlockDevice(const std::string& partition_name) const {
956 uint32_t index;
957 return FindBlockDeviceByName(partition_name, &index);
958 }
959
GetBlockDeviceInfo(const std::string & partition_name,BlockDeviceInfo * info) const960 bool MetadataBuilder::GetBlockDeviceInfo(const std::string& partition_name,
961 BlockDeviceInfo* info) const {
962 uint32_t index;
963 if (!FindBlockDeviceByName(partition_name, &index)) {
964 LERROR << "No device named " << partition_name;
965 return false;
966 }
967 info->size = block_devices_[index].size;
968 info->alignment = block_devices_[index].alignment;
969 info->alignment_offset = block_devices_[index].alignment_offset;
970 info->logical_block_size = geometry_.logical_block_size;
971 info->partition_name = partition_name;
972 return true;
973 }
974
UpdateBlockDeviceInfo(const std::string & partition_name,const BlockDeviceInfo & device_info)975 bool MetadataBuilder::UpdateBlockDeviceInfo(const std::string& partition_name,
976 const BlockDeviceInfo& device_info) {
977 uint32_t index;
978 if (!FindBlockDeviceByName(partition_name, &index)) {
979 LERROR << "No device named " << partition_name;
980 return false;
981 }
982 return UpdateBlockDeviceInfo(index, device_info);
983 }
984
UpdateBlockDeviceInfo(size_t index,const BlockDeviceInfo & device_info)985 bool MetadataBuilder::UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& device_info) {
986 CHECK(index < block_devices_.size());
987
988 LpMetadataBlockDevice& block_device = block_devices_[index];
989 if (device_info.size != block_device.size) {
990 LERROR << "Device size does not match (got " << device_info.size << ", expected "
991 << block_device.size << ")";
992 return false;
993 }
994 if (geometry_.logical_block_size % device_info.logical_block_size) {
995 LERROR << "Device logical block size is misaligned (block size="
996 << device_info.logical_block_size << ", alignment=" << geometry_.logical_block_size
997 << ")";
998 return false;
999 }
1000
1001 // The kernel does not guarantee these values are present, so we only
1002 // replace existing values if the new values are non-zero.
1003 if (device_info.alignment) {
1004 block_device.alignment = device_info.alignment;
1005 }
1006 if (device_info.alignment_offset) {
1007 block_device.alignment_offset = device_info.alignment_offset;
1008 }
1009 return true;
1010 }
1011
ResizePartition(Partition * partition,uint64_t requested_size,const std::vector<Interval> & free_region_hint)1012 bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size,
1013 const std::vector<Interval>& free_region_hint) {
1014 // Align the space needed up to the nearest sector.
1015 uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
1016 uint64_t old_size = partition->size();
1017
1018 if (!ValidatePartitionSizeChange(partition, old_size, aligned_size, false)) {
1019 return false;
1020 }
1021
1022 if (aligned_size > old_size) {
1023 if (!GrowPartition(partition, aligned_size, free_region_hint)) {
1024 return false;
1025 }
1026 } else if (aligned_size < partition->size()) {
1027 ShrinkPartition(partition, aligned_size);
1028 }
1029
1030 if (partition->size() != old_size) {
1031 LINFO << "Partition " << partition->name() << " will resize from " << old_size
1032 << " bytes to " << aligned_size << " bytes";
1033 }
1034 return true;
1035 }
1036
ListGroups() const1037 std::vector<std::string> MetadataBuilder::ListGroups() const {
1038 std::vector<std::string> names;
1039 for (const auto& group : groups_) {
1040 names.emplace_back(group->name());
1041 }
1042 return names;
1043 }
1044
RemoveGroupAndPartitions(std::string_view group_name)1045 void MetadataBuilder::RemoveGroupAndPartitions(std::string_view group_name) {
1046 if (group_name == kDefaultGroup) {
1047 // Cannot remove the default group.
1048 return;
1049 }
1050 std::vector<std::string> partition_names;
1051 for (const auto& partition : partitions_) {
1052 if (partition->group_name() == group_name) {
1053 partition_names.emplace_back(partition->name());
1054 }
1055 }
1056
1057 for (const auto& partition_name : partition_names) {
1058 RemovePartition(partition_name);
1059 }
1060 for (auto iter = groups_.begin(); iter != groups_.end(); iter++) {
1061 if ((*iter)->name() == group_name) {
1062 groups_.erase(iter);
1063 break;
1064 }
1065 }
1066 }
1067
CompareBlockDevices(const LpMetadataBlockDevice & first,const LpMetadataBlockDevice & second)1068 static bool CompareBlockDevices(const LpMetadataBlockDevice& first,
1069 const LpMetadataBlockDevice& second) {
1070 // Note: we don't compare alignment, since it's a performance thing and
1071 // won't affect whether old extents continue to work.
1072 return first.first_logical_sector == second.first_logical_sector && first.size == second.size &&
1073 android::fs_mgr::GetBlockDevicePartitionName(first) ==
1074 android::fs_mgr::GetBlockDevicePartitionName(second);
1075 }
1076
ImportPartitions(const LpMetadata & metadata,const std::set<std::string> & partition_names)1077 bool MetadataBuilder::ImportPartitions(const LpMetadata& metadata,
1078 const std::set<std::string>& partition_names) {
1079 // The block device list must be identical. We do not try to be clever and
1080 // allow ordering changes or changes that don't affect partitions. This
1081 // process is designed to allow the most common flashing scenarios and more
1082 // complex ones should require a wipe.
1083 if (metadata.block_devices.size() != block_devices_.size()) {
1084 LINFO << "Block device tables does not match.";
1085 return false;
1086 }
1087 for (size_t i = 0; i < metadata.block_devices.size(); i++) {
1088 const LpMetadataBlockDevice& old_device = metadata.block_devices[i];
1089 const LpMetadataBlockDevice& new_device = block_devices_[i];
1090 if (!CompareBlockDevices(old_device, new_device)) {
1091 LINFO << "Block device tables do not match";
1092 return false;
1093 }
1094 }
1095
1096 // Import named partitions. Note that we do not attempt to merge group
1097 // information here. If the device changed its group names, the old
1098 // partitions will fail to merge. The same could happen if the group
1099 // allocation sizes change.
1100 for (const auto& partition : metadata.partitions) {
1101 std::string partition_name = GetPartitionName(partition);
1102 if (partition_names.find(partition_name) == partition_names.end()) {
1103 continue;
1104 }
1105 if (!ImportPartition(metadata, partition)) {
1106 return false;
1107 }
1108 }
1109 return true;
1110 }
1111
ImportPartition(const LpMetadata & metadata,const LpMetadataPartition & source)1112 bool MetadataBuilder::ImportPartition(const LpMetadata& metadata,
1113 const LpMetadataPartition& source) {
1114 std::string partition_name = GetPartitionName(source);
1115 Partition* partition = FindPartition(partition_name);
1116 if (!partition) {
1117 std::string group_name = GetPartitionGroupName(metadata.groups[source.group_index]);
1118 partition = AddPartition(partition_name, group_name, source.attributes);
1119 if (!partition) {
1120 return false;
1121 }
1122 }
1123 if (partition->size() > 0) {
1124 LINFO << "Importing partition table would overwrite non-empty partition: "
1125 << partition_name;
1126 return false;
1127 }
1128
1129 ImportExtents(partition, metadata, source);
1130
1131 // Note: we've already increased the partition size by calling
1132 // ImportExtents(). In order to figure out the size before that,
1133 // we would have to iterate the extents and add up the linear
1134 // segments. Instead, we just force ValidatePartitionSizeChange
1135 // to check if the current configuration is acceptable.
1136 if (!ValidatePartitionSizeChange(partition, partition->size(), partition->size(), true)) {
1137 partition->RemoveExtents();
1138 return false;
1139 }
1140 return true;
1141 }
1142
SetAutoSlotSuffixing()1143 void MetadataBuilder::SetAutoSlotSuffixing() {
1144 auto_slot_suffixing_ = true;
1145 }
1146
SetVirtualABDeviceFlag()1147 void MetadataBuilder::SetVirtualABDeviceFlag() {
1148 RequireExpandedMetadataHeader();
1149 header_.flags |= LP_HEADER_FLAG_VIRTUAL_AB_DEVICE;
1150 }
1151
IsABDevice()1152 bool MetadataBuilder::IsABDevice() {
1153 return !IPropertyFetcher::GetInstance()->GetProperty("ro.boot.slot_suffix", "").empty();
1154 }
1155
IsRetrofitDynamicPartitionsDevice()1156 bool MetadataBuilder::IsRetrofitDynamicPartitionsDevice() {
1157 return IPropertyFetcher::GetInstance()->GetBoolProperty("ro.boot.dynamic_partitions_retrofit",
1158 false);
1159 }
1160
ShouldHalveSuper() const1161 bool MetadataBuilder::ShouldHalveSuper() const {
1162 return GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME &&
1163 !IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false);
1164 }
1165
AddLinearExtent(Partition * partition,const std::string & block_device,uint64_t num_sectors,uint64_t physical_sector)1166 bool MetadataBuilder::AddLinearExtent(Partition* partition, const std::string& block_device,
1167 uint64_t num_sectors, uint64_t physical_sector) {
1168 uint32_t device_index;
1169 if (!FindBlockDeviceByName(block_device, &device_index)) {
1170 LERROR << "Could not find backing block device for extent: " << block_device;
1171 return false;
1172 }
1173
1174 auto extent = std::make_unique<LinearExtent>(num_sectors, device_index, physical_sector);
1175 partition->AddExtent(std::move(extent));
1176 return true;
1177 }
1178
ListPartitionsInGroup(std::string_view group_name)1179 std::vector<Partition*> MetadataBuilder::ListPartitionsInGroup(std::string_view group_name) {
1180 std::vector<Partition*> partitions;
1181 for (const auto& partition : partitions_) {
1182 if (partition->group_name() == group_name) {
1183 partitions.emplace_back(partition.get());
1184 }
1185 }
1186 return partitions;
1187 }
1188
ChangePartitionGroup(Partition * partition,std::string_view group_name)1189 bool MetadataBuilder::ChangePartitionGroup(Partition* partition, std::string_view group_name) {
1190 if (!FindGroup(group_name)) {
1191 LERROR << "Partition cannot change to unknown group: " << group_name;
1192 return false;
1193 }
1194 partition->set_group_name(group_name);
1195 return true;
1196 }
1197
ValidatePartitionGroups() const1198 bool MetadataBuilder::ValidatePartitionGroups() const {
1199 for (const auto& group : groups_) {
1200 if (!group->maximum_size()) {
1201 continue;
1202 }
1203 uint64_t used = TotalSizeOfGroup(group.get());
1204 if (used > group->maximum_size()) {
1205 LERROR << "Partition group " << group->name() << " exceeds maximum size (" << used
1206 << " bytes used, maximum " << group->maximum_size() << ")";
1207 return false;
1208 }
1209 }
1210 return true;
1211 }
1212
ChangeGroupSize(const std::string & group_name,uint64_t maximum_size)1213 bool MetadataBuilder::ChangeGroupSize(const std::string& group_name, uint64_t maximum_size) {
1214 if (group_name == kDefaultGroup) {
1215 LERROR << "Cannot change the size of the default group";
1216 return false;
1217 }
1218 PartitionGroup* group = FindGroup(group_name);
1219 if (!group) {
1220 LERROR << "Cannot change size of unknown partition group: " << group_name;
1221 return false;
1222 }
1223 group->set_maximum_size(maximum_size);
1224 return true;
1225 }
1226
GetBlockDevicePartitionName(uint64_t index) const1227 std::string MetadataBuilder::GetBlockDevicePartitionName(uint64_t index) const {
1228 return index < block_devices_.size()
1229 ? android::fs_mgr::GetBlockDevicePartitionName(block_devices_[index])
1230 : "";
1231 }
1232
logical_block_size() const1233 uint64_t MetadataBuilder::logical_block_size() const {
1234 return geometry_.logical_block_size;
1235 }
1236
1237 } // namespace fs_mgr
1238 } // namespace android
1239