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