• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2018 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "update_engine/boot_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 <fs_mgr.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 #include <libdm/dm.h>
28 
29 #include "update_engine/mock_boot_control_hal.h"
30 #include "update_engine/mock_dynamic_partition_control.h"
31 
32 using android::dm::DmDeviceState;
33 using android::fs_mgr::MetadataBuilder;
34 using android::hardware::Void;
35 using std::string;
36 using testing::_;
37 using testing::AnyNumber;
38 using testing::Contains;
39 using testing::Eq;
40 using testing::Invoke;
41 using testing::Key;
42 using testing::MakeMatcher;
43 using testing::Matcher;
44 using testing::MatcherInterface;
45 using testing::MatchResultListener;
46 using testing::NiceMock;
47 using testing::Not;
48 using testing::Return;
49 
50 namespace chromeos_update_engine {
51 
52 constexpr const uint32_t kMaxNumSlots = 2;
53 constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
54 constexpr const char* kFakeDevicePath = "/fake/dev/path/";
55 constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/";
56 constexpr const uint32_t kFakeMetadataSize = 65536;
57 constexpr const char* kDefaultGroup = "foo";
58 
59 // A map describing the size of each partition.
60 // "{name, size}"
61 using PartitionSizes = std::map<string, uint64_t>;
62 
63 // "{name_a, size}"
64 using PartitionSuffixSizes = std::map<string, uint64_t>;
65 
66 using PartitionMetadata = BootControlInterface::PartitionMetadata;
67 
68 // C++ standards do not allow uint64_t (aka unsigned long) to be the parameter
69 // of user-defined literal operators.
operator ""_MiB(unsigned long long x)70 constexpr unsigned long long operator"" _MiB(unsigned long long x) {  // NOLINT
71   return x << 20;
72 }
operator ""_GiB(unsigned long long x)73 constexpr unsigned long long operator"" _GiB(unsigned long long x) {  // NOLINT
74   return x << 30;
75 }
76 
77 constexpr uint64_t kDefaultGroupSize = 5_GiB;
78 // Super device size. 1 MiB for metadata.
79 constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
80 
81 template <typename U, typename V>
operator <<(std::ostream & os,const std::map<U,V> & param)82 std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
83   os << "{";
84   bool first = true;
85   for (const auto& pair : param) {
86     if (!first)
87       os << ", ";
88     os << pair.first << ":" << pair.second;
89     first = false;
90   }
91   return os << "}";
92 }
93 
94 template <typename T>
operator <<(std::ostream & os,const std::vector<T> & param)95 std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) {
96   os << "[";
97   bool first = true;
98   for (const auto& e : param) {
99     if (!first)
100       os << ", ";
101     os << e;
102     first = false;
103   }
104   return os << "]";
105 }
106 
operator <<(std::ostream & os,const PartitionMetadata::Partition & p)107 std::ostream& operator<<(std::ostream& os,
108                          const PartitionMetadata::Partition& p) {
109   return os << "{" << p.name << ", " << p.size << "}";
110 }
111 
operator <<(std::ostream & os,const PartitionMetadata::Group & g)112 std::ostream& operator<<(std::ostream& os, const PartitionMetadata::Group& g) {
113   return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}";
114 }
115 
operator <<(std::ostream & os,const PartitionMetadata & m)116 std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) {
117   return os << m.groups;
118 }
119 
GetDevice(const string & name)120 inline string GetDevice(const string& name) {
121   return kFakeDevicePath + name;
122 }
123 
GetDmDevice(const string & name)124 inline string GetDmDevice(const string& name) {
125   return kFakeDmDevicePath + name;
126 }
127 
128 // TODO(elsk): fs_mgr_get_super_partition_name should be mocked.
GetSuperDevice(uint32_t slot)129 inline string GetSuperDevice(uint32_t slot) {
130   return GetDevice(fs_mgr_get_super_partition_name(slot));
131 }
132 
133 struct TestParam {
134   uint32_t source;
135   uint32_t target;
136 };
operator <<(std::ostream & os,const TestParam & param)137 std::ostream& operator<<(std::ostream& os, const TestParam& param) {
138   return os << "{source: " << param.source << ", target:" << param.target
139             << "}";
140 }
141 
142 // To support legacy tests, auto-convert {name_a: size} map to
143 // PartitionMetadata.
partitionSuffixSizesToMetadata(const PartitionSuffixSizes & partition_sizes)144 PartitionMetadata partitionSuffixSizesToMetadata(
145     const PartitionSuffixSizes& partition_sizes) {
146   PartitionMetadata metadata;
147   for (const char* suffix : kSlotSuffixes) {
148     metadata.groups.push_back(
149         {string(kDefaultGroup) + suffix, kDefaultGroupSize, {}});
150   }
151   for (const auto& pair : partition_sizes) {
152     for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
153       if (base::EndsWith(pair.first,
154                          kSlotSuffixes[suffix_idx],
155                          base::CompareCase::SENSITIVE)) {
156         metadata.groups[suffix_idx].partitions.push_back(
157             {pair.first, pair.second});
158       }
159     }
160   }
161   return metadata;
162 }
163 
164 // To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
partitionSizesToMetadata(const PartitionSizes & partition_sizes)165 PartitionMetadata partitionSizesToMetadata(
166     const PartitionSizes& partition_sizes) {
167   PartitionMetadata metadata;
168   metadata.groups.push_back({string{kDefaultGroup}, kDefaultGroupSize, {}});
169   for (const auto& pair : partition_sizes) {
170     metadata.groups[0].partitions.push_back({pair.first, pair.second});
171   }
172   return metadata;
173 }
174 
NewFakeMetadata(const PartitionMetadata & metadata)175 std::unique_ptr<MetadataBuilder> NewFakeMetadata(
176     const PartitionMetadata& metadata) {
177   auto builder =
178       MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
179   EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2);
180   EXPECT_NE(nullptr, builder);
181   if (builder == nullptr)
182     return nullptr;
183   for (const auto& group : metadata.groups) {
184     EXPECT_TRUE(builder->AddGroup(group.name, group.size));
185     for (const auto& partition : group.partitions) {
186       auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */);
187       EXPECT_TRUE(p && builder->ResizePartition(p, partition.size));
188     }
189   }
190   return builder;
191 }
192 
193 class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
194  public:
MetadataMatcher(const PartitionSuffixSizes & partition_sizes)195   explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
196       : partition_metadata_(partitionSuffixSizesToMetadata(partition_sizes)) {}
MetadataMatcher(const PartitionMetadata & partition_metadata)197   explicit MetadataMatcher(const PartitionMetadata& partition_metadata)
198       : partition_metadata_(partition_metadata) {}
199 
MatchAndExplain(MetadataBuilder * metadata,MatchResultListener * listener) const200   bool MatchAndExplain(MetadataBuilder* metadata,
201                        MatchResultListener* listener) const override {
202     bool success = true;
203     for (const auto& group : partition_metadata_.groups) {
204       for (const auto& partition : group.partitions) {
205         auto p = metadata->FindPartition(partition.name);
206         if (p == nullptr) {
207           if (!success)
208             *listener << "; ";
209           *listener << "No partition " << partition.name;
210           success = false;
211           continue;
212         }
213         if (p->size() != partition.size) {
214           if (!success)
215             *listener << "; ";
216           *listener << "Partition " << partition.name << " has size "
217                     << p->size() << ", expected " << partition.size;
218           success = false;
219         }
220         if (p->group_name() != group.name) {
221           if (!success)
222             *listener << "; ";
223           *listener << "Partition " << partition.name << " has group "
224                     << p->group_name() << ", expected " << group.name;
225           success = false;
226         }
227       }
228     }
229     return success;
230   }
231 
DescribeTo(std::ostream * os) const232   void DescribeTo(std::ostream* os) const override {
233     *os << "expect: " << partition_metadata_;
234   }
235 
DescribeNegationTo(std::ostream * os) const236   void DescribeNegationTo(std::ostream* os) const override {
237     *os << "expect not: " << partition_metadata_;
238   }
239 
240  private:
241   PartitionMetadata partition_metadata_;
242 };
243 
MetadataMatches(const PartitionSuffixSizes & partition_sizes)244 inline Matcher<MetadataBuilder*> MetadataMatches(
245     const PartitionSuffixSizes& partition_sizes) {
246   return MakeMatcher(new MetadataMatcher(partition_sizes));
247 }
248 
MetadataMatches(const PartitionMetadata & partition_metadata)249 inline Matcher<MetadataBuilder*> MetadataMatches(
250     const PartitionMetadata& partition_metadata) {
251   return MakeMatcher(new MetadataMatcher(partition_metadata));
252 }
253 
254 MATCHER_P(HasGroup, group, " has group " + group) {
255   auto groups = arg->ListGroups();
256   return std::find(groups.begin(), groups.end(), group) != groups.end();
257 }
258 
259 class BootControlAndroidTest : public ::testing::Test {
260  protected:
SetUp()261   void SetUp() override {
262     // Fake init bootctl_
263     bootctl_.module_ = new NiceMock<MockBootControlHal>();
264     bootctl_.dynamic_control_ =
265         std::make_unique<NiceMock<MockDynamicPartitionControl>>();
266 
267     ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] {
268       return kMaxNumSlots;
269     }));
270     ON_CALL(module(), getSuffix(_, _))
271         .WillByDefault(Invoke([](auto slot, auto cb) {
272           EXPECT_LE(slot, kMaxNumSlots);
273           cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : "");
274           return Void();
275         }));
276 
277     ON_CALL(dynamicControl(), IsDynamicPartitionsEnabled())
278         .WillByDefault(Return(true));
279     ON_CALL(dynamicControl(), IsDynamicPartitionsRetrofit())
280         .WillByDefault(Return(false));
281     ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true));
282     ON_CALL(dynamicControl(), GetDeviceDir(_))
283         .WillByDefault(Invoke([](auto path) {
284           *path = kFakeDevicePath;
285           return true;
286         }));
287     ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
288         .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
289           *device = GetDmDevice(partition_name_suffix);
290           return true;
291         }));
292   }
293 
294   // Return the mocked HAL module.
module()295   NiceMock<MockBootControlHal>& module() {
296     return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
297   }
298 
299   // Return the mocked DynamicPartitionControlInterface.
dynamicControl()300   NiceMock<MockDynamicPartitionControl>& dynamicControl() {
301     return static_cast<NiceMock<MockDynamicPartitionControl>&>(
302         *bootctl_.dynamic_control_);
303   }
304 
305   // Set the fake metadata to return when LoadMetadataBuilder is called on
306   // |slot|.
SetMetadata(uint32_t slot,const PartitionSuffixSizes & sizes)307   void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
308     SetMetadata(slot, partitionSuffixSizesToMetadata(sizes));
309   }
310 
SetMetadata(uint32_t slot,const PartitionMetadata & metadata)311   void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) {
312     EXPECT_CALL(dynamicControl(),
313                 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
314         .Times(AnyNumber())
315         .WillRepeatedly(Invoke([metadata](auto, auto, auto) {
316           return NewFakeMetadata(metadata);
317         }));
318   }
319 
320   // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
321   // slot with each partition in |partitions|.
ExpectUnmap(const std::set<string> & partitions)322   void ExpectUnmap(const std::set<string>& partitions) {
323     // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
324     ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
325         .WillByDefault(Return(false));
326 
327     for (const auto& partition : partitions) {
328       EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
329           .WillOnce(Invoke([this](auto partition, auto) {
330             mapped_devices_.erase(partition);
331             return true;
332           }));
333     }
334   }
335 
ExpectDevicesAreMapped(const std::set<string> & partitions)336   void ExpectDevicesAreMapped(const std::set<string>& partitions) {
337     ASSERT_EQ(partitions.size(), mapped_devices_.size());
338     for (const auto& partition : partitions) {
339       EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
340           << "Expect that " << partition << " is mapped, but it is not.";
341     }
342   }
343 
ExpectStoreMetadata(const PartitionSuffixSizes & partition_sizes)344   void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
345     ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
346   }
347 
ExpectStoreMetadataMatch(const Matcher<MetadataBuilder * > & matcher)348   virtual void ExpectStoreMetadataMatch(
349       const Matcher<MetadataBuilder*>& matcher) {
350     EXPECT_CALL(dynamicControl(),
351                 StoreMetadata(GetSuperDevice(target()), matcher, target()))
352         .WillOnce(Return(true));
353   }
354 
source()355   uint32_t source() { return slots_.source; }
356 
target()357   uint32_t target() { return slots_.target; }
358 
359   // Return partition names with suffix of source().
S(const string & name)360   string S(const string& name) { return name + kSlotSuffixes[source()]; }
361 
362   // Return partition names with suffix of target().
T(const string & name)363   string T(const string& name) { return name + kSlotSuffixes[target()]; }
364 
365   // Set source and target slots to use before testing.
SetSlots(const TestParam & slots)366   void SetSlots(const TestParam& slots) {
367     slots_ = slots;
368 
369     ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
370       return source();
371     }));
372     // Should not store metadata to source slot.
373     EXPECT_CALL(dynamicControl(),
374                 StoreMetadata(GetSuperDevice(source()), _, source()))
375         .Times(0);
376     // Should not load metadata from target slot.
377     EXPECT_CALL(dynamicControl(),
378                 LoadMetadataBuilder(GetSuperDevice(target()), target(), _))
379         .Times(0);
380   }
381 
InitPartitionMetadata(uint32_t slot,PartitionSizes partition_sizes,bool update_metadata=true)382   bool InitPartitionMetadata(uint32_t slot,
383                              PartitionSizes partition_sizes,
384                              bool update_metadata = true) {
385     auto m = partitionSizesToMetadata(partition_sizes);
386     LOG(INFO) << m;
387     return bootctl_.InitPartitionMetadata(slot, m, update_metadata);
388   }
389 
390   BootControlAndroid bootctl_;  // BootControlAndroid under test.
391   TestParam slots_;
392   // mapped devices through MapPartitionOnDeviceMapper.
393   std::map<string, string> mapped_devices_;
394 };
395 
396 class BootControlAndroidTestP
397     : public BootControlAndroidTest,
398       public ::testing::WithParamInterface<TestParam> {
399  public:
SetUp()400   void SetUp() override {
401     BootControlAndroidTest::SetUp();
402     SetSlots(GetParam());
403   }
404 };
405 
406 // Test resize case. Grow if target metadata contains a partition with a size
407 // less than expected.
TEST_P(BootControlAndroidTestP,NeedGrowIfSizeNotMatchWhenResizing)408 TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
409   SetMetadata(source(),
410               {{S("system"), 2_GiB},
411                {S("vendor"), 1_GiB},
412                {T("system"), 2_GiB},
413                {T("vendor"), 1_GiB}});
414   ExpectStoreMetadata({{S("system"), 2_GiB},
415                        {S("vendor"), 1_GiB},
416                        {T("system"), 3_GiB},
417                        {T("vendor"), 1_GiB}});
418   ExpectUnmap({T("system"), T("vendor")});
419 
420   EXPECT_TRUE(
421       InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
422 }
423 
424 // Test resize case. Shrink if target metadata contains a partition with a size
425 // greater than expected.
TEST_P(BootControlAndroidTestP,NeedShrinkIfSizeNotMatchWhenResizing)426 TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
427   SetMetadata(source(),
428               {{S("system"), 2_GiB},
429                {S("vendor"), 1_GiB},
430                {T("system"), 2_GiB},
431                {T("vendor"), 1_GiB}});
432   ExpectStoreMetadata({{S("system"), 2_GiB},
433                        {S("vendor"), 1_GiB},
434                        {T("system"), 2_GiB},
435                        {T("vendor"), 150_MiB}});
436   ExpectUnmap({T("system"), T("vendor")});
437 
438   EXPECT_TRUE(InitPartitionMetadata(target(),
439                                     {{"system", 2_GiB}, {"vendor", 150_MiB}}));
440 }
441 
442 // Test adding partitions on the first run.
TEST_P(BootControlAndroidTestP,AddPartitionToEmptyMetadata)443 TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
444   SetMetadata(source(), PartitionSuffixSizes{});
445   ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
446   ExpectUnmap({T("system"), T("vendor")});
447 
448   EXPECT_TRUE(
449       InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
450 }
451 
452 // Test subsequent add case.
TEST_P(BootControlAndroidTestP,AddAdditionalPartition)453 TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
454   SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
455   ExpectStoreMetadata(
456       {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
457   ExpectUnmap({T("system"), T("vendor")});
458 
459   EXPECT_TRUE(
460       InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
461 }
462 
463 // Test delete one partition.
TEST_P(BootControlAndroidTestP,DeletePartition)464 TEST_P(BootControlAndroidTestP, DeletePartition) {
465   SetMetadata(source(),
466               {{S("system"), 2_GiB},
467                {S("vendor"), 1_GiB},
468                {T("system"), 2_GiB},
469                {T("vendor"), 1_GiB}});
470   // No T("vendor")
471   ExpectStoreMetadata(
472       {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
473   ExpectUnmap({T("system")});
474 
475   EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
476 }
477 
478 // Test delete all partitions.
TEST_P(BootControlAndroidTestP,DeleteAll)479 TEST_P(BootControlAndroidTestP, DeleteAll) {
480   SetMetadata(source(),
481               {{S("system"), 2_GiB},
482                {S("vendor"), 1_GiB},
483                {T("system"), 2_GiB},
484                {T("vendor"), 1_GiB}});
485   ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
486 
487   EXPECT_TRUE(InitPartitionMetadata(target(), {}));
488 }
489 
490 // Test corrupt source metadata case.
TEST_P(BootControlAndroidTestP,CorruptedSourceMetadata)491 TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
492   EXPECT_CALL(dynamicControl(),
493               LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
494       .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
495   ExpectUnmap({T("system")});
496 
497   EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
498       << "Should not be able to continue with corrupt source metadata";
499 }
500 
501 // Test that InitPartitionMetadata fail if there is not enough space on the
502 // device.
TEST_P(BootControlAndroidTestP,NotEnoughSpace)503 TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
504   SetMetadata(source(),
505               {{S("system"), 3_GiB},
506                {S("vendor"), 2_GiB},
507                {T("system"), 0},
508                {T("vendor"), 0}});
509   EXPECT_FALSE(
510       InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
511       << "Should not be able to fit 11GiB data into 10GiB space";
512 }
513 
TEST_P(BootControlAndroidTestP,NotEnoughSpaceForSlot)514 TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
515   SetMetadata(source(),
516               {{S("system"), 1_GiB},
517                {S("vendor"), 1_GiB},
518                {T("system"), 0},
519                {T("vendor"), 0}});
520   EXPECT_FALSE(
521       InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
522       << "Should not be able to grow over size of super / 2";
523 }
524 
525 // Test applying retrofit update on a build with dynamic partitions enabled.
TEST_P(BootControlAndroidTestP,ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild)526 TEST_P(BootControlAndroidTestP,
527        ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
528   SetMetadata(source(),
529               {{S("system"), 2_GiB},
530                {S("vendor"), 1_GiB},
531                {T("system"), 2_GiB},
532                {T("vendor"), 1_GiB}});
533   // Should not try to unmap any target partition.
534   EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _)).Times(0);
535   // Should not store metadata to target slot.
536   EXPECT_CALL(dynamicControl(),
537               StoreMetadata(GetSuperDevice(target()), _, target()))
538       .Times(0);
539 
540   // Not calling through BootControlAndroidTest::InitPartitionMetadata(), since
541   // we don't want any default group in the PartitionMetadata.
542   EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}, true));
543 
544   // Should use dynamic source partitions.
545   EXPECT_CALL(dynamicControl(), GetState(S("system")))
546       .Times(1)
547       .WillOnce(Return(DmDeviceState::ACTIVE));
548   string system_device;
549   EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device));
550   EXPECT_EQ(GetDmDevice(S("system")), system_device);
551 
552   // Should use static target partitions without querying dynamic control.
553   EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
554   EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device));
555   EXPECT_EQ(GetDevice(T("system")), system_device);
556 
557   // Static partition "bar".
558   EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
559   std::string bar_device;
560   EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device));
561   EXPECT_EQ(GetDevice(S("bar")), bar_device);
562 
563   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
564   EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device));
565   EXPECT_EQ(GetDevice(T("bar")), bar_device);
566 }
567 
TEST_P(BootControlAndroidTestP,GetPartitionDeviceWhenResumingUpdate)568 TEST_P(BootControlAndroidTestP, GetPartitionDeviceWhenResumingUpdate) {
569   // Both of the two slots contain valid partition metadata, since this is
570   // resuming an update.
571   SetMetadata(source(),
572               {{S("system"), 2_GiB},
573                {S("vendor"), 1_GiB},
574                {T("system"), 2_GiB},
575                {T("vendor"), 1_GiB}});
576   SetMetadata(target(),
577               {{S("system"), 2_GiB},
578                {S("vendor"), 1_GiB},
579                {T("system"), 2_GiB},
580                {T("vendor"), 1_GiB}});
581   EXPECT_CALL(dynamicControl(),
582               StoreMetadata(GetSuperDevice(target()), _, target()))
583       .Times(0);
584   EXPECT_TRUE(InitPartitionMetadata(
585       target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}, false));
586 
587   // Dynamic partition "system".
588   EXPECT_CALL(dynamicControl(), GetState(S("system")))
589       .Times(1)
590       .WillOnce(Return(DmDeviceState::ACTIVE));
591   string system_device;
592   EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device));
593   EXPECT_EQ(GetDmDevice(S("system")), system_device);
594 
595   EXPECT_CALL(dynamicControl(), GetState(T("system")))
596       .Times(AnyNumber())
597       .WillOnce(Return(DmDeviceState::ACTIVE));
598   EXPECT_CALL(dynamicControl(),
599               MapPartitionOnDeviceMapper(
600                   GetSuperDevice(target()), T("system"), target(), _, _))
601       .Times(AnyNumber())
602       .WillRepeatedly(
603           Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
604             *device = "/fake/remapped/" + name;
605             return true;
606           }));
607   EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device));
608   EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
609 
610   // Static partition "bar".
611   EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
612   std::string bar_device;
613   EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device));
614   EXPECT_EQ(GetDevice(S("bar")), bar_device);
615 
616   EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
617   EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device));
618   EXPECT_EQ(GetDevice(T("bar")), bar_device);
619 }
620 
621 INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
622                         BootControlAndroidTestP,
623                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
624 
update_sizes_0()625 const PartitionSuffixSizes update_sizes_0() {
626   // Initial state is 0 for "other" slot.
627   return {
628       {"grown_a", 2_GiB},
629       {"shrunk_a", 1_GiB},
630       {"same_a", 100_MiB},
631       {"deleted_a", 150_MiB},
632       // no added_a
633       {"grown_b", 200_MiB},
634       // simulate system_other
635       {"shrunk_b", 0},
636       {"same_b", 0},
637       {"deleted_b", 0},
638       // no added_b
639   };
640 }
641 
update_sizes_1()642 const PartitionSuffixSizes update_sizes_1() {
643   return {
644       {"grown_a", 2_GiB},
645       {"shrunk_a", 1_GiB},
646       {"same_a", 100_MiB},
647       {"deleted_a", 150_MiB},
648       // no added_a
649       {"grown_b", 3_GiB},
650       {"shrunk_b", 150_MiB},
651       {"same_b", 100_MiB},
652       {"added_b", 150_MiB},
653       // no deleted_b
654   };
655 }
656 
update_sizes_2()657 const PartitionSuffixSizes update_sizes_2() {
658   return {
659       {"grown_a", 4_GiB},
660       {"shrunk_a", 100_MiB},
661       {"same_a", 100_MiB},
662       {"deleted_a", 64_MiB},
663       // no added_a
664       {"grown_b", 3_GiB},
665       {"shrunk_b", 150_MiB},
666       {"same_b", 100_MiB},
667       {"added_b", 150_MiB},
668       // no deleted_b
669   };
670 }
671 
672 // Test case for first update after the device is manufactured, in which
673 // case the "other" slot is likely of size "0" (except system, which is
674 // non-zero because of system_other partition)
TEST_F(BootControlAndroidTest,SimulatedFirstUpdate)675 TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
676   SetSlots({0, 1});
677 
678   SetMetadata(source(), update_sizes_0());
679   SetMetadata(target(), update_sizes_0());
680   ExpectStoreMetadata(update_sizes_1());
681   ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
682 
683   EXPECT_TRUE(InitPartitionMetadata(target(),
684                                     {{"grown", 3_GiB},
685                                      {"shrunk", 150_MiB},
686                                      {"same", 100_MiB},
687                                      {"added", 150_MiB}}));
688 }
689 
690 // After first update, test for the second update. In the second update, the
691 // "added" partition is deleted and "deleted" partition is re-added.
TEST_F(BootControlAndroidTest,SimulatedSecondUpdate)692 TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
693   SetSlots({1, 0});
694 
695   SetMetadata(source(), update_sizes_1());
696   SetMetadata(target(), update_sizes_0());
697 
698   ExpectStoreMetadata(update_sizes_2());
699   ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
700 
701   EXPECT_TRUE(InitPartitionMetadata(target(),
702                                     {{"grown", 4_GiB},
703                                      {"shrunk", 100_MiB},
704                                      {"same", 100_MiB},
705                                      {"deleted", 64_MiB}}));
706 }
707 
TEST_F(BootControlAndroidTest,ApplyingToCurrentSlot)708 TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
709   SetSlots({1, 1});
710   EXPECT_FALSE(InitPartitionMetadata(target(), {}))
711       << "Should not be able to apply to current slot.";
712 }
713 
714 class BootControlAndroidGroupTestP : public BootControlAndroidTestP {
715  public:
SetUp()716   void SetUp() override {
717     BootControlAndroidTestP::SetUp();
718     SetMetadata(
719         source(),
720         {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
721                     SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB),
722                     SimpleGroup(T("android"), 3_GiB, T("system"), 0),
723                     SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}});
724   }
725 
726   // Return a simple group with only one partition.
SimpleGroup(const string & group,uint64_t group_size,const string & partition,uint64_t partition_size)727   PartitionMetadata::Group SimpleGroup(const string& group,
728                                        uint64_t group_size,
729                                        const string& partition,
730                                        uint64_t partition_size) {
731     return {.name = group,
732             .size = group_size,
733             .partitions = {{.name = partition, .size = partition_size}}};
734   }
735 
ExpectStoreMetadata(const PartitionMetadata & partition_metadata)736   void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) {
737     ExpectStoreMetadataMatch(MetadataMatches(partition_metadata));
738   }
739 
740   // Expect that target slot is stored with target groups.
ExpectStoreMetadataMatch(const Matcher<MetadataBuilder * > & matcher)741   void ExpectStoreMetadataMatch(
742       const Matcher<MetadataBuilder*>& matcher) override {
743     BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf(
744         MetadataMatches(PartitionMetadata{
745             .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
746                        SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}),
747         matcher));
748   }
749 };
750 
751 // Allow to resize within group.
TEST_P(BootControlAndroidGroupTestP,ResizeWithinGroup)752 TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
753   ExpectStoreMetadata(PartitionMetadata{
754       .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
755                  SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
756   ExpectUnmap({T("system"), T("vendor")});
757 
758   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
759       target(),
760       PartitionMetadata{
761           .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
762                      SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
763       true));
764 }
765 
TEST_P(BootControlAndroidGroupTestP,NotEnoughSpaceForGroup)766 TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
767   EXPECT_FALSE(bootctl_.InitPartitionMetadata(
768       target(),
769       PartitionMetadata{
770           .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
771                      SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}},
772       true))
773       << "Should not be able to grow over maximum size of group";
774 }
775 
TEST_P(BootControlAndroidGroupTestP,GroupTooBig)776 TEST_P(BootControlAndroidGroupTestP, GroupTooBig) {
777   EXPECT_FALSE(bootctl_.InitPartitionMetadata(
778       target(),
779       PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
780                                    {.name = "oem", .size = 3_GiB}}},
781       true))
782       << "Should not be able to grow over size of super / 2";
783 }
784 
TEST_P(BootControlAndroidGroupTestP,AddPartitionToGroup)785 TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
786   ExpectStoreMetadata(PartitionMetadata{
787       .groups = {
788           {.name = T("android"),
789            .size = 3_GiB,
790            .partitions = {{.name = T("system"), .size = 2_GiB},
791                           {.name = T("product_services"), .size = 1_GiB}}}}});
792   ExpectUnmap({T("system"), T("vendor"), T("product_services")});
793 
794   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
795       target(),
796       PartitionMetadata{
797           .groups = {{.name = "android",
798                       .size = 3_GiB,
799                       .partitions = {{.name = "system", .size = 2_GiB},
800                                      {.name = "product_services",
801                                       .size = 1_GiB}}},
802                      SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
803       true));
804 }
805 
TEST_P(BootControlAndroidGroupTestP,RemovePartitionFromGroup)806 TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
807   ExpectStoreMetadata(PartitionMetadata{
808       .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
809   ExpectUnmap({T("vendor")});
810 
811   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
812       target(),
813       PartitionMetadata{
814           .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
815                      SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
816       true));
817 }
818 
TEST_P(BootControlAndroidGroupTestP,AddGroup)819 TEST_P(BootControlAndroidGroupTestP, AddGroup) {
820   ExpectStoreMetadata(PartitionMetadata{
821       .groups = {
822           SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
823   ExpectUnmap({T("system"), T("vendor"), T("new_partition")});
824 
825   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
826       target(),
827       PartitionMetadata{
828           .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
829                      SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
830                      SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}},
831       true));
832 }
833 
TEST_P(BootControlAndroidGroupTestP,RemoveGroup)834 TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
835   ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
836   ExpectUnmap({T("system")});
837   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
838       target(),
839       PartitionMetadata{
840           .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}},
841       true));
842 }
843 
TEST_P(BootControlAndroidGroupTestP,ResizeGroup)844 TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
845   ExpectStoreMetadata(PartitionMetadata{
846       .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
847                  SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
848   ExpectUnmap({T("system"), T("vendor")});
849 
850   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
851       target(),
852       PartitionMetadata{
853           .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
854                      SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}},
855       true));
856 }
857 
858 INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
859                         BootControlAndroidGroupTestP,
860                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
861 
862 }  // namespace chromeos_update_engine
863