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 <algorithm>
20 #include <set>
21 #include <vector>
22 
23 #include <base/logging.h>
24 #include <base/strings/string_util.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 #include <libavb/libavb.h>
28 #include <libsnapshot/mock_snapshot.h>
29 
30 #include "update_engine/aosp/dynamic_partition_test_utils.h"
31 #include "update_engine/aosp/mock_dynamic_partition_control_android.h"
32 #include "update_engine/common/mock_prefs.h"
33 #include "update_engine/common/test_utils.h"
34 
35 using android::dm::DmDeviceState;
36 using android::snapshot::MockSnapshotManager;
37 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
38 using std::string;
39 using testing::_;
40 using testing::AnyNumber;
41 using testing::AnyOf;
42 using testing::AtLeast;
43 using testing::Invoke;
44 using testing::NiceMock;
45 using testing::Not;
46 using testing::Optional;
47 using testing::Return;
48 
49 namespace chromeos_update_engine {
50 
51 class DynamicPartitionControlAndroidTest : public ::testing::Test {
52  public:
SetUp()53   void SetUp() override {
54     module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
55 
56     ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
57         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
58     ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
59         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
60     ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
61         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
62     ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
63         .WillByDefault(Return(false));
64     ON_CALL(dynamicControl(), GetDeviceDir(_))
65         .WillByDefault(Invoke([](auto path) {
66           *path = kFakeDevicePath;
67           return true;
68         }));
69 
70     ON_CALL(dynamicControl(), GetSuperPartitionName(_))
71         .WillByDefault(Return(kFakeSuper));
72 
73     ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
74         .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
75           *device = GetDmDevice(partition_name_suffix);
76           return true;
77         }));
78 
79     ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
80         .WillByDefault(Return(true));
81 
82     ON_CALL(dynamicControl(), IsRecovery()).WillByDefault(Return(false));
83 
84     ON_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
85         .WillByDefault(Invoke([&](uint32_t source_slot,
86                                   uint32_t target_slot,
87                                   const DeltaArchiveManifest& manifest,
88                                   bool delete_source) {
89           return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
90               source_slot, target_slot, manifest, delete_source);
91         }));
92   }
93 
94   // Return the mocked DynamicPartitionControlInterface.
dynamicControl()95   NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
96     return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
97   }
98 
GetSuperDevice(uint32_t slot)99   std::string GetSuperDevice(uint32_t slot) {
100     return GetDevice(dynamicControl().GetSuperPartitionName(slot));
101   }
102 
source()103   uint32_t source() { return slots_.source; }
target()104   uint32_t target() { return slots_.target; }
105 
106   // Return partition names with suffix of source().
S(const std::string & name)107   std::string S(const std::string& name) {
108     return name + kSlotSuffixes[source()];
109   }
110 
111   // Return partition names with suffix of target().
T(const std::string & name)112   std::string T(const std::string& name) {
113     return name + kSlotSuffixes[target()];
114   }
115 
116   // Set the fake metadata to return when LoadMetadataBuilder is called on
117   // |slot|.
SetMetadata(uint32_t slot,const PartitionSuffixSizes & sizes,uint32_t partition_attr=0,uint64_t super_size=kDefaultSuperSize)118   void SetMetadata(uint32_t slot,
119                    const PartitionSuffixSizes& sizes,
120                    uint32_t partition_attr = 0,
121                    uint64_t super_size = kDefaultSuperSize) {
122     EXPECT_CALL(dynamicControl(),
123                 LoadMetadataBuilder(GetSuperDevice(slot), slot))
124         .Times(AnyNumber())
125         .WillRepeatedly(Invoke([=](auto, auto) {
126           return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
127                                  partition_attr,
128                                  super_size);
129         }));
130 
131     EXPECT_CALL(dynamicControl(),
132                 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
133         .Times(AnyNumber())
134         .WillRepeatedly(Invoke([=](auto, auto, auto) {
135           return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
136                                  partition_attr,
137                                  super_size);
138         }));
139   }
140 
ExpectStoreMetadata(const PartitionSuffixSizes & partition_sizes)141   void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
142     EXPECT_CALL(dynamicControl(),
143                 StoreMetadata(GetSuperDevice(target()),
144                               MetadataMatches(partition_sizes),
145                               target()))
146         .WillOnce(Return(true));
147   }
148 
149   // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
150   // slot with each partition in |partitions|.
ExpectUnmap(const std::set<std::string> & partitions)151   void ExpectUnmap(const std::set<std::string>& partitions) {
152     // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
153     ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
154         .WillByDefault(Return(false));
155 
156     for (const auto& partition : partitions) {
157       EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
158           .WillOnce(Return(true));
159     }
160   }
PreparePartitionsForUpdate(const PartitionSizes & partition_sizes)161   bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
162     return dynamicControl().PreparePartitionsForUpdate(
163         source(),
164         target(),
165         PartitionSizesToManifest(partition_sizes),
166         true,
167         nullptr);
168   }
SetSlots(const TestParam & slots)169   void SetSlots(const TestParam& slots) { slots_ = slots; }
170 
SetSnapshotEnabled(bool enabled)171   void SetSnapshotEnabled(bool enabled) {
172     dynamicControl().target_supports_snapshot_ = enabled;
173   }
174 
175   struct Listener : public ::testing::MatchResultListener {
Listenerchromeos_update_engine::DynamicPartitionControlAndroidTest::Listener176     explicit Listener(std::ostream* os) : MatchResultListener(os) {}
177   };
178 
UpdatePartitionMetadata(const PartitionSuffixSizes & source_metadata,const PartitionSizes & update_metadata,const PartitionSuffixSizes & expected)179   testing::AssertionResult UpdatePartitionMetadata(
180       const PartitionSuffixSizes& source_metadata,
181       const PartitionSizes& update_metadata,
182       const PartitionSuffixSizes& expected) {
183     return UpdatePartitionMetadata(
184         PartitionSuffixSizesToManifest(source_metadata),
185         PartitionSizesToManifest(update_metadata),
186         PartitionSuffixSizesToManifest(expected));
187   }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const DeltaArchiveManifest & expected)188   testing::AssertionResult UpdatePartitionMetadata(
189       const DeltaArchiveManifest& source_manifest,
190       const DeltaArchiveManifest& update_manifest,
191       const DeltaArchiveManifest& expected) {
192     return UpdatePartitionMetadata(
193         source_manifest, update_manifest, MetadataMatches(expected));
194   }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const Matcher<MetadataBuilder * > & matcher)195   testing::AssertionResult UpdatePartitionMetadata(
196       const DeltaArchiveManifest& source_manifest,
197       const DeltaArchiveManifest& update_manifest,
198       const Matcher<MetadataBuilder*>& matcher) {
199     auto super_metadata = NewFakeMetadata(source_manifest);
200     if (!module_->UpdatePartitionMetadata(
201             super_metadata.get(), target(), update_manifest)) {
202       return testing::AssertionFailure()
203              << "UpdatePartitionMetadataInternal failed";
204     }
205     std::stringstream ss;
206     Listener listener(&ss);
207     if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
208       return testing::AssertionSuccess() << ss.str();
209     } else {
210       return testing::AssertionFailure() << ss.str();
211     }
212   }
213 
214   std::unique_ptr<DynamicPartitionControlAndroid> module_;
215   TestParam slots_;
216 };
217 
218 class DynamicPartitionControlAndroidTestP
219     : public DynamicPartitionControlAndroidTest,
220       public ::testing::WithParamInterface<TestParam> {
221  public:
SetUp()222   void SetUp() override {
223     DynamicPartitionControlAndroidTest::SetUp();
224     SetSlots(GetParam());
225     dynamicControl().SetSourceSlot(source());
226     dynamicControl().SetTargetSlot(target());
227   }
228 };
229 
230 // Test resize case. Grow if target metadata contains a partition with a size
231 // less than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedGrowIfSizeNotMatchWhenResizing)232 TEST_P(DynamicPartitionControlAndroidTestP,
233        NeedGrowIfSizeNotMatchWhenResizing) {
234   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
235                                        {S("vendor"), 1_GiB},
236                                        {T("system"), 2_GiB},
237                                        {T("vendor"), 1_GiB}};
238   PartitionSuffixSizes expected{{S("system"), 2_GiB},
239                                 {S("vendor"), 1_GiB},
240                                 {T("system"), 3_GiB},
241                                 {T("vendor"), 1_GiB}};
242   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
243   EXPECT_TRUE(
244       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
245 }
246 
247 // Test resize case. Shrink if target metadata contains a partition with a size
248 // greater than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedShrinkIfSizeNotMatchWhenResizing)249 TEST_P(DynamicPartitionControlAndroidTestP,
250        NeedShrinkIfSizeNotMatchWhenResizing) {
251   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
252                                        {S("vendor"), 1_GiB},
253                                        {T("system"), 2_GiB},
254                                        {T("vendor"), 1_GiB}};
255   PartitionSuffixSizes expected{{S("system"), 2_GiB},
256                                 {S("vendor"), 1_GiB},
257                                 {T("system"), 2_GiB},
258                                 {T("vendor"), 150_MiB}};
259   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
260   EXPECT_TRUE(
261       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
262 }
263 
264 // Test adding partitions on the first run.
TEST_P(DynamicPartitionControlAndroidTestP,AddPartitionToEmptyMetadata)265 TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
266   PartitionSuffixSizes source_metadata{};
267   PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
268   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
269   EXPECT_TRUE(
270       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
271 }
272 
273 // Test subsequent add case.
TEST_P(DynamicPartitionControlAndroidTestP,AddAdditionalPartition)274 TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
275   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
276                                        {T("system"), 2_GiB}};
277   PartitionSuffixSizes expected{
278       {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
279   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
280   EXPECT_TRUE(
281       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
282 }
283 
284 // Test delete one partition.
TEST_P(DynamicPartitionControlAndroidTestP,DeletePartition)285 TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
286   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
287                                        {S("vendor"), 1_GiB},
288                                        {T("system"), 2_GiB},
289                                        {T("vendor"), 1_GiB}};
290   // No T("vendor")
291   PartitionSuffixSizes expected{
292       {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
293   PartitionSizes update_metadata{{"system", 2_GiB}};
294   EXPECT_TRUE(
295       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
296 }
297 
298 // Test delete all partitions.
TEST_P(DynamicPartitionControlAndroidTestP,DeleteAll)299 TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
300   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
301                                        {S("vendor"), 1_GiB},
302                                        {T("system"), 2_GiB},
303                                        {T("vendor"), 1_GiB}};
304   PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
305   PartitionSizes update_metadata{};
306   EXPECT_TRUE(
307       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
308 }
309 
310 // Test corrupt source metadata case.
TEST_P(DynamicPartitionControlAndroidTestP,CorruptedSourceMetadata)311 TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
312   EXPECT_CALL(dynamicControl(),
313               LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
314       .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
315   ExpectUnmap({T("system")});
316 
317   EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
318       << "Should not be able to continue with corrupt source metadata";
319 }
320 
321 // Test that UpdatePartitionMetadata fails if there is not enough space on the
322 // device.
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpace)323 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
324   PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
325                                        {S("vendor"), 2_GiB},
326                                        {T("system"), 0},
327                                        {T("vendor"), 0}};
328   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
329 
330   EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
331       << "Should not be able to fit 11GiB data into 10GiB space";
332 }
333 
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpaceForSlot)334 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
335   PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
336                                        {S("vendor"), 1_GiB},
337                                        {T("system"), 0},
338                                        {T("vendor"), 0}};
339   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
340   EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
341       << "Should not be able to grow over size of super / 2";
342 }
343 
TEST_P(DynamicPartitionControlAndroidTestP,ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild)344 TEST_P(DynamicPartitionControlAndroidTestP,
345        ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
346   ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
347       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
348   // Static partition {system,bar}_{a,b} exists.
349   EXPECT_CALL(dynamicControl(),
350               DeviceExists(AnyOf(GetDevice(S("bar")),
351                                  GetDevice(T("bar")),
352                                  GetDevice(S("system")),
353                                  GetDevice(T("system")))))
354       .WillRepeatedly(Return(true));
355 
356   SetMetadata(source(),
357               {{S("system"), 2_GiB},
358                {S("vendor"), 1_GiB},
359                {T("system"), 2_GiB},
360                {T("vendor"), 1_GiB}});
361 
362   // Not calling through
363   // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
364   // don't want any default group in the PartitionMetadata.
365   EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
366       source(), target(), {}, true, nullptr));
367 
368   // Should use dynamic source partitions.
369   EXPECT_CALL(dynamicControl(), GetState(S("system")))
370       .Times(1)
371       .WillOnce(Return(DmDeviceState::ACTIVE));
372   string system_device;
373   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
374       "system", source(), source(), &system_device));
375   EXPECT_EQ(GetDmDevice(S("system")), system_device);
376 
377   // Should use static target partitions without querying dynamic control.
378   EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
379   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
380       "system", target(), source(), &system_device));
381   EXPECT_EQ(GetDevice(T("system")), system_device);
382 
383   // Static partition "bar".
384   EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
385   std::string bar_device;
386   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
387       "bar", source(), source(), &bar_device));
388   EXPECT_EQ(GetDevice(S("bar")), bar_device);
389 
390   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
391   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
392       "bar", target(), source(), &bar_device));
393   EXPECT_EQ(GetDevice(T("bar")), bar_device);
394 }
395 
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePath)396 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePath) {
397   ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
398       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
399   ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
400       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
401   ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
402       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
403   ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
404       .WillByDefault(Return(false));
405   ON_CALL(dynamicControl(), IsDynamicPartition(_, _))
406       .WillByDefault(Return(true));
407 
408   EXPECT_CALL(dynamicControl(),
409               DeviceExists(AnyOf(GetDevice(S("vendor")),
410                                  GetDevice(T("vendor")),
411                                  GetDevice(S("system")),
412                                  GetDevice(T("system")))))
413       .WillRepeatedly(Return(true));
414   EXPECT_CALL(
415       dynamicControl(),
416       GetState(AnyOf(S("vendor"), T("vendor"), S("system"), T("system"))))
417       .WillRepeatedly(Return(DmDeviceState::ACTIVE));
418 
419   SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
420   SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
421   std::string device;
422   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
423       "system", source(), source(), &device));
424   ASSERT_EQ(GetDmDevice(S("system")), device);
425 
426   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
427       "system", target(), source(), &device));
428   ASSERT_EQ(GetDevice(T("system")), device);
429 
430   // If VABC is disabled, mountable device path should be same as device path.
431   auto device_info =
432       dynamicControl().GetPartitionDevice("system", target(), source(), false);
433   ASSERT_TRUE(device_info.has_value());
434   ASSERT_EQ(device_info->readonly_device_path, device);
435 }
436 
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePathVABC)437 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePathVABC) {
438   ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
439       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
440   ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
441       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
442   ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
443       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
444   ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
445       .WillByDefault(Return(true));
446   EXPECT_CALL(dynamicControl(), IsDynamicPartition(_, _))
447       .Times(AtLeast(1))
448       .WillRepeatedly(Return(true));
449 
450   EXPECT_CALL(dynamicControl(),
451               DeviceExists(AnyOf(GetDevice(S("vendor")),
452                                  GetDevice(T("vendor")),
453                                  GetDevice(S("system")),
454                                  GetDevice(T("system")))))
455       .WillRepeatedly(Return(true));
456   EXPECT_CALL(
457       dynamicControl(),
458       GetState(AnyOf(S("vendor"), T("vendor"), S("system"), T("system"))))
459       .WillRepeatedly(Return(DmDeviceState::ACTIVE));
460 
461   SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
462   SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
463 
464   std::string device;
465   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
466       "system", source(), source(), &device));
467   ASSERT_EQ(GetDmDevice(S("system")), device);
468 
469   ASSERT_TRUE(dynamicControl().GetPartitionDevice(
470       "system", target(), source(), &device));
471   ASSERT_EQ("", device);
472 
473   auto device_info =
474       dynamicControl().GetPartitionDevice("system", target(), source(), false);
475   ASSERT_TRUE(device_info.has_value());
476   base::FilePath vabc_device_dir{
477       std::string{DynamicPartitionControlAndroid::VABC_DEVICE_DIR}};
478   ASSERT_EQ(device_info->readonly_device_path,
479             vabc_device_dir.Append(T("system")).value());
480 }
481 
TEST_P(DynamicPartitionControlAndroidTestP,GetPartitionDeviceWhenResumingUpdate)482 TEST_P(DynamicPartitionControlAndroidTestP,
483        GetPartitionDeviceWhenResumingUpdate) {
484   // Static partition bar_{a,b} exists.
485   EXPECT_CALL(dynamicControl(),
486               DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
487       .WillRepeatedly(Return(true));
488 
489   // Both of the two slots contain valid partition metadata, since this is
490   // resuming an update.
491   SetMetadata(source(),
492               {{S("system"), 2_GiB},
493                {S("vendor"), 1_GiB},
494                {T("system"), 2_GiB},
495                {T("vendor"), 1_GiB}});
496   SetMetadata(target(),
497               {{S("system"), 2_GiB},
498                {S("vendor"), 1_GiB},
499                {T("system"), 2_GiB},
500                {T("vendor"), 1_GiB}});
501 
502   EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
503       source(),
504       target(),
505       PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
506       false,
507       nullptr));
508 
509   // Dynamic partition "system".
510   EXPECT_CALL(dynamicControl(), GetState(S("system")))
511       .Times(1)
512       .WillOnce(Return(DmDeviceState::ACTIVE));
513   string system_device;
514   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
515       "system", source(), source(), &system_device));
516   EXPECT_EQ(GetDmDevice(S("system")), 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   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
531       "system", target(), source(), &system_device));
532   EXPECT_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   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
538       "bar", source(), source(), &bar_device));
539   EXPECT_EQ(GetDevice(S("bar")), bar_device);
540 
541   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
542   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
543       "bar", target(), source(), &bar_device));
544   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   EXPECT_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   dynamicControl().set_fake_mapped_devices({T("foo")});
764 
765   InstallOperation iop;
766   InstallOperation optimized;
767   Extent *se, *de;
768 
769   // Not a SOURCE_COPY operation, cannot skip.
770   iop.set_type(InstallOperation::REPLACE);
771   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
772 
773   iop.set_type(InstallOperation::SOURCE_COPY);
774 
775   // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
776   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
777 
778   // Enable GetVirtualAbFeatureFlag in the mock interface.
779   ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
780       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
781 
782   // By default target_supports_snapshot_ is set to false. Cannot skip
783   // operation.
784   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
785 
786   SetSnapshotEnabled(true);
787 
788   // Empty source and destination. Skip.
789   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
790   EXPECT_TRUE(optimized.src_extents().empty());
791   EXPECT_TRUE(optimized.dst_extents().empty());
792 
793   se = iop.add_src_extents();
794   se->set_start_block(0);
795   se->set_num_blocks(1);
796 
797   // There is something in sources, but destinations are empty. Cannot skip.
798   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
799 
800   InstallOperation iop2;
801 
802   de = iop2.add_dst_extents();
803   de->set_start_block(0);
804   de->set_num_blocks(1);
805 
806   // There is something in destinations, but sources are empty. Cannot skip.
807   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
808 
809   de = iop.add_dst_extents();
810   de->set_start_block(0);
811   de->set_num_blocks(1);
812 
813   // Sources and destinations are identical. Skip.
814   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
815   EXPECT_TRUE(optimized.src_extents().empty());
816   EXPECT_TRUE(optimized.dst_extents().empty());
817 
818   se = iop.add_src_extents();
819   se->set_start_block(1);
820   se->set_num_blocks(5);
821 
822   // There is something in source, but not in destination. Cannot skip.
823   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
824 
825   de = iop.add_dst_extents();
826   de->set_start_block(1);
827   de->set_num_blocks(5);
828 
829   // There is source and destination are equal. Skip.
830   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
831   EXPECT_TRUE(optimized.src_extents().empty());
832   EXPECT_TRUE(optimized.dst_extents().empty());
833 
834   de = iop.add_dst_extents();
835   de->set_start_block(6);
836   de->set_num_blocks(5);
837 
838   // There is something extra in dest. Cannot skip.
839   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
840 
841   se = iop.add_src_extents();
842   se->set_start_block(6);
843   se->set_num_blocks(5);
844 
845   // Source and dest are identical again. Skip.
846   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
847   EXPECT_TRUE(optimized.src_extents().empty());
848   EXPECT_TRUE(optimized.dst_extents().empty());
849 
850   iop.Clear();
851   iop.set_type(InstallOperation::SOURCE_COPY);
852   se = iop.add_src_extents();
853   se->set_start_block(1);
854   se->set_num_blocks(1);
855   se = iop.add_src_extents();
856   se->set_start_block(3);
857   se->set_num_blocks(2);
858   se = iop.add_src_extents();
859   se->set_start_block(7);
860   se->set_num_blocks(2);
861   de = iop.add_dst_extents();
862   de->set_start_block(2);
863   de->set_num_blocks(5);
864 
865   // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
866   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
867   ASSERT_EQ(2, optimized.src_extents_size());
868   ASSERT_EQ(2, optimized.dst_extents_size());
869   EXPECT_EQ(1u, optimized.src_extents(0).start_block());
870   EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
871   EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
872   EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
873   EXPECT_EQ(7u, optimized.src_extents(1).start_block());
874   EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
875   EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
876   EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
877 
878   // Don't skip for static partitions.
879   EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
880 }
881 
TEST_F(DynamicPartitionControlAndroidTest,ResetUpdate)882 TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
883   MockPrefs prefs;
884   ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
885 }
886 
TEST_F(DynamicPartitionControlAndroidTest,IsAvbNotEnabledInFstab)887 TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
888   std::string fstab_content =
889       "system /postinstall ext4 ro,nosuid,nodev,noexec "
890       "slotselect_other,logical\n"
891       "/dev/block/by-name/system /postinstall ext4 "
892       "ro,nosuid,nodev,noexec slotselect_other\n";
893   ScopedTempFile fstab;
894   ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
895   ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
896               Optional(false));
897 }
898 
TEST_F(DynamicPartitionControlAndroidTest,IsAvbEnabledInFstab)899 TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
900   std::string fstab_content =
901       "system /postinstall ext4 ro,nosuid,nodev,noexec "
902       "slotselect_other,logical,avb_keys=/foo\n";
903   ScopedTempFile fstab;
904   ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
905   ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
906               Optional(true));
907 }
908 
TEST_P(DynamicPartitionControlAndroidTestP,AvbNotEnabledOnSystemOther)909 TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
910   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
911       .WillByDefault(Invoke([&](auto source_slot,
912                                 auto target_slot,
913                                 const auto& name,
914                                 auto path,
915                                 auto should_unmap) {
916         return dynamicControl().RealGetSystemOtherPath(
917             source_slot, target_slot, name, path, should_unmap);
918       }));
919   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
920       .WillByDefault(Return(false));
921   EXPECT_TRUE(
922       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
923 }
924 
TEST_P(DynamicPartitionControlAndroidTestP,NoSystemOtherToErase)925 TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
926   SetMetadata(source(), {{S("system"), 100_MiB}});
927   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
928       .WillByDefault(Return(true));
929   std::string path;
930   bool should_unmap;
931   ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
932       source(), target(), T("system"), &path, &should_unmap));
933   ASSERT_TRUE(path.empty()) << path;
934   ASSERT_FALSE(should_unmap);
935   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
936       .WillByDefault(Invoke([&](auto source_slot,
937                                 auto target_slot,
938                                 const auto& name,
939                                 auto path,
940                                 auto should_unmap) {
941         return dynamicControl().RealGetSystemOtherPath(
942             source_slot, target_slot, name, path, should_unmap);
943       }));
944   EXPECT_TRUE(
945       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
946 }
947 
TEST_P(DynamicPartitionControlAndroidTestP,SkipEraseUpdatedSystemOther)948 TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
949   PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
950   SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
951   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
952       .WillByDefault(Return(true));
953   std::string path;
954   bool should_unmap;
955   ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
956       source(), target(), T("system"), &path, &should_unmap));
957   ASSERT_TRUE(path.empty()) << path;
958   ASSERT_FALSE(should_unmap);
959   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
960       .WillByDefault(Invoke([&](auto source_slot,
961                                 auto target_slot,
962                                 const auto& name,
963                                 auto path,
964                                 auto should_unmap) {
965         return dynamicControl().RealGetSystemOtherPath(
966             source_slot, target_slot, name, path, should_unmap);
967       }));
968   EXPECT_TRUE(
969       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
970 }
971 
TEST_P(DynamicPartitionControlAndroidTestP,EraseSystemOtherAvbFooter)972 TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
973   constexpr uint64_t file_size = 1_MiB;
974   static_assert(file_size > AVB_FOOTER_SIZE);
975   ScopedTempFile system_other;
976   brillo::Blob original(file_size, 'X');
977   ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
978   std::string mnt_path;
979   ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
980   ASSERT_TRUE(dev.is_bound());
981 
982   brillo::Blob device_content;
983   ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
984   ASSERT_EQ(original, device_content);
985 
986   PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
987   SetMetadata(source(), sizes);
988   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
989       .WillByDefault(Return(true));
990   EXPECT_CALL(dynamicControl(),
991               GetSystemOtherPath(source(), target(), T("system"), _, _))
992       .WillRepeatedly(
993           Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
994             *path = mnt_path;
995             *should_unmap = false;
996             return true;
997           }));
998   ASSERT_TRUE(
999       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
1000 
1001   device_content.clear();
1002   ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
1003   brillo::Blob new_expected(original);
1004   // Clear the last AVB_FOOTER_SIZE bytes.
1005   new_expected.resize(file_size - AVB_FOOTER_SIZE);
1006   new_expected.resize(file_size, '\0');
1007   ASSERT_EQ(new_expected, device_content);
1008 }
1009 
1010 class FakeAutoDevice : public android::snapshot::AutoDevice {
1011  public:
FakeAutoDevice()1012   FakeAutoDevice() : AutoDevice("") {}
1013 };
1014 
1015 class SnapshotPartitionTestP : public DynamicPartitionControlAndroidTestP {
1016  public:
SetUp()1017   void SetUp() override {
1018     DynamicPartitionControlAndroidTestP::SetUp();
1019     ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
1020         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
1021 
1022     snapshot_ = new NiceMock<MockSnapshotManager>();
1023     dynamicControl().snapshot_.reset(snapshot_);  // takes ownership
1024     EXPECT_CALL(*snapshot_, BeginUpdate()).WillOnce(Return(true));
1025     EXPECT_CALL(*snapshot_, EnsureMetadataMounted())
1026         .WillRepeatedly(
1027             Invoke([]() { return std::make_unique<FakeAutoDevice>(); }));
1028 
1029     manifest_ =
1030         PartitionSizesToManifest({{"system", 3_GiB}, {"vendor", 1_GiB}});
1031   }
ExpectCreateUpdateSnapshots(android::snapshot::Return val)1032   void ExpectCreateUpdateSnapshots(android::snapshot::Return val) {
1033     manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
1034     EXPECT_CALL(*snapshot_, CreateUpdateSnapshots(_))
1035         .WillRepeatedly(Invoke([&, val](const auto& manifest) {
1036           // Deep comparison requires full protobuf library. Comparing the
1037           // pointers are sufficient.
1038           EXPECT_EQ(&manifest_, &manifest);
1039           LOG(WARNING) << "CreateUpdateSnapshots returning " << val.string();
1040           return val;
1041         }));
1042   }
PreparePartitionsForUpdate(uint64_t * required_size)1043   bool PreparePartitionsForUpdate(uint64_t* required_size) {
1044     return dynamicControl().PreparePartitionsForUpdate(
1045         source(), target(), manifest_, true /* update */, required_size);
1046   }
1047   MockSnapshotManager* snapshot_ = nullptr;
1048   DeltaArchiveManifest manifest_;
1049 };
1050 
1051 // Test happy path of PreparePartitionsForUpdate on a Virtual A/B device.
TEST_P(SnapshotPartitionTestP,PreparePartitions)1052 TEST_P(SnapshotPartitionTestP, PreparePartitions) {
1053   ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1054   SetMetadata(source(), {});
1055   uint64_t required_size = 0;
1056   EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1057   EXPECT_EQ(0u, required_size);
1058 }
1059 
1060 // Test that if not enough space, required size returned by SnapshotManager is
1061 // passed up.
TEST_P(SnapshotPartitionTestP,PreparePartitionsNoSpace)1062 TEST_P(SnapshotPartitionTestP, PreparePartitionsNoSpace) {
1063   ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1064   uint64_t required_size = 0;
1065 
1066   SetMetadata(source(), {});
1067   EXPECT_FALSE(PreparePartitionsForUpdate(&required_size));
1068   EXPECT_EQ(1_GiB, required_size);
1069 }
1070 
1071 // Test that in recovery, use empty space in super partition for a snapshot
1072 // update first.
TEST_P(SnapshotPartitionTestP,RecoveryUseSuperEmpty)1073 TEST_P(SnapshotPartitionTestP, RecoveryUseSuperEmpty) {
1074   ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1075   EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1076 
1077   // Metadata is needed to perform super partition size check.
1078   SetMetadata(source(), {});
1079 
1080   // Must not call PrepareDynamicPartitionsForUpdate if
1081   // PrepareSnapshotPartitionsForUpdate succeeds.
1082   EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1083       .Times(0);
1084   uint64_t required_size = 0;
1085   EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1086   EXPECT_EQ(0u, required_size);
1087 }
1088 
1089 // Test that in recovery, if CreateUpdateSnapshots throws an error, try
1090 // the flashing path for full updates.
TEST_P(SnapshotPartitionTestP,RecoveryErrorShouldDeleteSource)1091 TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
1092   // Expectation on PreparePartitionsForUpdate
1093   ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1094   EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1095   EXPECT_CALL(*snapshot_, CancelUpdate()).WillOnce(Return(true));
1096   EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1097       .WillRepeatedly(Invoke([&](auto source_slot,
1098                                  auto target_slot,
1099                                  const auto& manifest,
1100                                  auto delete_source) {
1101         EXPECT_EQ(source(), source_slot);
1102         EXPECT_EQ(target(), target_slot);
1103         // Deep comparison requires full protobuf library. Comparing the
1104         // pointers are sufficient.
1105         EXPECT_EQ(&manifest_, &manifest);
1106         EXPECT_TRUE(delete_source);
1107         return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
1108             source_slot, target_slot, manifest, delete_source);
1109       }));
1110   // Only one slot of space in super
1111   uint64_t super_size = kDefaultGroupSize + 1_MiB;
1112   // Expectation on PrepareDynamicPartitionsForUpdate
1113   SetMetadata(
1114       source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size);
1115   ExpectUnmap({T("system"), T("vendor")});
1116   // Expect that the source partitions aren't present in target super
1117   // metadata.
1118   ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
1119 
1120   uint64_t required_size = 0;
1121   EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1122   EXPECT_EQ(0u, required_size);
1123 }
1124 
1125 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
1126                         SnapshotPartitionTestP,
1127                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
1128 
1129 }  // namespace chromeos_update_engine
1130