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/dynamic_partition_control_android.h"
18 
19 #include <set>
20 #include <vector>
21 
22 #include <base/logging.h>
23 #include <base/strings/string_util.h>
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26 #include <libavb/libavb.h>
27 
28 #include "update_engine/common/mock_prefs.h"
29 #include "update_engine/common/test_utils.h"
30 #include "update_engine/dynamic_partition_test_utils.h"
31 #include "update_engine/mock_dynamic_partition_control.h"
32 
33 using android::dm::DmDeviceState;
34 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
35 using chromeos_update_engine::test_utils::ScopedTempFile;
36 using std::string;
37 using testing::_;
38 using testing::AnyNumber;
39 using testing::AnyOf;
40 using testing::Invoke;
41 using testing::NiceMock;
42 using testing::Not;
43 using testing::Optional;
44 using testing::Return;
45 
46 namespace chromeos_update_engine {
47 
48 class DynamicPartitionControlAndroidTest : public ::testing::Test {
49  public:
50   void SetUp() override {
51     module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
52 
53     ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
54         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
55     ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
56         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
57 
58     ON_CALL(dynamicControl(), GetDeviceDir(_))
59         .WillByDefault(Invoke([](auto path) {
60           *path = kFakeDevicePath;
61           return true;
62         }));
63 
64     ON_CALL(dynamicControl(), GetSuperPartitionName(_))
65         .WillByDefault(Return(kFakeSuper));
66 
67     ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
68         .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
69           *device = GetDmDevice(partition_name_suffix);
70           return true;
71         }));
72 
73     ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
74         .WillByDefault(Return(true));
75   }
76 
77   // Return the mocked DynamicPartitionControlInterface.
78   NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
79     return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
80   }
81 
82   std::string GetSuperDevice(uint32_t slot) {
83     return GetDevice(dynamicControl().GetSuperPartitionName(slot));
84   }
85 
86   uint32_t source() { return slots_.source; }
87   uint32_t target() { return slots_.target; }
88 
89   // Return partition names with suffix of source().
90   std::string S(const std::string& name) {
91     return name + kSlotSuffixes[source()];
92   }
93 
94   // Return partition names with suffix of target().
95   std::string T(const std::string& name) {
96     return name + kSlotSuffixes[target()];
97   }
98 
99   // Set the fake metadata to return when LoadMetadataBuilder is called on
100   // |slot|.
101   void SetMetadata(uint32_t slot,
102                    const PartitionSuffixSizes& sizes,
103                    uint32_t partition_attr = 0) {
104     EXPECT_CALL(dynamicControl(),
105                 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
106         .Times(AnyNumber())
107         .WillRepeatedly(Invoke([sizes, partition_attr](auto, auto, auto) {
108           return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
109                                  partition_attr);
110         }));
111   }
112 
113   void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
114     EXPECT_CALL(dynamicControl(),
115                 StoreMetadata(GetSuperDevice(target()),
116                               MetadataMatches(partition_sizes),
117                               target()))
118         .WillOnce(Return(true));
119   }
120 
121   // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
122   // slot with each partition in |partitions|.
123   void ExpectUnmap(const std::set<std::string>& partitions) {
124     // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
125     ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
126         .WillByDefault(Return(false));
127 
128     for (const auto& partition : partitions) {
129       EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
130           .WillOnce(Return(true));
131     }
132   }
133   bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
134     return dynamicControl().PreparePartitionsForUpdate(
135         source(),
136         target(),
137         PartitionSizesToManifest(partition_sizes),
138         true,
139         nullptr);
140   }
141   void SetSlots(const TestParam& slots) { slots_ = slots; }
142 
143   void SetSnapshotEnabled(bool enabled) {
144     dynamicControl().target_supports_snapshot_ = enabled;
145   }
146 
147   struct Listener : public ::testing::MatchResultListener {
148     explicit Listener(std::ostream* os) : MatchResultListener(os) {}
149   };
150 
151   testing::AssertionResult UpdatePartitionMetadata(
152       const PartitionSuffixSizes& source_metadata,
153       const PartitionSizes& update_metadata,
154       const PartitionSuffixSizes& expected) {
155     return UpdatePartitionMetadata(
156         PartitionSuffixSizesToManifest(source_metadata),
157         PartitionSizesToManifest(update_metadata),
158         PartitionSuffixSizesToManifest(expected));
159   }
160   testing::AssertionResult UpdatePartitionMetadata(
161       const DeltaArchiveManifest& source_manifest,
162       const DeltaArchiveManifest& update_manifest,
163       const DeltaArchiveManifest& expected) {
164     return UpdatePartitionMetadata(
165         source_manifest, update_manifest, MetadataMatches(expected));
166   }
167   testing::AssertionResult UpdatePartitionMetadata(
168       const DeltaArchiveManifest& source_manifest,
169       const DeltaArchiveManifest& update_manifest,
170       const Matcher<MetadataBuilder*>& matcher) {
171     auto super_metadata = NewFakeMetadata(source_manifest);
172     if (!module_->UpdatePartitionMetadata(
173             super_metadata.get(), target(), update_manifest)) {
174       return testing::AssertionFailure()
175              << "UpdatePartitionMetadataInternal failed";
176     }
177     std::stringstream ss;
178     Listener listener(&ss);
179     if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
180       return testing::AssertionSuccess() << ss.str();
181     } else {
182       return testing::AssertionFailure() << ss.str();
183     }
184   }
185 
186   std::unique_ptr<DynamicPartitionControlAndroid> module_;
187   TestParam slots_;
188 };
189 
190 class DynamicPartitionControlAndroidTestP
191     : public DynamicPartitionControlAndroidTest,
192       public ::testing::WithParamInterface<TestParam> {
193  public:
194   void SetUp() override {
195     DynamicPartitionControlAndroidTest::SetUp();
196     SetSlots(GetParam());
197   }
198 };
199 
200 // Test resize case. Grow if target metadata contains a partition with a size
201 // less than expected.
202 TEST_P(DynamicPartitionControlAndroidTestP,
203        NeedGrowIfSizeNotMatchWhenResizing) {
204   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
205                                        {S("vendor"), 1_GiB},
206                                        {T("system"), 2_GiB},
207                                        {T("vendor"), 1_GiB}};
208   PartitionSuffixSizes expected{{S("system"), 2_GiB},
209                                 {S("vendor"), 1_GiB},
210                                 {T("system"), 3_GiB},
211                                 {T("vendor"), 1_GiB}};
212   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
213   EXPECT_TRUE(
214       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
215 }
216 
217 // Test resize case. Shrink if target metadata contains a partition with a size
218 // greater than expected.
219 TEST_P(DynamicPartitionControlAndroidTestP,
220        NeedShrinkIfSizeNotMatchWhenResizing) {
221   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
222                                        {S("vendor"), 1_GiB},
223                                        {T("system"), 2_GiB},
224                                        {T("vendor"), 1_GiB}};
225   PartitionSuffixSizes expected{{S("system"), 2_GiB},
226                                 {S("vendor"), 1_GiB},
227                                 {T("system"), 2_GiB},
228                                 {T("vendor"), 150_MiB}};
229   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
230   EXPECT_TRUE(
231       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
232 }
233 
234 // Test adding partitions on the first run.
235 TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
236   PartitionSuffixSizes source_metadata{};
237   PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
238   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
239   EXPECT_TRUE(
240       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
241 }
242 
243 // Test subsequent add case.
244 TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
245   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
246                                        {T("system"), 2_GiB}};
247   PartitionSuffixSizes expected{
248       {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
249   PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
250   EXPECT_TRUE(
251       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
252 }
253 
254 // Test delete one partition.
255 TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
256   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
257                                        {S("vendor"), 1_GiB},
258                                        {T("system"), 2_GiB},
259                                        {T("vendor"), 1_GiB}};
260   // No T("vendor")
261   PartitionSuffixSizes expected{
262       {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
263   PartitionSizes update_metadata{{"system", 2_GiB}};
264   EXPECT_TRUE(
265       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
266 }
267 
268 // Test delete all partitions.
269 TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
270   PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
271                                        {S("vendor"), 1_GiB},
272                                        {T("system"), 2_GiB},
273                                        {T("vendor"), 1_GiB}};
274   PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
275   PartitionSizes update_metadata{};
276   EXPECT_TRUE(
277       UpdatePartitionMetadata(source_metadata, update_metadata, expected));
278 }
279 
280 // Test corrupt source metadata case.
281 TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
282   EXPECT_CALL(dynamicControl(),
283               LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
284       .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
285   ExpectUnmap({T("system")});
286 
287   EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
288       << "Should not be able to continue with corrupt source metadata";
289 }
290 
291 // Test that UpdatePartitionMetadata fails if there is not enough space on the
292 // device.
293 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
294   PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
295                                        {S("vendor"), 2_GiB},
296                                        {T("system"), 0},
297                                        {T("vendor"), 0}};
298   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
299 
300   EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
301       << "Should not be able to fit 11GiB data into 10GiB space";
302 }
303 
304 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
305   PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
306                                        {S("vendor"), 1_GiB},
307                                        {T("system"), 0},
308                                        {T("vendor"), 0}};
309   PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
310   EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
311       << "Should not be able to grow over size of super / 2";
312 }
313 
314 TEST_P(DynamicPartitionControlAndroidTestP,
315        ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
316   ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
317       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
318   // Static partition {system,bar}_{a,b} exists.
319   EXPECT_CALL(dynamicControl(),
320               DeviceExists(AnyOf(GetDevice(S("bar")),
321                                  GetDevice(T("bar")),
322                                  GetDevice(S("system")),
323                                  GetDevice(T("system")))))
324       .WillRepeatedly(Return(true));
325 
326   SetMetadata(source(),
327               {{S("system"), 2_GiB},
328                {S("vendor"), 1_GiB},
329                {T("system"), 2_GiB},
330                {T("vendor"), 1_GiB}});
331 
332   // Not calling through
333   // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
334   // don't want any default group in the PartitionMetadata.
335   EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
336       source(), target(), {}, true, nullptr));
337 
338   // Should use dynamic source partitions.
339   EXPECT_CALL(dynamicControl(), GetState(S("system")))
340       .Times(1)
341       .WillOnce(Return(DmDeviceState::ACTIVE));
342   string system_device;
343   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
344       "system", source(), source(), &system_device));
345   EXPECT_EQ(GetDmDevice(S("system")), system_device);
346 
347   // Should use static target partitions without querying dynamic control.
348   EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
349   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
350       "system", target(), source(), &system_device));
351   EXPECT_EQ(GetDevice(T("system")), system_device);
352 
353   // Static partition "bar".
354   EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
355   std::string bar_device;
356   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
357       "bar", source(), source(), &bar_device));
358   EXPECT_EQ(GetDevice(S("bar")), bar_device);
359 
360   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
361   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
362       "bar", target(), source(), &bar_device));
363   EXPECT_EQ(GetDevice(T("bar")), bar_device);
364 }
365 
366 TEST_P(DynamicPartitionControlAndroidTestP,
367        GetPartitionDeviceWhenResumingUpdate) {
368   // Static partition bar_{a,b} exists.
369   EXPECT_CALL(dynamicControl(),
370               DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
371       .WillRepeatedly(Return(true));
372 
373   // Both of the two slots contain valid partition metadata, since this is
374   // resuming an update.
375   SetMetadata(source(),
376               {{S("system"), 2_GiB},
377                {S("vendor"), 1_GiB},
378                {T("system"), 2_GiB},
379                {T("vendor"), 1_GiB}});
380   SetMetadata(target(),
381               {{S("system"), 2_GiB},
382                {S("vendor"), 1_GiB},
383                {T("system"), 2_GiB},
384                {T("vendor"), 1_GiB}});
385 
386   EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
387       source(),
388       target(),
389       PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
390       false,
391       nullptr));
392 
393   // Dynamic partition "system".
394   EXPECT_CALL(dynamicControl(), GetState(S("system")))
395       .Times(1)
396       .WillOnce(Return(DmDeviceState::ACTIVE));
397   string system_device;
398   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
399       "system", source(), source(), &system_device));
400   EXPECT_EQ(GetDmDevice(S("system")), system_device);
401 
402   EXPECT_CALL(dynamicControl(), GetState(T("system")))
403       .Times(AnyNumber())
404       .WillOnce(Return(DmDeviceState::ACTIVE));
405   EXPECT_CALL(dynamicControl(),
406               MapPartitionOnDeviceMapper(
407                   GetSuperDevice(target()), T("system"), target(), _, _))
408       .Times(AnyNumber())
409       .WillRepeatedly(
410           Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
411             *device = "/fake/remapped/" + name;
412             return true;
413           }));
414   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
415       "system", target(), source(), &system_device));
416   EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
417 
418   // Static partition "bar".
419   EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
420   std::string bar_device;
421   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
422       "bar", source(), source(), &bar_device));
423   EXPECT_EQ(GetDevice(S("bar")), bar_device);
424 
425   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
426   EXPECT_TRUE(dynamicControl().GetPartitionDevice(
427       "bar", target(), source(), &bar_device));
428   EXPECT_EQ(GetDevice(T("bar")), bar_device);
429 }
430 
431 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
432                         DynamicPartitionControlAndroidTestP,
433                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
434 
435 class DynamicPartitionControlAndroidGroupTestP
436     : public DynamicPartitionControlAndroidTestP {
437  public:
438   DeltaArchiveManifest source_manifest;
439   void SetUp() override {
440     DynamicPartitionControlAndroidTestP::SetUp();
441     AddGroupAndPartition(
442         &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
443     AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
444     AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
445     AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
446   }
447 
448   void AddGroupAndPartition(DeltaArchiveManifest* manifest,
449                             const string& group,
450                             uint64_t group_size,
451                             const string& partition,
452                             uint64_t partition_size) {
453     auto* g = AddGroup(manifest, group, group_size);
454     AddPartition(manifest, g, partition, partition_size);
455   }
456 };
457 
458 // Allow to resize within group.
459 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
460   DeltaArchiveManifest expected;
461   AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
462   AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
463 
464   DeltaArchiveManifest update_manifest;
465   AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
466   AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
467 
468   EXPECT_TRUE(
469       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
470 }
471 
472 TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
473   DeltaArchiveManifest update_manifest;
474   AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
475       AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
476   EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
477       << "Should not be able to grow over maximum size of group";
478 }
479 
480 TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
481   DeltaArchiveManifest update_manifest;
482   AddGroup(&update_manifest, "android", 3_GiB);
483   AddGroup(&update_manifest, "oem", 3_GiB);
484   EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
485       << "Should not be able to grow over size of super / 2";
486 }
487 
488 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
489   DeltaArchiveManifest expected;
490   auto* g = AddGroup(&expected, T("android"), 3_GiB);
491   AddPartition(&expected, g, T("system"), 2_GiB);
492   AddPartition(&expected, g, T("system_ext"), 1_GiB);
493 
494   DeltaArchiveManifest update_manifest;
495   g = AddGroup(&update_manifest, "android", 3_GiB);
496   AddPartition(&update_manifest, g, "system", 2_GiB);
497   AddPartition(&update_manifest, g, "system_ext", 1_GiB);
498   AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
499 
500   EXPECT_TRUE(
501       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
502 }
503 
504 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
505   DeltaArchiveManifest expected;
506   AddGroup(&expected, T("android"), 3_GiB);
507 
508   DeltaArchiveManifest update_manifest;
509   AddGroup(&update_manifest, "android", 3_GiB);
510   AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
511 
512   EXPECT_TRUE(
513       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
514 }
515 
516 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
517   DeltaArchiveManifest expected;
518   AddGroupAndPartition(
519       &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
520 
521   DeltaArchiveManifest update_manifest;
522   AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
523   AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
524   AddGroupAndPartition(
525       &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
526   EXPECT_TRUE(
527       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
528 }
529 
530 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
531   DeltaArchiveManifest update_manifest;
532   AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
533 
534   EXPECT_TRUE(UpdatePartitionMetadata(
535       source_manifest, update_manifest, Not(HasGroup(T("oem")))));
536 }
537 
538 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
539   DeltaArchiveManifest expected;
540   AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
541   AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
542   DeltaArchiveManifest update_manifest;
543   AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
544       AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
545   EXPECT_TRUE(
546       UpdatePartitionMetadata(source_manifest, update_manifest, expected));
547 }
548 
549 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
550                         DynamicPartitionControlAndroidGroupTestP,
551                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
552 
553 const PartitionSuffixSizes update_sizes_0() {
554   // Initial state is 0 for "other" slot.
555   return {
556       {"grown_a", 2_GiB},
557       {"shrunk_a", 1_GiB},
558       {"same_a", 100_MiB},
559       {"deleted_a", 150_MiB},
560       // no added_a
561       {"grown_b", 200_MiB},
562       // simulate system_other
563       {"shrunk_b", 0},
564       {"same_b", 0},
565       {"deleted_b", 0},
566       // no added_b
567   };
568 }
569 
570 const PartitionSuffixSizes update_sizes_1() {
571   return {
572       {"grown_a", 2_GiB},
573       {"shrunk_a", 1_GiB},
574       {"same_a", 100_MiB},
575       {"deleted_a", 150_MiB},
576       // no added_a
577       {"grown_b", 3_GiB},
578       {"shrunk_b", 150_MiB},
579       {"same_b", 100_MiB},
580       {"added_b", 150_MiB},
581       // no deleted_b
582   };
583 }
584 
585 const PartitionSuffixSizes update_sizes_2() {
586   return {
587       {"grown_a", 4_GiB},
588       {"shrunk_a", 100_MiB},
589       {"same_a", 100_MiB},
590       {"deleted_a", 64_MiB},
591       // no added_a
592       {"grown_b", 3_GiB},
593       {"shrunk_b", 150_MiB},
594       {"same_b", 100_MiB},
595       {"added_b", 150_MiB},
596       // no deleted_b
597   };
598 }
599 
600 // Test case for first update after the device is manufactured, in which
601 // case the "other" slot is likely of size "0" (except system, which is
602 // non-zero because of system_other partition)
603 TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
604   SetSlots({0, 1});
605 
606   SetMetadata(source(), update_sizes_0());
607   SetMetadata(target(), update_sizes_0());
608   ExpectStoreMetadata(update_sizes_1());
609   ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
610 
611   EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
612                                           {"shrunk", 150_MiB},
613                                           {"same", 100_MiB},
614                                           {"added", 150_MiB}}));
615 }
616 
617 // After first update, test for the second update. In the second update, the
618 // "added" partition is deleted and "deleted" partition is re-added.
619 TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
620   SetSlots({1, 0});
621 
622   SetMetadata(source(), update_sizes_1());
623   SetMetadata(target(), update_sizes_0());
624 
625   ExpectStoreMetadata(update_sizes_2());
626   ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
627 
628   EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
629                                           {"shrunk", 100_MiB},
630                                           {"same", 100_MiB},
631                                           {"deleted", 64_MiB}}));
632 }
633 
634 TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
635   SetSlots({1, 1});
636   EXPECT_FALSE(PreparePartitionsForUpdate({}))
637       << "Should not be able to apply to current slot.";
638 }
639 
640 TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
641   ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
642       source(),
643       target(),
644       PartitionSizesToManifest({{"foo", 4_MiB}}),
645       false,
646       nullptr));
647   dynamicControl().set_fake_mapped_devices({T("foo")});
648 
649   InstallOperation iop;
650   InstallOperation optimized;
651   Extent *se, *de;
652 
653   // Not a SOURCE_COPY operation, cannot skip.
654   iop.set_type(InstallOperation::REPLACE);
655   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
656 
657   iop.set_type(InstallOperation::SOURCE_COPY);
658 
659   // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
660   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
661 
662   // Enable GetVirtualAbFeatureFlag in the mock interface.
663   ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
664       .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
665 
666   // By default target_supports_snapshot_ is set to false. Cannot skip
667   // operation.
668   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
669 
670   SetSnapshotEnabled(true);
671 
672   // Empty source and destination. Skip.
673   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
674   EXPECT_TRUE(optimized.src_extents().empty());
675   EXPECT_TRUE(optimized.dst_extents().empty());
676 
677   se = iop.add_src_extents();
678   se->set_start_block(0);
679   se->set_num_blocks(1);
680 
681   // There is something in sources, but destinations are empty. Cannot skip.
682   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
683 
684   InstallOperation iop2;
685 
686   de = iop2.add_dst_extents();
687   de->set_start_block(0);
688   de->set_num_blocks(1);
689 
690   // There is something in destinations, but sources are empty. Cannot skip.
691   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
692 
693   de = iop.add_dst_extents();
694   de->set_start_block(0);
695   de->set_num_blocks(1);
696 
697   // Sources and destinations are identical. Skip.
698   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
699   EXPECT_TRUE(optimized.src_extents().empty());
700   EXPECT_TRUE(optimized.dst_extents().empty());
701 
702   se = iop.add_src_extents();
703   se->set_start_block(1);
704   se->set_num_blocks(5);
705 
706   // There is something in source, but not in destination. Cannot skip.
707   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
708 
709   de = iop.add_dst_extents();
710   de->set_start_block(1);
711   de->set_num_blocks(5);
712 
713   // There is source and destination are equal. Skip.
714   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
715   EXPECT_TRUE(optimized.src_extents().empty());
716   EXPECT_TRUE(optimized.dst_extents().empty());
717 
718   de = iop.add_dst_extents();
719   de->set_start_block(6);
720   de->set_num_blocks(5);
721 
722   // There is something extra in dest. Cannot skip.
723   EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
724 
725   se = iop.add_src_extents();
726   se->set_start_block(6);
727   se->set_num_blocks(5);
728 
729   // Source and dest are identical again. Skip.
730   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
731   EXPECT_TRUE(optimized.src_extents().empty());
732   EXPECT_TRUE(optimized.dst_extents().empty());
733 
734   iop.Clear();
735   iop.set_type(InstallOperation::SOURCE_COPY);
736   se = iop.add_src_extents();
737   se->set_start_block(1);
738   se->set_num_blocks(1);
739   se = iop.add_src_extents();
740   se->set_start_block(3);
741   se->set_num_blocks(2);
742   se = iop.add_src_extents();
743   se->set_start_block(7);
744   se->set_num_blocks(2);
745   de = iop.add_dst_extents();
746   de->set_start_block(2);
747   de->set_num_blocks(5);
748 
749   // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
750   EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
751   ASSERT_EQ(2, optimized.src_extents_size());
752   ASSERT_EQ(2, optimized.dst_extents_size());
753   EXPECT_EQ(1u, optimized.src_extents(0).start_block());
754   EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
755   EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
756   EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
757   EXPECT_EQ(7u, optimized.src_extents(1).start_block());
758   EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
759   EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
760   EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
761 
762   // Don't skip for static partitions.
763   EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
764 }
765 
766 TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
767   MockPrefs prefs;
768   ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
769 }
770 
771 TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
772   // clang-format off
773   std::string fstab_content =
774       "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical\n"  // NOLINT(whitespace/line_length)
775       "/dev/block/by-name/system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other\n";  // NOLINT(whitespace/line_length)
776   // clang-format on
777   ScopedTempFile fstab;
778   ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
779   ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
780               Optional(false));
781 }
782 
783 TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
784   // clang-format off
785   std::string fstab_content =
786       "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical,avb_keys=/foo\n";  // NOLINT(whitespace/line_length)
787   // clang-format on
788   ScopedTempFile fstab;
789   ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
790   ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
791               Optional(true));
792 }
793 
794 TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
795   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
796       .WillByDefault(Invoke([&](auto source_slot,
797                                 auto target_slot,
798                                 const auto& name,
799                                 auto path,
800                                 auto should_unmap) {
801         return dynamicControl().RealGetSystemOtherPath(
802             source_slot, target_slot, name, path, should_unmap);
803       }));
804   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
805       .WillByDefault(Return(false));
806   EXPECT_TRUE(
807       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
808 }
809 
810 TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
811   SetMetadata(source(), {{S("system"), 100_MiB}});
812   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
813       .WillByDefault(Return(true));
814   std::string path;
815   bool should_unmap;
816   ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
817       source(), target(), T("system"), &path, &should_unmap));
818   ASSERT_TRUE(path.empty()) << path;
819   ASSERT_FALSE(should_unmap);
820   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
821       .WillByDefault(Invoke([&](auto source_slot,
822                                 auto target_slot,
823                                 const auto& name,
824                                 auto path,
825                                 auto should_unmap) {
826         return dynamicControl().RealGetSystemOtherPath(
827             source_slot, target_slot, name, path, should_unmap);
828       }));
829   EXPECT_TRUE(
830       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
831 }
832 
833 TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
834   PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
835   SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
836   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
837       .WillByDefault(Return(true));
838   std::string path;
839   bool should_unmap;
840   ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
841       source(), target(), T("system"), &path, &should_unmap));
842   ASSERT_TRUE(path.empty()) << path;
843   ASSERT_FALSE(should_unmap);
844   ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
845       .WillByDefault(Invoke([&](auto source_slot,
846                                 auto target_slot,
847                                 const auto& name,
848                                 auto path,
849                                 auto should_unmap) {
850         return dynamicControl().RealGetSystemOtherPath(
851             source_slot, target_slot, name, path, should_unmap);
852       }));
853   EXPECT_TRUE(
854       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
855 }
856 
857 TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
858   constexpr uint64_t file_size = 1_MiB;
859   static_assert(file_size > AVB_FOOTER_SIZE);
860   ScopedTempFile system_other;
861   brillo::Blob original(file_size, 'X');
862   ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
863   std::string mnt_path;
864   ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
865   ASSERT_TRUE(dev.is_bound());
866 
867   brillo::Blob device_content;
868   ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
869   ASSERT_EQ(original, device_content);
870 
871   PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
872   SetMetadata(source(), sizes);
873   ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
874       .WillByDefault(Return(true));
875   EXPECT_CALL(dynamicControl(),
876               GetSystemOtherPath(source(), target(), T("system"), _, _))
877       .WillRepeatedly(
878           Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
879             *path = mnt_path;
880             *should_unmap = false;
881             return true;
882           }));
883   ASSERT_TRUE(
884       dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
885 
886   device_content.clear();
887   ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
888   brillo::Blob new_expected(original);
889   // Clear the last AVB_FOOTER_SIZE bytes.
890   new_expected.resize(file_size - AVB_FOOTER_SIZE);
891   new_expected.resize(file_size, '\0');
892   ASSERT_EQ(new_expected, device_content);
893 }
894 
895 }  // namespace chromeos_update_engine
896