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