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_DYNAMIC_PARTITION_CONTROL_ANDROID_H_
18 #define UPDATE_ENGINE_DYNAMIC_PARTITION_CONTROL_ANDROID_H_
19 
20 #include <memory>
21 #include <set>
22 #include <string>
23 #include <vector>
24 
25 #include <base/files/file_util.h>
26 #include <libsnapshot/auto_device.h>
27 #include <libsnapshot/snapshot.h>
28 
29 #include "update_engine/common/dynamic_partition_control_interface.h"
30 
31 namespace chromeos_update_engine {
32 
33 class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
34  public:
35   DynamicPartitionControlAndroid();
36   ~DynamicPartitionControlAndroid();
37   FeatureFlag GetDynamicPartitionsFeatureFlag() override;
38   FeatureFlag GetVirtualAbFeatureFlag() override;
39   bool OptimizeOperation(const std::string& partition_name,
40                          const InstallOperation& operation,
41                          InstallOperation* optimized) override;
42   void Cleanup() override;
43 
44   bool PreparePartitionsForUpdate(uint32_t source_slot,
45                                   uint32_t target_slot,
46                                   const DeltaArchiveManifest& manifest,
47                                   bool update,
48                                   uint64_t* required_size) override;
49   bool FinishUpdate(bool powerwash_required) override;
50   std::unique_ptr<AbstractAction> GetCleanupPreviousUpdateAction(
51       BootControlInterface* boot_control,
52       PrefsInterface* prefs,
53       CleanupPreviousUpdateActionDelegateInterface* delegate) override;
54 
55   bool ResetUpdate(PrefsInterface* prefs) override;
56 
57   bool ListDynamicPartitionsForSlot(
58       uint32_t current_slot, std::vector<std::string>* partitions) override;
59 
60   bool VerifyExtentsForUntouchedPartitions(
61       uint32_t source_slot,
62       uint32_t target_slot,
63       const std::vector<std::string>& partitions) override;
64 
65   bool GetDeviceDir(std::string* path) override;
66 
67   // Return the device for partition |partition_name| at slot |slot|.
68   // |current_slot| should be set to the current active slot.
69   // Note: this function is only used by BootControl*::GetPartitionDevice.
70   // Other callers should prefer BootControl*::GetPartitionDevice over
71   // BootControl*::GetDynamicPartitionControl()->GetPartitionDevice().
72   bool GetPartitionDevice(const std::string& partition_name,
73                           uint32_t slot,
74                           uint32_t current_slot,
75                           bool not_in_payload,
76                           std::string* device,
77                           bool* is_dynamic);
78 
79   bool GetPartitionDevice(const std::string& partition_name,
80                           uint32_t slot,
81                           uint32_t current_slot,
82                           std::string* device);
83 
84  protected:
85   // These functions are exposed for testing.
86 
87   // Unmap logical partition on device mapper. This is the reverse operation
88   // of MapPartitionOnDeviceMapper.
89   // Returns true if unmapped successfully.
90   virtual bool UnmapPartitionOnDeviceMapper(
91       const std::string& target_partition_name);
92 
93   // Retrieves metadata from |super_device| at slot |slot|.
94   virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
95       const std::string& super_device, uint32_t slot);
96 
97   // Retrieves metadata from |super_device| at slot |source_slot|. And modifies
98   // the metadata so that during updates, the metadata can be written to
99   // |target_slot|. In particular, on retrofit devices, the returned metadata
100   // automatically includes block devices at |target_slot|.
101   virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
102       const std::string& super_device,
103       uint32_t source_slot,
104       uint32_t target_slot);
105 
106   // Write metadata |builder| to |super_device| at slot |target_slot|.
107   virtual bool StoreMetadata(const std::string& super_device,
108                              android::fs_mgr::MetadataBuilder* builder,
109                              uint32_t target_slot);
110 
111   // Map logical partition on device-mapper.
112   // |super_device| is the device path of the physical partition ("super").
113   // |target_partition_name| is the identifier used in metadata; for example,
114   // "vendor_a"
115   // |slot| is the selected slot to mount; for example, 0 for "_a".
116   // Returns true if mapped successfully; if so, |path| is set to the device
117   // path of the mapped logical partition.
118   virtual bool MapPartitionOnDeviceMapper(
119       const std::string& super_device,
120       const std::string& target_partition_name,
121       uint32_t slot,
122       bool force_writable,
123       std::string* path);
124 
125   // Return true if a static partition exists at device path |path|.
126   virtual bool DeviceExists(const std::string& path);
127 
128   // Returns the current state of the underlying device mapper device
129   // with given name.
130   // One of INVALID, SUSPENDED or ACTIVE.
131   virtual android::dm::DmDeviceState GetState(const std::string& name);
132 
133   // Returns the path to the device mapper device node in '/dev' corresponding
134   // to 'name'. If the device does not exist, false is returned, and the path
135   // parameter is not set.
136   virtual bool GetDmDevicePathByName(const std::string& name,
137                                      std::string* path);
138 
139   // Return the name of the super partition (which stores super partition
140   // metadata) for a given slot.
141   virtual std::string GetSuperPartitionName(uint32_t slot);
142 
143   virtual void set_fake_mapped_devices(const std::set<std::string>& fake);
144 
145   // Allow mock objects to override this to test recovery mode.
146   virtual bool IsRecovery();
147 
148   // Determine path for system_other partition.
149   // |source_slot| should be current slot.
150   // |target_slot| should be "other" slot.
151   // |partition_name_suffix| should be "system" + suffix(|target_slot|).
152   // Return true and set |path| if successful.
153   // Set |path| to empty if no need to erase system_other.
154   // Set |should_unmap| to true if path needs to be unmapped later.
155   //
156   // Note: system_other cannot use GetPartitionDevice or
157   // GetDynamicPartitionDevice because:
158   // - super partition metadata may be loaded from the source slot
159   // - UPDATED flag needs to be check to skip erasing if partition is not
160   //   created by flashing tools
161   // - Snapshots from previous update attempts should not be used.
162   virtual bool GetSystemOtherPath(uint32_t source_slot,
163                                   uint32_t target_slot,
164                                   const std::string& partition_name_suffix,
165                                   std::string* path,
166                                   bool* should_unmap);
167 
168   // Returns true if any entry in the fstab file in |path| has AVB enabled,
169   // false if not enabled, and nullopt for any error.
170   virtual std::optional<bool> IsAvbEnabledInFstab(const std::string& path);
171 
172   // Returns true if system_other has AVB enabled, false if not enabled, and
173   // nullopt for any error.
174   virtual std::optional<bool> IsAvbEnabledOnSystemOther();
175 
176   // Erase system_other partition that may contain system_other.img.
177   // After the update, the content of system_other may be corrupted but with
178   // valid AVB footer. If the update is rolled back and factory data reset is
179   // triggered, system_b fails to be mapped with verity errors (see
180   // b/152444348). Erase the system_other so that mapping system_other is
181   // skipped.
182   virtual bool EraseSystemOtherAvbFooter(uint32_t source_slot,
183                                          uint32_t target_slot);
184 
185   // Helper for PreparePartitionsForUpdate. Used for devices with dynamic
186   // partitions updating without snapshots.
187   // If |delete_source| is set, source partitions are deleted before resizing
188   // target partitions (using DeleteSourcePartitions).
189   virtual bool PrepareDynamicPartitionsForUpdate(
190       uint32_t source_slot,
191       uint32_t target_slot,
192       const DeltaArchiveManifest& manifest,
193       bool delete_source);
194 
195  private:
196   friend class DynamicPartitionControlAndroidTest;
197   friend class SnapshotPartitionTestP;
198 
199   void UnmapAllPartitions();
200   bool MapPartitionInternal(const std::string& super_device,
201                             const std::string& target_partition_name,
202                             uint32_t slot,
203                             bool force_writable,
204                             std::string* path);
205 
206   // Update |builder| according to |partition_metadata|, assuming the device
207   // does not have Virtual A/B.
208   bool UpdatePartitionMetadata(android::fs_mgr::MetadataBuilder* builder,
209                                uint32_t target_slot,
210                                const DeltaArchiveManifest& manifest);
211 
212   // Helper for PreparePartitionsForUpdate. Used for snapshotted partitions for
213   // Virtual A/B update.
214   bool PrepareSnapshotPartitionsForUpdate(uint32_t source_slot,
215                                           uint32_t target_slot,
216                                           const DeltaArchiveManifest& manifest,
217                                           uint64_t* required_size);
218 
219   enum class DynamicPartitionDeviceStatus {
220     SUCCESS,
221     ERROR,
222     TRY_STATIC,
223   };
224 
225   // Return SUCCESS and path in |device| if partition is dynamic.
226   // Return ERROR if any error.
227   // Return TRY_STATIC if caller should resolve the partition as a static
228   // partition instead.
229   DynamicPartitionDeviceStatus GetDynamicPartitionDevice(
230       const base::FilePath& device_dir,
231       const std::string& partition_name_suffix,
232       uint32_t slot,
233       uint32_t current_slot,
234       bool not_in_payload,
235       std::string* device);
236 
237   // Return true if |partition_name_suffix| is a block device of
238   // super partition metadata slot |slot|.
239   bool IsSuperBlockDevice(const base::FilePath& device_dir,
240                           uint32_t current_slot,
241                           const std::string& partition_name_suffix);
242 
243   // If sideloading a full OTA, delete source partitions from |builder|.
244   bool DeleteSourcePartitions(android::fs_mgr::MetadataBuilder* builder,
245                               uint32_t source_slot,
246                               const DeltaArchiveManifest& manifest);
247 
248   // Returns true if metadata is expected to be mounted, false otherwise.
249   // Note that it returns false on non-Virtual A/B devices.
250   //
251   // Almost all functions of SnapshotManager depends on metadata being mounted.
252   // - In Android mode for Virtual A/B devices, assume it is mounted. If not,
253   //   let caller fails when calling into SnapshotManager.
254   // - In recovery for Virtual A/B devices, it is possible that metadata is not
255   //   formatted, hence it cannot be mounted. Caller should not call into
256   //   SnapshotManager.
257   // - On non-Virtual A/B devices, updates do not depend on metadata partition.
258   //   Caller should not call into SnapshotManager.
259   //
260   // This function does NOT mount metadata partition. Use EnsureMetadataMounted
261   // to mount metadata partition.
262   bool ExpectMetadataMounted();
263 
264   // Ensure /metadata is mounted. Returns true if successful, false otherwise.
265   //
266   // Note that this function returns true on non-Virtual A/B devices without
267   // doing anything.
268   bool EnsureMetadataMounted();
269 
270   std::set<std::string> mapped_devices_;
271   const FeatureFlag dynamic_partitions_;
272   const FeatureFlag virtual_ab_;
273   std::unique_ptr<android::snapshot::ISnapshotManager> snapshot_;
274   std::unique_ptr<android::snapshot::AutoDevice> metadata_device_;
275   bool target_supports_snapshot_ = false;
276   // Whether the target partitions should be loaded as dynamic partitions. Set
277   // by PreparePartitionsForUpdate() per each update.
278   bool is_target_dynamic_ = false;
279   uint32_t source_slot_ = UINT32_MAX;
280   uint32_t target_slot_ = UINT32_MAX;
281 
282   DISALLOW_COPY_AND_ASSIGN(DynamicPartitionControlAndroid);
283 };
284 
285 }  // namespace chromeos_update_engine
286 
287 #endif  // UPDATE_ENGINE_DYNAMIC_PARTITION_CONTROL_ANDROID_H_
288