• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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