xref: /aosp_15_r20/system/update_engine/aosp/dynamic_partition_control_android_unittest.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1 //
2 // Copyright (C) 2019 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 #include "update_engine/aosp/dynamic_partition_control_android.h"
18 
19 #include <set>
20 
21 #include <base/logging.h>
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24 #include <libavb/libavb.h>
25 #include <libsnapshot/mock_snapshot.h>
26 
27 #include "update_engine/aosp/boot_control_android.h"
28 #include "update_engine/aosp/dynamic_partition_test_utils.h"
29 #include "update_engine/aosp/mock_dynamic_partition_control_android.h"
30 #include "update_engine/common/mock_prefs.h"
31 #include "update_engine/common/test_utils.h"
32 
33 using android::dm::DmDeviceState;
34 using android::snapshot::MockSnapshotManager;
35 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
36 using std::string;
37 using testing::_;
38 using testing::AnyNumber;
39 using testing::AnyOf;
40 using testing::AtLeast;
41 using testing::Invoke;
42 using testing::NiceMock;
43 using testing::Not;
44 using testing::Optional;
45 using testing::Return;
46 
47 namespace chromeos_update_engine {
48 
49 class DynamicPartitionControlAndroidTest : public ::testing::Test {
50  public:
SetUp()51   void SetUp() override {
52     module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
53 
54     ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
55         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
56     ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
57         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
58     ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
59         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
60     ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
61         .WillByDefault(Return(false));
62     ON_CALL(dynamicControl(), GetDeviceDir(_))
63         .WillByDefault(Invoke([](auto path) {
64           *path = kFakeDevicePath;
65           return true;
66         }));
67 
68     ON_CALL(dynamicControl(), GetSuperPartitionName(_))
69         .WillByDefault(Return(kFakeSuper));
70 
71     ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
72         .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
73           *device = GetDmDevice(partition_name_suffix);
74           return true;
75         }));
76 
77     ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
78         .WillByDefault(Return(true));
79 
80     ON_CALL(dynamicControl(), IsRecovery()).WillByDefault(Return(false));
81 
82     ON_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
83         .WillByDefault(Invoke([&](uint32_t source_slot,
84                                   uint32_t target_slot,
85                                   const DeltaArchiveManifest& manifest,
86                                   bool delete_source) {
87           return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
88               source_slot, target_slot, manifest, delete_source);
89         }));
90   }
91 
92   // Return the mocked DynamicPartitionControlInterface.
dynamicControl()93   NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
94     return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
95   }
96 
GetSuperDevice(uint32_t slot)97   std::string GetSuperDevice(uint32_t slot) {
98     return GetDevice(dynamicControl().GetSuperPartitionName(slot));
99   }
100 
source()101   uint32_t source() { return slots_.source; }
target()102   uint32_t target() { return slots_.target; }
103 
104   // Return partition names with suffix of source().
S(const std::string & name)105   std::string S(const std::string& name) {
106     return name + kSlotSuffixes[source()];
107   }
108 
109   // Return partition names with suffix of target().
T(const std::string & name)110   std::string T(const std::string& name) {
111     return name + kSlotSuffixes[target()];
112   }
113 
114   // Set the fake metadata to return when LoadMetadataBuilder is called on
115   // |slot|.
SetMetadata(uint32_t slot,const PartitionSuffixSizes & sizes,uint32_t partition_attr=0,uint64_t super_size=kDefaultSuperSize)116   void SetMetadata(uint32_t slot,
117                    const PartitionSuffixSizes& sizes,
118                    uint32_t partition_attr = 0,
119                    uint64_t super_size = kDefaultSuperSize) {
120     EXPECT_CALL(dynamicControl(),
121                 LoadMetadataBuilder(GetSuperDevice(slot), slot))
122         .Times(AnyNumber())
123         .WillRepeatedly(Invoke([=](auto, auto) {
124           return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
125                                  partition_attr,
126                                  super_size);
127         }));
128 
129     EXPECT_CALL(dynamicControl(),
130                 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
131         .Times(AnyNumber())
132         .WillRepeatedly(Invoke([=](auto, auto, auto) {
133           return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
134                                  partition_attr,
135                                  super_size);
136         }));
137   }
138 
ExpectStoreMetadata(const PartitionSuffixSizes & partition_sizes)139   void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
140     EXPECT_CALL(dynamicControl(),
141                 StoreMetadata(GetSuperDevice(target()),
142                               MetadataMatches(partition_sizes),
143                               target()))
144         .WillOnce(Return(true));
145   }
146 
147   // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
148   // slot with each partition in |partitions|.
ExpectUnmap(const std::set<std::string> & partitions)149   void ExpectUnmap(const std::set<std::string>& partitions) {
150     // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
151     ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
152         .WillByDefault(Return(false));
153 
154     for (const auto& partition : partitions) {
155       EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
156           .WillOnce(Return(true));
157     }
158   }
PreparePartitionsForUpdate(const PartitionSizes & partition_sizes)159   bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
160     return dynamicControl().PreparePartitionsForUpdate(
161         source(),
162         target(),
163         PartitionSizesToManifest(partition_sizes),
164         true,
165         nullptr,
166         nullptr);
167   }
SetSlots(const TestParam & slots)168   void SetSlots(const TestParam& slots) { slots_ = slots; }
169 
SetSnapshotEnabled(bool enabled)170   void SetSnapshotEnabled(bool enabled) {
171     dynamicControl().target_supports_snapshot_ = enabled;
172   }
173 
174   struct Listener : public ::testing::MatchResultListener {
Listenerchromeos_update_engine::DynamicPartitionControlAndroidTest::Listener175     explicit Listener(std::ostream* os) : MatchResultListener(os) {}
176   };
177 
UpdatePartitionMetadata(const PartitionSuffixSizes & source_metadata,const PartitionSizes & update_metadata,const PartitionSuffixSizes & expected)178   testing::AssertionResult UpdatePartitionMetadata(
179       const PartitionSuffixSizes& source_metadata,
180       const PartitionSizes& update_metadata,
181       const PartitionSuffixSizes& expected) {
182     return UpdatePartitionMetadata(
183         PartitionSuffixSizesToManifest(source_metadata),
184         PartitionSizesToManifest(update_metadata),
185         PartitionSuffixSizesToManifest(expected));
186   }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const DeltaArchiveManifest & expected)187   testing::AssertionResult UpdatePartitionMetadata(
188       const DeltaArchiveManifest& source_manifest,
189       const DeltaArchiveManifest& update_manifest,
190       const DeltaArchiveManifest& expected) {
191     return UpdatePartitionMetadata(
192         source_manifest, update_manifest, MetadataMatches(expected));
193   }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const Matcher<MetadataBuilder * > & matcher)194   testing::AssertionResult UpdatePartitionMetadata(
195       const DeltaArchiveManifest& source_manifest,
196       const DeltaArchiveManifest& update_manifest,
197       const Matcher<MetadataBuilder*>& matcher) {
198     auto super_metadata = NewFakeMetadata(source_manifest);
199     if (!module_->UpdatePartitionMetadata(
200             super_metadata.get(), target(), update_manifest)) {
201       return testing::AssertionFailure()
202              << "UpdatePartitionMetadataInternal failed";
203     }
204     std::stringstream ss;
205     Listener listener(&ss);
206     if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
207       return testing::AssertionSuccess() << ss.str();
208     } else {
209       return testing::AssertionFailure() << ss.str();
210     }
211   }
212 
213   std::unique_ptr<DynamicPartitionControlAndroid> module_;
214   TestParam slots_{};
215 };
216 
217 class DynamicPartitionControlAndroidTestP
218     : public DynamicPartitionControlAndroidTest,
219       public ::testing::WithParamInterface<TestParam> {
220  public:
SetUp()221   void SetUp() override {
222     DynamicPartitionControlAndroidTest::SetUp();
223     SetSlots(GetParam());
224     dynamicControl().SetSourceSlot(source());
225     dynamicControl().SetTargetSlot(target());
226   }
227 };
228 
229 // Test resize case. Grow if target metadata contains a partition with a size
230 // less than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedGrowIfSizeNotMatchWhenResizing)231 TEST_P(DynamicPartitionControlAndroidTestP,
232        NeedGrowIfSizeNotMatchWhenResizing) {
233   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
234                                        {S("vendor"), 1_GiB},
235                                        {T("system"), 2_GiB},
236                                        {T("vendor"), 1_GiB}};
237   PartitionSuffixSizes expected{{S("system"), 2_GiB},
238                                 {S("vendor"), 1_GiB},
239                                 {T("system"), 3_GiB},
240                                 {T("vendor"), 1_GiB}};
241   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
242   ASSERT_TRUE(
243       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
244 }
245 
246 // Test resize case. Shrink if target metadata contains a partition with a size
247 // greater than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedShrinkIfSizeNotMatchWhenResizing)248 TEST_P(DynamicPartitionControlAndroidTestP,
249        NeedShrinkIfSizeNotMatchWhenResizing) {
250   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
251                                        {S("vendor"), 1_GiB},
252                                        {T("system"), 2_GiB},
253                                        {T("vendor"), 1_GiB}};
254   PartitionSuffixSizes expected{{S("system"), 2_GiB},
255                                 {S("vendor"), 1_GiB},
256                                 {T("system"), 2_GiB},
257                                 {T("vendor"), 150_MiB}};
258   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
259   ASSERT_TRUE(
260       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
261 }
262 
263 // Test adding partitions on the first run.
TEST_P(DynamicPartitionControlAndroidTestP,AddPartitionToEmptyMetadata)264 TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
265   PartitionSuffixSizes source_metadata{};
266   PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
267   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
268   ASSERT_TRUE(
269       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
270 }
271 
272 // Test subsequent add case.
TEST_P(DynamicPartitionControlAndroidTestP,AddAdditionalPartition)273 TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
274   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
275                                        {T("system"), 2_GiB}};
276   PartitionSuffixSizes expected{
277       {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
278   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
279   ASSERT_TRUE(
280       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
281 }
282 
283 // Test delete one partition.
TEST_P(DynamicPartitionControlAndroidTestP,DeletePartition)284 TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
285   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
286                                        {S("vendor"), 1_GiB},
287                                        {T("system"), 2_GiB},
288                                        {T("vendor"), 1_GiB}};
289   // No T("vendor")
290   PartitionSuffixSizes expected{
291       {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
292   PartitionSizes update_metadata{{"system", 2_GiB}};
293   ASSERT_TRUE(
294       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
295 }
296 
297 // Test delete all partitions.
TEST_P(DynamicPartitionControlAndroidTestP,DeleteAll)298 TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
299   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
300                                        {S("vendor"), 1_GiB},
301                                        {T("system"), 2_GiB},
302                                        {T("vendor"), 1_GiB}};
303   PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
304   PartitionSizes update_metadata{};
305   ASSERT_TRUE(
306       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
307 }
308 
309 // Test corrupt source metadata case.
TEST_P(DynamicPartitionControlAndroidTestP,CorruptedSourceMetadata)310 TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
311   EXPECT_CALL(dynamicControl(),
312               LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
313       .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
314   ExpectUnmap({T("system")});
315 
316   ASSERT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
317       << "Should not be able to continue with corrupt source metadata";
318 }
319 
320 // Test that UpdatePartitionMetadata fails if there is not enough space on the
321 // device.
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpace)322 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
323   PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
324                                        {S("vendor"), 2_GiB},
325                                        {T("system"), 0},
326                                        {T("vendor"), 0}};
327   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
328 
329   ASSERT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
330       << "Should not be able to fit 11GiB data into 10GiB space";
331 }
332 
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpaceForSlot)333 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
334   PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
335                                        {S("vendor"), 1_GiB},
336                                        {T("system"), 0},
337                                        {T("vendor"), 0}};
338   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
339   ASSERT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
340       << "Should not be able to grow over size of super / 2";
341 }
342 
TEST_P(DynamicPartitionControlAndroidTestP,ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild)343 TEST_P(DynamicPartitionControlAndroidTestP,
344        ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
345   ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
346       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
347   // Static partition {system,bar}_{a,b} exists.
348   EXPECT_CALL(dynamicControl(),
349               DeviceExists(AnyOf(GetDevice(S("bar")),
350                                  GetDevice(T("bar")),
351                                  GetDevice(S("system")),
352                                  GetDevice(T("system")))))
353       .WillRepeatedly(Return(true));
354 
355   SetMetadata(source(),
356               {{S("system"), 2_GiB},
357                {S("vendor"), 1_GiB},
358                {T("system"), 2_GiB},
359                {T("vendor"), 1_GiB}});
360 
361   // Not calling through
362   // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
363   // don't want any default group in the PartitionMetadata.
364   ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
365       source(), target(), {}, true, nullptr, nullptr));
366 
367   // Should use dynamic source partitions.
368   EXPECT_CALL(dynamicControl(), GetState(S("system") + "_ota"))
369       .Times(1)
370       .WillOnce(Return(DmDeviceState::ACTIVE));
371   string system_device;
372   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
373       "system", source(), source(), &system_device));
374   ASSERT_EQ(GetDmDevice(S("system") + "_ota"), system_device);
375 
376   // Should use static target partitions without querying dynamic control.
377   EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
378   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
379       "system", target(), source(), &system_device));
380   ASSERT_EQ(GetDevice(T("system")), system_device);
381 
382   // Static partition "bar".
383   EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
384   std::string bar_device;
385   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
386       "bar", source(), source(), &bar_device));
387   ASSERT_EQ(GetDevice(S("bar")), bar_device);
388 
389   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
390   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
391       "bar", target(), source(), &bar_device));
392   ASSERT_EQ(GetDevice(T("bar")), bar_device);
393 }
394 
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePath)395 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePath) {
396   ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
397       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
398   ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
399       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
400   ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
401       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
402   ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
403       .WillByDefault(Return(false));
404   ON_CALL(dynamicControl(), IsDynamicPartition(_, _))
405       .WillByDefault(Return(true));
406 
407   EXPECT_CALL(dynamicControl(),
408               DeviceExists(AnyOf(GetDevice(S("vendor")),
409                                  GetDevice(T("vendor")),
410                                  GetDevice(S("system")),
411                                  GetDevice(T("system")))))
412       .WillRepeatedly(Return(true));
413   EXPECT_CALL(dynamicControl(),
414               GetState(AnyOf(
415                   S("vendor"), T("vendor"), S("system") + "_ota", T("system"))))
416       .WillRepeatedly(Return(DmDeviceState::ACTIVE));
417 
418   SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
419   SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
420   std::string device;
421   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
422       "system", source(), source(), &device));
423   ASSERT_EQ(GetDmDevice(S("system") + "_ota"), device);
424 
425   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
426       "system", target(), source(), &device));
427   ASSERT_EQ(GetDevice(T("system")), device);
428 
429   // If VABC is disabled, mountable device path should be same as device path.
430   auto device_info =
431       dynamicControl().GetPartitionDevice("system", target(), source(), false);
432   ASSERT_TRUE(device_info.has_value());
433   ASSERT_EQ(device_info->readonly_device_path, device);
434 }
435 
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePathVABC)436 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePathVABC) {
437   ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
438       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
439   ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
440       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
441   ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
442       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
443   ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
444       .WillByDefault(Return(true));
445   EXPECT_CALL(dynamicControl(), IsDynamicPartition(_, _))
446       .Times(AtLeast(1))
447       .WillRepeatedly(Return(true));
448 
449   EXPECT_CALL(dynamicControl(),
450               DeviceExists(AnyOf(GetDevice(S("vendor")),
451                                  GetDevice(T("vendor")),
452                                  GetDevice(S("system")),
453                                  GetDevice(T("system")))))
454       .WillRepeatedly(Return(true));
455   EXPECT_CALL(dynamicControl(),
456               GetState(AnyOf(
457                   S("vendor"), T("vendor"), S("system") + "_ota", T("system"))))
458       .WillRepeatedly(Return(DmDeviceState::ACTIVE));
459 
460   SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
461   SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
462 
463   std::string device;
464   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
465       "system", source(), source(), &device));
466   ASSERT_EQ(GetDmDevice(S("system") + "_ota"), device);
467 
468   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
469       "system", target(), source(), &device));
470   ASSERT_EQ("", device);
471 
472   auto device_info =
473       dynamicControl().GetPartitionDevice("system", target(), source(), false);
474   ASSERT_TRUE(device_info.has_value());
475   base::FilePath vabc_device_dir{
476       std::string{DynamicPartitionControlAndroid::VABC_DEVICE_DIR}};
477   ASSERT_EQ(device_info->readonly_device_path,
478             vabc_device_dir.Append(T("system")).value());
479 }
480 
TEST_P(DynamicPartitionControlAndroidTestP,GetPartitionDeviceWhenResumingUpdate)481 TEST_P(DynamicPartitionControlAndroidTestP,
482        GetPartitionDeviceWhenResumingUpdate) {
483   // Static partition bar_{a,b} exists.
484   EXPECT_CALL(dynamicControl(),
485               DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
486       .WillRepeatedly(Return(true));
487 
488   // Both of the two slots contain valid partition metadata, since this is
489   // resuming an update.
490   SetMetadata(source(),
491               {{S("system"), 2_GiB},
492                {S("vendor"), 1_GiB},
493                {T("system"), 2_GiB},
494                {T("vendor"), 1_GiB}});
495   SetMetadata(target(),
496               {{S("system"), 2_GiB},
497                {S("vendor"), 1_GiB},
498                {T("system"), 2_GiB},
499                {T("vendor"), 1_GiB}});
500 
501   ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
502       source(),
503       target(),
504       PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
505       false,
506       nullptr,
507       nullptr));
508 
509   // Dynamic partition "system".
510   EXPECT_CALL(dynamicControl(), GetState(S("system") + "_ota"))
511       .Times(1)
512       .WillOnce(Return(DmDeviceState::ACTIVE));
513   string system_device;
514   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
515       "system", source(), source(), &system_device));
516   ASSERT_EQ(GetDmDevice(S("system") + "_ota"), system_device);
517 
518   EXPECT_CALL(dynamicControl(), GetState(T("system")))
519       .Times(AnyNumber())
520       .WillOnce(Return(DmDeviceState::ACTIVE));
521   EXPECT_CALL(dynamicControl(),
522               MapPartitionOnDeviceMapper(
523                   GetSuperDevice(target()), T("system"), target(), _, _))
524       .Times(AnyNumber())
525       .WillRepeatedly(
526           Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
527             *device = "/fake/remapped/" + name;
528             return true;
529           }));
530   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
531       "system", target(), source(), &system_device));
532   ASSERT_EQ("/fake/remapped/" + T("system"), system_device);
533 
534   // Static partition "bar".
535   EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
536   std::string bar_device;
537   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
538       "bar", source(), source(), &bar_device));
539   ASSERT_EQ(GetDevice(S("bar")), bar_device);
540 
541   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
542   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
543       "bar", target(), source(), &bar_device));
544   ASSERT_EQ(GetDevice(T("bar")), bar_device);
545 }
546 
547 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
548                         DynamicPartitionControlAndroidTestP,
549                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
550 
551 class DynamicPartitionControlAndroidGroupTestP
552     : public DynamicPartitionControlAndroidTestP {
553  public:
554   DeltaArchiveManifest source_manifest;
SetUp()555   void SetUp() override {
556     DynamicPartitionControlAndroidTestP::SetUp();
557     AddGroupAndPartition(
558         &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
559     AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
560     AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
561     AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
562   }
563 
AddGroupAndPartition(DeltaArchiveManifest * manifest,const string & group,uint64_t group_size,const string & partition,uint64_t partition_size)564   void AddGroupAndPartition(DeltaArchiveManifest* manifest,
565                             const string& group,
566                             uint64_t group_size,
567                             const string& partition,
568                             uint64_t partition_size) {
569     auto* g = AddGroup(manifest, group, group_size);
570     AddPartition(manifest, g, partition, partition_size);
571   }
572 };
573 
574 // Allow to resize within group.
TEST_P(DynamicPartitionControlAndroidGroupTestP,ResizeWithinGroup)575 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
576   DeltaArchiveManifest expected;
577   AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
578   AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
579 
580   DeltaArchiveManifest update_manifest;
581   AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
582   AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
583 
584   ASSERT_TRUE(
585       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
586 }
587 
TEST_P(DynamicPartitionControlAndroidGroupTestP,NotEnoughSpaceForGroup)588 TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
589   DeltaArchiveManifest update_manifest;
590   AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
591       AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
592   ASSERT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
593       << "Should not be able to grow over maximum size of group";
594 }
595 
TEST_P(DynamicPartitionControlAndroidGroupTestP,GroupTooBig)596 TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
597   DeltaArchiveManifest update_manifest;
598   AddGroup(&update_manifest, "android", 3_GiB);
599   AddGroup(&update_manifest, "oem", 3_GiB);
600   ASSERT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
601       << "Should not be able to grow over size of super / 2";
602 }
603 
TEST_P(DynamicPartitionControlAndroidGroupTestP,AddPartitionToGroup)604 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
605   DeltaArchiveManifest expected;
606   auto* g = AddGroup(&expected, T("android"), 3_GiB);
607   AddPartition(&expected, g, T("system"), 2_GiB);
608   AddPartition(&expected, g, T("system_ext"), 1_GiB);
609 
610   DeltaArchiveManifest update_manifest;
611   g = AddGroup(&update_manifest, "android", 3_GiB);
612   AddPartition(&update_manifest, g, "system", 2_GiB);
613   AddPartition(&update_manifest, g, "system_ext", 1_GiB);
614   AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
615 
616   ASSERT_TRUE(
617       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
618 }
619 
TEST_P(DynamicPartitionControlAndroidGroupTestP,RemovePartitionFromGroup)620 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
621   DeltaArchiveManifest expected;
622   AddGroup(&expected, T("android"), 3_GiB);
623 
624   DeltaArchiveManifest update_manifest;
625   AddGroup(&update_manifest, "android", 3_GiB);
626   AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
627 
628   ASSERT_TRUE(
629       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
630 }
631 
TEST_P(DynamicPartitionControlAndroidGroupTestP,AddGroup)632 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
633   DeltaArchiveManifest expected;
634   AddGroupAndPartition(
635       &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
636 
637   DeltaArchiveManifest update_manifest;
638   AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
639   AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
640   AddGroupAndPartition(
641       &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
642   ASSERT_TRUE(
643       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
644 }
645 
TEST_P(DynamicPartitionControlAndroidGroupTestP,RemoveGroup)646 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
647   DeltaArchiveManifest update_manifest;
648   AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
649 
650   ASSERT_TRUE(UpdatePartitionMetadata(
651       source_manifest, update_manifest, Not(HasGroup(T("oem")))));
652 }
653 
TEST_P(DynamicPartitionControlAndroidGroupTestP,ResizeGroup)654 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
655   DeltaArchiveManifest expected;
656   AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
657   AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
658   DeltaArchiveManifest update_manifest;
659   AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
660       AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
661   ASSERT_TRUE(
662       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
663 }
664 
665 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
666                         DynamicPartitionControlAndroidGroupTestP,
667                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
668 
update_sizes_0()669 const PartitionSuffixSizes update_sizes_0() {
670   // Initial state is 0 for "other" slot.
671   return {
672       {"grown_a", 2_GiB},
673       {"shrunk_a", 1_GiB},
674       {"same_a", 100_MiB},
675       {"deleted_a", 150_MiB},
676       // no added_a
677       {"grown_b", 200_MiB},
678       // simulate system_other
679       {"shrunk_b", 0},
680       {"same_b", 0},
681       {"deleted_b", 0},
682       // no added_b
683   };
684 }
685 
update_sizes_1()686 const PartitionSuffixSizes update_sizes_1() {
687   return {
688       {"grown_a", 2_GiB},
689       {"shrunk_a", 1_GiB},
690       {"same_a", 100_MiB},
691       {"deleted_a", 150_MiB},
692       // no added_a
693       {"grown_b", 3_GiB},
694       {"shrunk_b", 150_MiB},
695       {"same_b", 100_MiB},
696       {"added_b", 150_MiB},
697       // no deleted_b
698   };
699 }
700 
update_sizes_2()701 const PartitionSuffixSizes update_sizes_2() {
702   return {
703       {"grown_a", 4_GiB},
704       {"shrunk_a", 100_MiB},
705       {"same_a", 100_MiB},
706       {"deleted_a", 64_MiB},
707       // no added_a
708       {"grown_b", 3_GiB},
709       {"shrunk_b", 150_MiB},
710       {"same_b", 100_MiB},
711       {"added_b", 150_MiB},
712       // no deleted_b
713   };
714 }
715 
716 // Test case for first update after the device is manufactured, in which
717 // case the "other" slot is likely of size "0" (except system, which is
718 // non-zero because of system_other partition)
TEST_F(DynamicPartitionControlAndroidTest,SimulatedFirstUpdate)719 TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
720   SetSlots({0, 1});
721 
722   SetMetadata(source(), update_sizes_0());
723   SetMetadata(target(), update_sizes_0());
724   ExpectStoreMetadata(update_sizes_1());
725   ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
726 
727   ASSERT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
728                                           {"shrunk", 150_MiB},
729                                           {"same", 100_MiB},
730                                           {"added", 150_MiB}}));
731 }
732 
733 // After first update, test for the second update. In the second update, the
734 // "added" partition is deleted and "deleted" partition is re-added.
TEST_F(DynamicPartitionControlAndroidTest,SimulatedSecondUpdate)735 TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
736   SetSlots({1, 0});
737 
738   SetMetadata(source(), update_sizes_1());
739   SetMetadata(target(), update_sizes_0());
740 
741   ExpectStoreMetadata(update_sizes_2());
742   ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
743 
744   ASSERT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
745                                           {"shrunk", 100_MiB},
746                                           {"same", 100_MiB},
747                                           {"deleted", 64_MiB}}));
748 }
749 
TEST_F(DynamicPartitionControlAndroidTest,ApplyingToCurrentSlot)750 TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
751   SetSlots({1, 1});
752   ASSERT_FALSE(PreparePartitionsForUpdate({}))
753       << "Should not be able to apply to current slot.";
754 }
755 
TEST_P(DynamicPartitionControlAndroidTestP,OptimizeOperationTest)756 TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
757   ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
758       source(),
759       target(),
760       PartitionSizesToManifest({{"foo", 4_MiB}}),
761       false,
762       nullptr,
763       nullptr));
764   dynamicControl().set_fake_mapped_devices({T("foo")});
765 
766   InstallOperation iop;
767   InstallOperation optimized;
768   Extent *se{}, *de{};
769 
770   // Not a SOURCE_COPY operation, cannot skip.
771   iop.set_type(InstallOperation::REPLACE);
772   ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
773 
774   iop.set_type(InstallOperation::SOURCE_COPY);
775 
776   // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
777   ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
778 
779   // Enable GetVirtualAbFeatureFlag in the mock interface.
780   ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
781       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
782 
783   // By default target_supports_snapshot_ is set to false. Cannot skip
784   // operation.
785   ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
786 
787   SetSnapshotEnabled(true);
788 
789   // Empty source and destination. Skip.
790   ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
791   ASSERT_TRUE(optimized.src_extents().empty());
792   ASSERT_TRUE(optimized.dst_extents().empty());
793 
794   se = iop.add_src_extents();
795   se->set_start_block(0);
796   se->set_num_blocks(1);
797 
798   // There is something in sources, but destinations are empty. Cannot skip.
799   ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
800 
801   InstallOperation iop2;
802 
803   de = iop2.add_dst_extents();
804   de->set_start_block(0);
805   de->set_num_blocks(1);
806 
807   // There is something in destinations, but sources are empty. Cannot skip.
808   ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
809 
810   de = iop.add_dst_extents();
811   de->set_start_block(0);
812   de->set_num_blocks(1);
813 
814   // Sources and destinations are identical. Skip.
815   ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
816   ASSERT_TRUE(optimized.src_extents().empty());
817   ASSERT_TRUE(optimized.dst_extents().empty());
818 
819   se = iop.add_src_extents();
820   se->set_start_block(1);
821   se->set_num_blocks(5);
822 
823   // There is something in source, but not in destination. Cannot skip.
824   ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
825 
826   de = iop.add_dst_extents();
827   de->set_start_block(1);
828   de->set_num_blocks(5);
829 
830   // There is source and destination are equal. Skip.
831   ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
832   ASSERT_TRUE(optimized.src_extents().empty());
833   ASSERT_TRUE(optimized.dst_extents().empty());
834 
835   de = iop.add_dst_extents();
836   de->set_start_block(6);
837   de->set_num_blocks(5);
838 
839   // There is something extra in dest. Cannot skip.
840   ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
841 
842   se = iop.add_src_extents();
843   se->set_start_block(6);
844   se->set_num_blocks(5);
845 
846   // Source and dest are identical again. Skip.
847   ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
848   ASSERT_TRUE(optimized.src_extents().empty());
849   ASSERT_TRUE(optimized.dst_extents().empty());
850 
851   iop.Clear();
852   iop.set_type(InstallOperation::SOURCE_COPY);
853   se = iop.add_src_extents();
854   se->set_start_block(1);
855   se->set_num_blocks(1);
856   se = iop.add_src_extents();
857   se->set_start_block(3);
858   se->set_num_blocks(2);
859   se = iop.add_src_extents();
860   se->set_start_block(7);
861   se->set_num_blocks(2);
862   de = iop.add_dst_extents();
863   de->set_start_block(2);
864   de->set_num_blocks(5);
865 
866   // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
867   ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
868   ASSERT_EQ(2, optimized.src_extents_size());
869   ASSERT_EQ(2, optimized.dst_extents_size());
870   ASSERT_EQ(1u, optimized.src_extents(0).start_block());
871   ASSERT_EQ(1u, optimized.src_extents(0).num_blocks());
872   ASSERT_EQ(2u, optimized.dst_extents(0).start_block());
873   ASSERT_EQ(1u, optimized.dst_extents(0).num_blocks());
874   ASSERT_EQ(7u, optimized.src_extents(1).start_block());
875   ASSERT_EQ(2u, optimized.src_extents(1).num_blocks());
876   ASSERT_EQ(5u, optimized.dst_extents(1).start_block());
877   ASSERT_EQ(2u, optimized.dst_extents(1).num_blocks());
878 
879   // Don't skip for static partitions.
880   ASSERT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
881 }
882 
TEST_F(DynamicPartitionControlAndroidTest,ResetUpdate)883 TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
884   MockPrefs prefs;
885   ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
886 }
887 
TEST_F(DynamicPartitionControlAndroidTest,IsAvbNotEnabledInFstab)888 TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
889   std::string fstab_content =
890       "system /postinstall ext4 ro,nosuid,nodev,noexec "
891       "slotselect_other,logical\n"
892       "/dev/block/by-name/system /postinstall ext4 "
893       "ro,nosuid,nodev,noexec slotselect_other\n";
894   ScopedTempFile fstab;
895   ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
896   ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
897               Optional(false));
898 }
899 
TEST_F(DynamicPartitionControlAndroidTest,IsAvbEnabledInFstab)900 TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
901   std::string fstab_content =
902       "system /postinstall ext4 ro,nosuid,nodev,noexec "
903       "slotselect_other,logical,avb_keys=/foo\n";
904   ScopedTempFile fstab;
905   ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
906   ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
907               Optional(true));
908 }
909 
TEST_P(DynamicPartitionControlAndroidTestP,AvbNotEnabledOnSystemOther)910 TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
911   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
912       .WillByDefault(Invoke([&](auto source_slot,
913                                 auto target_slot,
914                                 const auto& name,
915                                 auto path,
916                                 auto should_unmap) {
917         return dynamicControl().RealGetSystemOtherPath(
918             source_slot, target_slot, name, path, should_unmap);
919       }));
920   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
921       .WillByDefault(Return(false));
922   ASSERT_TRUE(
923       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
924 }
925 
TEST_P(DynamicPartitionControlAndroidTestP,NoSystemOtherToErase)926 TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
927   SetMetadata(source(), {{S("system"), 100_MiB}});
928   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
929       .WillByDefault(Return(true));
930   std::string path;
931   bool should_unmap{};
932   ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
933       source(), target(), T("system"), &path, &should_unmap));
934   ASSERT_TRUE(path.empty()) << path;
935   ASSERT_FALSE(should_unmap);
936   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
937       .WillByDefault(Invoke([&](auto source_slot,
938                                 auto target_slot,
939                                 const auto& name,
940                                 auto path,
941                                 auto should_unmap) {
942         return dynamicControl().RealGetSystemOtherPath(
943             source_slot, target_slot, name, path, should_unmap);
944       }));
945   ASSERT_TRUE(
946       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
947 }
948 
TEST_P(DynamicPartitionControlAndroidTestP,SkipEraseUpdatedSystemOther)949 TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
950   PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
951   SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
952   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
953       .WillByDefault(Return(true));
954   std::string path;
955   bool should_unmap{};
956   ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
957       source(), target(), T("system"), &path, &should_unmap));
958   ASSERT_TRUE(path.empty()) << path;
959   ASSERT_FALSE(should_unmap);
960   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
961       .WillByDefault(Invoke([&](auto source_slot,
962                                 auto target_slot,
963                                 const auto& name,
964                                 auto path,
965                                 auto should_unmap) {
966         return dynamicControl().RealGetSystemOtherPath(
967             source_slot, target_slot, name, path, should_unmap);
968       }));
969   ASSERT_TRUE(
970       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
971 }
972 
TEST_P(DynamicPartitionControlAndroidTestP,EraseSystemOtherAvbFooter)973 TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
974   constexpr uint64_t file_size = 1_MiB;
975   static_assert(file_size > AVB_FOOTER_SIZE);
976   ScopedTempFile system_other;
977   brillo::Blob original(file_size, 'X');
978   ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
979   std::string mnt_path;
980   ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
981   ASSERT_TRUE(dev.is_bound());
982 
983   brillo::Blob device_content;
984   ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
985   ASSERT_EQ(original, device_content);
986 
987   PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
988   SetMetadata(source(), sizes);
989   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
990       .WillByDefault(Return(true));
991   EXPECT_CALL(dynamicControl(),
992               GetSystemOtherPath(source(), target(), T("system"), _, _))
993       .WillRepeatedly(
994           Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
995             *path = mnt_path;
996             *should_unmap = false;
997             return true;
998           }));
999   ASSERT_TRUE(
1000       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
1001 
1002   device_content.clear();
1003   ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
1004   brillo::Blob new_expected(original);
1005   // Clear the last AVB_FOOTER_SIZE bytes.
1006   new_expected.resize(file_size - AVB_FOOTER_SIZE);
1007   new_expected.resize(file_size, '\0');
1008   ASSERT_EQ(new_expected, device_content);
1009 }
1010 
1011 class FakeAutoDevice : public android::snapshot::AutoDevice {
1012  public:
FakeAutoDevice()1013   FakeAutoDevice() : AutoDevice("") {}
1014 };
1015 
1016 class SnapshotPartitionTestP : public DynamicPartitionControlAndroidTestP {
1017  public:
SetUp()1018   void SetUp() override {
1019     DynamicPartitionControlAndroidTestP::SetUp();
1020     ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
1021         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
1022 
1023     snapshot_ = new NiceMock<MockSnapshotManager>();
1024     dynamicControl().snapshot_.reset(snapshot_);  // takes ownership
1025     EXPECT_CALL(*snapshot_, BeginUpdate()).WillOnce(Return(true));
1026     EXPECT_CALL(*snapshot_, EnsureMetadataMounted())
1027         .WillRepeatedly(
1028             Invoke([]() { return std::make_unique<FakeAutoDevice>(); }));
1029 
1030     manifest_ =
1031         PartitionSizesToManifest({{"system", 3_GiB}, {"vendor", 1_GiB}});
1032   }
ExpectCreateUpdateSnapshots(android::snapshot::Return val)1033   void ExpectCreateUpdateSnapshots(android::snapshot::Return val) {
1034     manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
1035     EXPECT_CALL(*snapshot_, CreateUpdateSnapshots(_))
1036         .WillRepeatedly(Invoke([&, val](const auto& manifest) {
1037           // Deep comparison requires full protobuf library. Comparing the
1038           // pointers are sufficient.
1039           EXPECT_EQ(&manifest_, &manifest);
1040           LOG(WARNING) << "CreateUpdateSnapshots returning " << val.string();
1041           return val;
1042         }));
1043   }
PreparePartitionsForUpdate(uint64_t * required_size)1044   bool PreparePartitionsForUpdate(uint64_t* required_size) {
1045     return dynamicControl().PreparePartitionsForUpdate(source(),
1046                                                        target(),
1047                                                        manifest_,
1048                                                        true /* update */,
1049                                                        required_size,
1050                                                        nullptr);
1051   }
1052   MockSnapshotManager* snapshot_ = nullptr;
1053   DeltaArchiveManifest manifest_;
1054 };
1055 
1056 // Test happy path of PreparePartitionsForUpdate on a Virtual A/B device.
TEST_P(SnapshotPartitionTestP,PreparePartitions)1057 TEST_P(SnapshotPartitionTestP, PreparePartitions) {
1058   ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1059   SetMetadata(source(), {});
1060   uint64_t required_size = 0;
1061   ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
1062   ASSERT_EQ(0u, required_size);
1063 }
1064 
1065 // Test that if not enough space, required size returned by SnapshotManager is
1066 // passed up.
TEST_P(SnapshotPartitionTestP,PreparePartitionsNoSpace)1067 TEST_P(SnapshotPartitionTestP, PreparePartitionsNoSpace) {
1068   ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1069   uint64_t required_size = 0;
1070 
1071   SetMetadata(source(), {});
1072   ASSERT_FALSE(PreparePartitionsForUpdate(&required_size));
1073   ASSERT_EQ(1_GiB, required_size);
1074 }
1075 
1076 // Test that in recovery, use empty space in super partition for a snapshot
1077 // update first.
TEST_P(SnapshotPartitionTestP,RecoveryUseSuperEmpty)1078 TEST_P(SnapshotPartitionTestP, RecoveryUseSuperEmpty) {
1079   ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1080   EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1081 
1082   // Metadata is needed to perform super partition size check.
1083   SetMetadata(source(), {});
1084 
1085   // Must not call PrepareDynamicPartitionsForUpdate if
1086   // PrepareSnapshotPartitionsForUpdate succeeds.
1087   EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1088       .Times(0);
1089   uint64_t required_size = 0;
1090   ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
1091   ASSERT_EQ(0u, required_size);
1092 }
1093 
1094 // Test that in recovery, if CreateUpdateSnapshots throws an error, try
1095 // the flashing path for full updates.
TEST_P(SnapshotPartitionTestP,RecoveryErrorShouldDeleteSource)1096 TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
1097   // Expectation on PreparePartitionsForUpdate
1098   ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1099   EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1100   EXPECT_CALL(*snapshot_, CancelUpdate()).WillOnce(Return(true));
1101   EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1102       .WillRepeatedly(Invoke([&](auto source_slot,
1103                                  auto target_slot,
1104                                  const auto& manifest,
1105                                  auto delete_source) {
1106         EXPECT_EQ(source(), source_slot);
1107         EXPECT_EQ(target(), target_slot);
1108         // Deep comparison requires full protobuf library. Comparing the
1109         // pointers are sufficient.
1110         EXPECT_EQ(&manifest_, &manifest);
1111         EXPECT_TRUE(delete_source);
1112         return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
1113             source_slot, target_slot, manifest, delete_source);
1114       }));
1115   // Only one slot of space in super
1116   uint64_t super_size = kDefaultGroupSize + 1_MiB;
1117   // Expectation on PrepareDynamicPartitionsForUpdate
1118   SetMetadata(
1119       source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size);
1120   ExpectUnmap({T("system"), T("vendor")});
1121   // Expect that the source partitions aren't present in target super
1122   // metadata.
1123   ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
1124 
1125   uint64_t required_size = 0;
1126   ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
1127   ASSERT_EQ(0u, required_size);
1128 }
1129 
1130 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
1131                         SnapshotPartitionTestP,
1132                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
1133 
TEST(SourcePartitionTest,MapSourceWritable)1134 TEST(SourcePartitionTest, MapSourceWritable) {
1135   BootControlAndroid boot_control;
1136   ASSERT_TRUE(boot_control.Init());
1137   auto source_slot = boot_control.GetCurrentSlot();
1138   DynamicPartitionControlAndroid dynamic_control(source_slot);
1139   std::string device;
1140   ASSERT_TRUE(dynamic_control.GetPartitionDevice(
1141       "system", source_slot, source_slot, &device));
1142   android::base::unique_fd fd(open(device.c_str(), O_RDWR | O_CLOEXEC));
1143   ASSERT_TRUE(utils::SetBlockDeviceReadOnly(device, false));
1144   ASSERT_GE(fd, 0) << android::base::ErrnoNumberAsString(errno);
1145   std::array<char, 512> block{};
1146   ASSERT_EQ(pread(fd.get(), block.data(), block.size(), 0),
1147             (ssize_t)block.size())
1148       << android::base::ErrnoNumberAsString(errno);
1149   ASSERT_EQ(pwrite(fd.get(), block.data(), block.size(), 0),
1150             (ssize_t)block.size())
1151       << android::base::ErrnoNumberAsString(errno);
1152 }
1153 
1154 }  // namespace chromeos_update_engine
1155