• 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 <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