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