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 #ifndef UPDATE_ENGINE_AOSP_DYNAMIC_PARTITION_CONTROL_ANDROID_H_ 18 #define UPDATE_ENGINE_AOSP_DYNAMIC_PARTITION_CONTROL_ANDROID_H_ 19 20 #include <memory> 21 #include <set> 22 #include <string> 23 #include <string_view> 24 #include <array> 25 26 #include <base/files/file_util.h> 27 #include <libsnapshot/auto_device.h> 28 #include <libsnapshot/snapshot.h> 29 #include <libsnapshot/snapshot_writer.h> 30 31 #include "update_engine/common/dynamic_partition_control_interface.h" 32 33 namespace chromeos_update_engine { 34 35 class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface { 36 public: 37 // A directory where all partitions mapped by VABC is expected to be found. 38 // Per earlier discussion with VAB team, this directory is unlikely to change. 39 // So we declare it as a constant here. 40 static constexpr std::string_view VABC_DEVICE_DIR = "/dev/block/mapper/"; 41 explicit DynamicPartitionControlAndroid(uint32_t source_slot); 42 ~DynamicPartitionControlAndroid(); 43 44 FeatureFlag GetDynamicPartitionsFeatureFlag() override; 45 FeatureFlag GetVirtualAbFeatureFlag() override; 46 FeatureFlag GetVirtualAbCompressionFeatureFlag() override; 47 FeatureFlag GetVirtualAbCompressionXorFeatureFlag() override; 48 FeatureFlag GetVirtualAbUserspaceSnapshotsFeatureFlag() override; 49 bool OptimizeOperation(const std::string& partition_name, 50 const InstallOperation& operation, 51 InstallOperation* optimized) override; 52 void Cleanup() override; 53 54 bool PreparePartitionsForUpdate(uint32_t source_slot, 55 uint32_t target_slot, 56 const DeltaArchiveManifest& manifest, 57 bool update, 58 uint64_t* required_size) override; 59 bool FinishUpdate(bool powerwash_required) override; 60 std::unique_ptr<AbstractAction> GetCleanupPreviousUpdateAction( 61 BootControlInterface* boot_control, 62 PrefsInterface* prefs, 63 CleanupPreviousUpdateActionDelegateInterface* delegate) override; 64 65 bool ResetUpdate(PrefsInterface* prefs) override; 66 67 bool ListDynamicPartitionsForSlot( 68 uint32_t slot, 69 uint32_t current_slot, 70 std::vector<std::string>* partitions) override; 71 72 bool VerifyExtentsForUntouchedPartitions( 73 uint32_t source_slot, 74 uint32_t target_slot, 75 const std::vector<std::string>& partitions) override; 76 77 bool GetDeviceDir(std::string* path) override; 78 79 // Return the device for partition |partition_name| at slot |slot|. 80 // |current_slot| should be set to the current active slot. 81 // Note: this function is only used by BootControl*::GetPartitionDevice. 82 // Other callers should prefer BootControl*::GetPartitionDevice over 83 // BootControl*::GetDynamicPartitionControl()->GetPartitionDevice(). 84 std::optional<PartitionDevice> GetPartitionDevice( 85 const std::string& partition_name, 86 uint32_t slot, 87 uint32_t current_slot, 88 bool not_in_payload); 89 // Deprecated, please use GetPartitionDevice(string, uint32_t, uint32_t); 90 // TODO(zhangkelvin) Remove below deprecated APIs. 91 bool GetPartitionDevice(const std::string& partition_name, 92 uint32_t slot, 93 uint32_t current_slot, 94 bool not_in_payload, 95 std::string* device, 96 bool* is_dynamic); 97 98 bool GetPartitionDevice(const std::string& partition_name, 99 uint32_t slot, 100 uint32_t current_slot, 101 std::string* device); 102 103 // Partition name is expected to be unsuffixed. e.g. system, vendor 104 // Return an interface to write to a snapshoted partition. 105 std::unique_ptr<android::snapshot::ISnapshotWriter> OpenCowWriter( 106 const std::string& unsuffixed_partition_name, 107 const std::optional<std::string>& source_path, 108 bool is_append) override; 109 std::unique_ptr<FileDescriptor> OpenCowFd( 110 const std::string& unsuffixed_partition_name, 111 const std::optional<std::string>&, 112 bool is_append = false) override; 113 114 bool MapAllPartitions() override; 115 bool UnmapAllPartitions() override; 116 117 bool IsDynamicPartition(const std::string& part_name, uint32_t slot) override; 118 119 bool UpdateUsesSnapshotCompression() override; 120 121 std::optional<base::FilePath> GetSuperDevice(); 122 123 protected: 124 // These functions are exposed for testing. 125 126 // Unmap logical partition on device mapper. This is the reverse operation 127 // of MapPartitionOnDeviceMapper. 128 // Returns true if unmapped successfully. 129 virtual bool UnmapPartitionOnDeviceMapper( 130 const std::string& target_partition_name); 131 132 // Retrieves metadata from |super_device| at slot |slot|. 133 virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder( 134 const std::string& super_device, uint32_t slot); 135 136 // Retrieves metadata from |super_device| at slot |source_slot|. And 137 // modifies the metadata so that during updates, the metadata can be written 138 // to |target_slot|. In particular, on retrofit devices, the returned 139 // metadata automatically includes block devices at |target_slot|. 140 virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder( 141 const std::string& super_device, 142 uint32_t source_slot, 143 uint32_t target_slot); 144 145 // Write metadata |builder| to |super_device| at slot |target_slot|. 146 virtual bool StoreMetadata(const std::string& super_device, 147 android::fs_mgr::MetadataBuilder* builder, 148 uint32_t target_slot); 149 150 // Map logical partition on device-mapper. 151 // |super_device| is the device path of the physical partition ("super"). 152 // |target_partition_name| is the identifier used in metadata; for example, 153 // "vendor_a" 154 // |slot| is the selected slot to mount; for example, 0 for "_a". 155 // Returns true if mapped successfully; if so, |path| is set to the device 156 // path of the mapped logical partition. 157 virtual bool MapPartitionOnDeviceMapper( 158 const std::string& super_device, 159 const std::string& target_partition_name, 160 uint32_t slot, 161 bool force_writable, 162 std::string* path); 163 164 // Return true if a static partition exists at device path |path|. 165 virtual bool DeviceExists(const std::string& path); 166 167 // Returns the current state of the underlying device mapper device 168 // with given name. 169 // One of INVALID, SUSPENDED or ACTIVE. 170 virtual android::dm::DmDeviceState GetState(const std::string& name); 171 172 // Returns the path to the device mapper device node in '/dev' corresponding 173 // to 'name'. If the device does not exist, false is returned, and the path 174 // parameter is not set. 175 virtual bool GetDmDevicePathByName(const std::string& name, 176 std::string* path); 177 178 // Return the name of the super partition (which stores super partition 179 // metadata) for a given slot. 180 virtual std::string GetSuperPartitionName(uint32_t slot); 181 182 virtual void set_fake_mapped_devices(const std::set<std::string>& fake); 183 184 // Allow mock objects to override this to test recovery mode. 185 virtual bool IsRecovery(); 186 187 // Determine path for system_other partition. 188 // |source_slot| should be current slot. 189 // |target_slot| should be "other" slot. 190 // |partition_name_suffix| should be "system" + suffix(|target_slot|). 191 // Return true and set |path| if successful. 192 // Set |path| to empty if no need to erase system_other. 193 // Set |should_unmap| to true if path needs to be unmapped later. 194 // 195 // Note: system_other cannot use GetPartitionDevice or 196 // GetDynamicPartitionDevice because: 197 // - super partition metadata may be loaded from the source slot 198 // - UPDATED flag needs to be check to skip erasing if partition is not 199 // created by flashing tools 200 // - Snapshots from previous update attempts should not be used. 201 virtual bool GetSystemOtherPath(uint32_t source_slot, 202 uint32_t target_slot, 203 const std::string& partition_name_suffix, 204 std::string* path, 205 bool* should_unmap); 206 207 // Returns true if any entry in the fstab file in |path| has AVB enabled, 208 // false if not enabled, and nullopt for any error. 209 virtual std::optional<bool> IsAvbEnabledInFstab(const std::string& path); 210 211 // Returns true if system_other has AVB enabled, false if not enabled, and 212 // nullopt for any error. 213 virtual std::optional<bool> IsAvbEnabledOnSystemOther(); 214 215 // Erase system_other partition that may contain system_other.img. 216 // After the update, the content of system_other may be corrupted but with 217 // valid AVB footer. If the update is rolled back and factory data reset is 218 // triggered, system_b fails to be mapped with verity errors (see 219 // b/152444348). Erase the system_other so that mapping system_other is 220 // skipped. 221 virtual bool EraseSystemOtherAvbFooter(uint32_t source_slot, 222 uint32_t target_slot); 223 224 // Helper for PreparePartitionsForUpdate. Used for devices with dynamic 225 // partitions updating without snapshots. 226 // If |delete_source| is set, source partitions are deleted before resizing 227 // target partitions (using DeleteSourcePartitions). 228 virtual bool PrepareDynamicPartitionsForUpdate( 229 uint32_t source_slot, 230 uint32_t target_slot, 231 const DeltaArchiveManifest& manifest, 232 bool delete_source); 233 SetSourceSlot(uint32_t slot)234 void SetSourceSlot(uint32_t slot) { source_slot_ = slot; } SetTargetSlot(uint32_t slot)235 void SetTargetSlot(uint32_t slot) { target_slot_ = slot; } 236 237 private: 238 friend class DynamicPartitionControlAndroidTest; 239 friend class SnapshotPartitionTestP; 240 241 bool MapPartitionInternal(const std::string& super_device, 242 const std::string& target_partition_name, 243 uint32_t slot, 244 bool force_writable, 245 std::string* path); 246 247 // Update |builder| according to |partition_metadata|. 248 // - In Android mode, this is only called when the device 249 // does not have Virtual A/B. 250 // - When sideloading, this maybe called as a fallback path if CoW cannot 251 // be created. 252 bool UpdatePartitionMetadata(android::fs_mgr::MetadataBuilder* builder, 253 uint32_t target_slot, 254 const DeltaArchiveManifest& manifest); 255 256 // Helper for PreparePartitionsForUpdate. Used for snapshotted partitions 257 // for Virtual A/B update. 258 bool PrepareSnapshotPartitionsForUpdate(uint32_t source_slot, 259 uint32_t target_slot, 260 const DeltaArchiveManifest& manifest, 261 uint64_t* required_size); 262 263 enum SpaceLimit { 264 // Most restricted: if sum(groups) > super / 2, error 265 ERROR_IF_EXCEEDED_HALF_OF_SUPER, 266 // Implies ERROR_IF_EXCEEDED_SUPER; then, if sum(groups) > super / 2, warn 267 WARN_IF_EXCEEDED_HALF_OF_SUPER, 268 // Least restricted: if sum(groups) > super, error 269 ERROR_IF_EXCEEDED_SUPER, 270 }; 271 // Helper of CheckSuperPartitionAllocatableSpace. Determine limit for groups 272 // and partitions. 273 SpaceLimit GetSpaceLimit(bool use_snapshot); 274 275 // Returns true if the allocatable space in super partition is larger than 276 // the size of dynamic partition groups in the manifest. 277 bool CheckSuperPartitionAllocatableSpace( 278 android::fs_mgr::MetadataBuilder* builder, 279 const DeltaArchiveManifest& manifest, 280 bool use_snapshot); 281 282 enum class DynamicPartitionDeviceStatus { 283 SUCCESS, 284 ERROR, 285 TRY_STATIC, 286 }; 287 288 // Return SUCCESS and path in |device| if partition is dynamic. 289 // Return ERROR if any error. 290 // Return TRY_STATIC if caller should resolve the partition as a static 291 // partition instead. 292 DynamicPartitionDeviceStatus GetDynamicPartitionDevice( 293 const base::FilePath& device_dir, 294 const std::string& partition_name_suffix, 295 uint32_t slot, 296 uint32_t current_slot, 297 bool not_in_payload, 298 std::string* device); 299 300 // Return true if |partition_name_suffix| is a block device of 301 // super partition metadata slot |slot|. 302 bool IsSuperBlockDevice(const base::FilePath& device_dir, 303 uint32_t current_slot, 304 const std::string& partition_name_suffix); 305 306 // If sideloading a full OTA, delete source partitions from |builder|. 307 bool DeleteSourcePartitions(android::fs_mgr::MetadataBuilder* builder, 308 uint32_t source_slot, 309 const DeltaArchiveManifest& manifest); 310 311 // Returns true if metadata is expected to be mounted, false otherwise. 312 // Note that it returns false on non-Virtual A/B devices. 313 // 314 // Almost all functions of SnapshotManager depends on metadata being 315 // mounted. 316 // - In Android mode for Virtual A/B devices, assume it is mounted. If not, 317 // let caller fails when calling into SnapshotManager. 318 // - In recovery for Virtual A/B devices, it is possible that metadata is 319 // not 320 // formatted, hence it cannot be mounted. Caller should not call into 321 // SnapshotManager. 322 // - On non-Virtual A/B devices, updates do not depend on metadata 323 // partition. 324 // Caller should not call into SnapshotManager. 325 // 326 // This function does NOT mount metadata partition. Use 327 // EnsureMetadataMounted to mount metadata partition. 328 bool ExpectMetadataMounted(); 329 330 // Ensure /metadata is mounted. Returns true if successful, false otherwise. 331 // 332 // Note that this function returns true on non-Virtual A/B devices without 333 // doing anything. 334 bool EnsureMetadataMounted(); 335 336 // Set boolean flags related to target build. This includes flags like 337 // target_supports_snapshot_ and is_target_dynamic_. 338 bool SetTargetBuildVars(const DeltaArchiveManifest& manifest); 339 340 std::set<std::string> mapped_devices_; 341 const FeatureFlag dynamic_partitions_; 342 const FeatureFlag virtual_ab_; 343 const FeatureFlag virtual_ab_compression_; 344 const FeatureFlag virtual_ab_compression_xor_; 345 const FeatureFlag virtual_ab_userspace_snapshots_; 346 std::unique_ptr<android::snapshot::ISnapshotManager> snapshot_; 347 std::unique_ptr<android::snapshot::AutoDevice> metadata_device_; 348 bool target_supports_snapshot_ = false; 349 // Whether the target partitions should be loaded as dynamic partitions. Set 350 // by PreparePartitionsForUpdate() per each update. 351 bool is_target_dynamic_ = false; 352 353 uint32_t source_slot_ = UINT32_MAX; 354 uint32_t target_slot_ = UINT32_MAX; 355 // We assume that there's only 2 slots, A and B. This assumption is unlikely 356 // to change in the future. And certaintly won't change at runtime. 357 std::array<std::vector<std::string>, 2> dynamic_partition_list_{}; 358 359 DISALLOW_COPY_AND_ASSIGN(DynamicPartitionControlAndroid); 360 }; 361 362 } // namespace chromeos_update_engine 363 364 #endif // UPDATE_ENGINE_AOSP_DYNAMIC_PARTITION_CONTROL_ANDROID_H_ 365