• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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