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