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