blob: 79f866257e316401b66df334341e3ab605967493 [file] [log] [blame]
Yifan Hong537802d2018-08-15 13:15:42 -07001//
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>
Yifan Hongd4db07e2018-10-18 17:46:27 -070020#include <vector>
Yifan Hong537802d2018-08-15 13:15:42 -070021
Yifan Hongd4db07e2018-10-18 17:46:27 -070022#include <base/logging.h>
23#include <base/strings/string_util.h>
David Andersond63cb3c2018-10-01 14:15:00 -070024#include <fs_mgr.h>
Yifan Hong537802d2018-08-15 13:15:42 -070025#include <gmock/gmock.h>
26#include <gtest/gtest.h>
Yifan Hong1d9077f2018-12-07 12:09:37 -080027#include <libdm/dm.h>
Yifan Hong537802d2018-08-15 13:15:42 -070028
29#include "update_engine/mock_boot_control_hal.h"
30#include "update_engine/mock_dynamic_partition_control.h"
31
Yifan Hong1d9077f2018-12-07 12:09:37 -080032using android::dm::DmDeviceState;
Yifan Hong537802d2018-08-15 13:15:42 -070033using android::fs_mgr::MetadataBuilder;
34using android::hardware::Void;
35using testing::_;
36using testing::AnyNumber;
37using testing::Contains;
38using testing::Eq;
39using testing::Invoke;
40using testing::Key;
41using testing::MakeMatcher;
42using testing::Matcher;
43using testing::MatcherInterface;
44using testing::MatchResultListener;
45using testing::NiceMock;
Yifan Hongd4db07e2018-10-18 17:46:27 -070046using testing::Not;
Yifan Hong537802d2018-08-15 13:15:42 -070047using testing::Return;
48
49namespace chromeos_update_engine {
50
51constexpr const uint32_t kMaxNumSlots = 2;
52constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
53constexpr const char* kFakeDevicePath = "/fake/dev/path/";
Yifan Hong1d9077f2018-12-07 12:09:37 -080054constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/";
Yifan Hong537802d2018-08-15 13:15:42 -070055constexpr const uint32_t kFakeMetadataSize = 65536;
Yifan Hongd4db07e2018-10-18 17:46:27 -070056constexpr const char* kDefaultGroup = "foo";
57
58// "vendor"
59struct PartitionName : std::string {
60 using std::string::string;
61};
62
63// "vendor_a"
64struct PartitionNameSuffix : std::string {
65 using std::string::string;
66};
Yifan Hong537802d2018-08-15 13:15:42 -070067
68// A map describing the size of each partition.
Yifan Hongd4db07e2018-10-18 17:46:27 -070069using PartitionSizes = std::map<PartitionName, uint64_t>;
70using PartitionSuffixSizes = std::map<PartitionNameSuffix, uint64_t>;
71
72using PartitionMetadata = BootControlInterface::PartitionMetadata;
Yifan Hong537802d2018-08-15 13:15:42 -070073
74// C++ standards do not allow uint64_t (aka unsigned long) to be the parameter
75// of user-defined literal operators.
Yifan Hongd4db07e2018-10-18 17:46:27 -070076constexpr unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT
Yifan Hong537802d2018-08-15 13:15:42 -070077 return x << 20;
78}
Yifan Hongd4db07e2018-10-18 17:46:27 -070079constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
Yifan Hong537802d2018-08-15 13:15:42 -070080 return x << 30;
81}
82
Yifan Hongd4db07e2018-10-18 17:46:27 -070083constexpr uint64_t kDefaultGroupSize = 5_GiB;
84// Super device size. 1 MiB for metadata.
85constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
86
Yifan Hong537802d2018-08-15 13:15:42 -070087template <typename U, typename V>
88std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
89 os << "{";
90 bool first = true;
91 for (const auto& pair : param) {
92 if (!first)
93 os << ", ";
94 os << pair.first << ":" << pair.second;
95 first = false;
96 }
97 return os << "}";
98}
99
Yifan Hongd4db07e2018-10-18 17:46:27 -0700100template <typename T>
101std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) {
102 os << "[";
103 bool first = true;
104 for (const auto& e : param) {
105 if (!first)
106 os << ", ";
107 os << e;
108 first = false;
109 }
110 return os << "]";
111}
112
113std::ostream& operator<<(std::ostream& os,
114 const PartitionMetadata::Partition& p) {
115 return os << "{" << p.name << ", " << p.size << "}";
116}
117
118std::ostream& operator<<(std::ostream& os, const PartitionMetadata::Group& g) {
119 return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}";
120}
121
122std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) {
123 return os << m.groups;
124}
125
Yifan Hong537802d2018-08-15 13:15:42 -0700126inline std::string GetDevice(const std::string& name) {
127 return kFakeDevicePath + name;
128}
Yifan Hong30eb7b52018-11-20 11:05:46 -0800129
Yifan Hong1d9077f2018-12-07 12:09:37 -0800130inline std::string GetDmDevice(const std::string& name) {
131 return kFakeDmDevicePath + name;
132}
133
Yifan Hong30eb7b52018-11-20 11:05:46 -0800134// TODO(elsk): fs_mgr_get_super_partition_name should be mocked.
135inline std::string GetSuperDevice(uint32_t slot) {
136 return GetDevice(fs_mgr_get_super_partition_name(slot));
Yifan Hong537802d2018-08-15 13:15:42 -0700137}
138
139struct TestParam {
140 uint32_t source;
141 uint32_t target;
142};
143std::ostream& operator<<(std::ostream& os, const TestParam& param) {
144 return os << "{source: " << param.source << ", target:" << param.target
145 << "}";
146}
147
Yifan Hongd4db07e2018-10-18 17:46:27 -0700148// To support legacy tests, auto-convert {name_a: size} map to
149// PartitionMetadata.
150PartitionMetadata toMetadata(const PartitionSuffixSizes& partition_sizes) {
151 PartitionMetadata metadata;
152 for (const char* suffix : kSlotSuffixes) {
153 metadata.groups.push_back(
154 {std::string(kDefaultGroup) + suffix, kDefaultGroupSize, {}});
155 }
156 for (const auto& pair : partition_sizes) {
157 for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
158 if (base::EndsWith(pair.first,
159 kSlotSuffixes[suffix_idx],
160 base::CompareCase::SENSITIVE)) {
161 metadata.groups[suffix_idx].partitions.push_back(
162 {pair.first, pair.second});
163 }
164 }
165 }
166 return metadata;
167}
168
169// To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
170PartitionMetadata toMetadata(const PartitionSizes& partition_sizes) {
171 PartitionMetadata metadata;
172 metadata.groups.push_back(
173 {std::string{kDefaultGroup}, kDefaultGroupSize, {}});
174 for (const auto& pair : partition_sizes) {
175 metadata.groups[0].partitions.push_back({pair.first, pair.second});
176 }
177 return metadata;
178}
179
180std::unique_ptr<MetadataBuilder> NewFakeMetadata(
181 const PartitionMetadata& metadata) {
182 auto builder =
183 MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
184 EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2);
Yifan Hong537802d2018-08-15 13:15:42 -0700185 EXPECT_NE(nullptr, builder);
186 if (builder == nullptr)
187 return nullptr;
Yifan Hongd4db07e2018-10-18 17:46:27 -0700188 for (const auto& group : metadata.groups) {
189 EXPECT_TRUE(builder->AddGroup(group.name, group.size));
190 for (const auto& partition : group.partitions) {
191 auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */);
192 EXPECT_TRUE(p && builder->ResizePartition(p, partition.size));
193 }
Yifan Hong537802d2018-08-15 13:15:42 -0700194 }
195 return builder;
196}
197
198class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
199 public:
Yifan Hongd4db07e2018-10-18 17:46:27 -0700200 explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
201 : partition_metadata_(toMetadata(partition_sizes)) {}
202 explicit MetadataMatcher(const PartitionMetadata& partition_metadata)
203 : partition_metadata_(partition_metadata) {}
204
Yifan Hong537802d2018-08-15 13:15:42 -0700205 bool MatchAndExplain(MetadataBuilder* metadata,
206 MatchResultListener* listener) const override {
207 bool success = true;
Yifan Hongd4db07e2018-10-18 17:46:27 -0700208 for (const auto& group : partition_metadata_.groups) {
209 for (const auto& partition : group.partitions) {
210 auto p = metadata->FindPartition(partition.name);
211 if (p == nullptr) {
212 if (!success)
213 *listener << "; ";
214 *listener << "No partition " << partition.name;
215 success = false;
216 continue;
217 }
218 if (p->size() != partition.size) {
219 if (!success)
220 *listener << "; ";
221 *listener << "Partition " << partition.name << " has size "
222 << p->size() << ", expected " << partition.size;
223 success = false;
224 }
225 if (p->group_name() != group.name) {
226 if (!success)
227 *listener << "; ";
228 *listener << "Partition " << partition.name << " has group "
229 << p->group_name() << ", expected " << group.name;
230 success = false;
231 }
Yifan Hong537802d2018-08-15 13:15:42 -0700232 }
233 }
234 return success;
235 }
236
237 void DescribeTo(std::ostream* os) const override {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700238 *os << "expect: " << partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700239 }
240
241 void DescribeNegationTo(std::ostream* os) const override {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700242 *os << "expect not: " << partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700243 }
244
245 private:
Yifan Hongd4db07e2018-10-18 17:46:27 -0700246 PartitionMetadata partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700247};
248
249inline Matcher<MetadataBuilder*> MetadataMatches(
Yifan Hongd4db07e2018-10-18 17:46:27 -0700250 const PartitionSuffixSizes& partition_sizes) {
Yifan Hong537802d2018-08-15 13:15:42 -0700251 return MakeMatcher(new MetadataMatcher(partition_sizes));
252}
253
Yifan Hongd4db07e2018-10-18 17:46:27 -0700254inline Matcher<MetadataBuilder*> MetadataMatches(
255 const PartitionMetadata& partition_metadata) {
256 return MakeMatcher(new MetadataMatcher(partition_metadata));
257}
258
259MATCHER_P(HasGroup, group, " has group " + group) {
260 auto groups = arg->ListGroups();
261 return std::find(groups.begin(), groups.end(), group) != groups.end();
262}
263
Yifan Hong537802d2018-08-15 13:15:42 -0700264class BootControlAndroidTest : public ::testing::Test {
265 protected:
266 void SetUp() override {
267 // Fake init bootctl_
268 bootctl_.module_ = new NiceMock<MockBootControlHal>();
269 bootctl_.dynamic_control_ =
270 std::make_unique<NiceMock<MockDynamicPartitionControl>>();
271
272 ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] {
273 return kMaxNumSlots;
274 }));
275 ON_CALL(module(), getSuffix(_, _))
276 .WillByDefault(Invoke([](auto slot, auto cb) {
277 EXPECT_LE(slot, kMaxNumSlots);
278 cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : "");
279 return Void();
280 }));
281
282 ON_CALL(dynamicControl(), IsDynamicPartitionsEnabled())
283 .WillByDefault(Return(true));
Yifan Hong6e38b352018-11-19 14:12:37 -0800284 ON_CALL(dynamicControl(), IsDynamicPartitionsRetrofit())
285 .WillByDefault(Return(false));
Yifan Hong1d9077f2018-12-07 12:09:37 -0800286 ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true));
Yifan Hong537802d2018-08-15 13:15:42 -0700287 ON_CALL(dynamicControl(), GetDeviceDir(_))
288 .WillByDefault(Invoke([](auto path) {
289 *path = kFakeDevicePath;
290 return true;
291 }));
Yifan Hong1d9077f2018-12-07 12:09:37 -0800292 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
293 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
294 *device = GetDmDevice(partition_name_suffix);
295 return true;
296 }));
Yifan Hong537802d2018-08-15 13:15:42 -0700297 }
298
299 // Return the mocked HAL module.
300 NiceMock<MockBootControlHal>& module() {
301 return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
302 }
303
304 // Return the mocked DynamicPartitionControlInterface.
305 NiceMock<MockDynamicPartitionControl>& dynamicControl() {
306 return static_cast<NiceMock<MockDynamicPartitionControl>&>(
307 *bootctl_.dynamic_control_);
308 }
309
310 // Set the fake metadata to return when LoadMetadataBuilder is called on
311 // |slot|.
Yifan Hongd4db07e2018-10-18 17:46:27 -0700312 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
313 SetMetadata(slot, toMetadata(sizes));
314 }
315
316 void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) {
Yifan Hong6e706b12018-11-09 16:50:51 -0800317 EXPECT_CALL(dynamicControl(),
Yifan Hong30eb7b52018-11-20 11:05:46 -0800318 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700319 .Times(AnyNumber())
Yifan Hong6e706b12018-11-09 16:50:51 -0800320 .WillRepeatedly(Invoke([metadata](auto, auto, auto) {
321 return NewFakeMetadata(metadata);
322 }));
Yifan Hong537802d2018-08-15 13:15:42 -0700323 }
324
Yifan Hong537802d2018-08-15 13:15:42 -0700325 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
326 // slot with each partition in |partitions|.
327 void ExpectUnmap(const std::set<std::string>& partitions) {
328 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
329 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
330 .WillByDefault(Return(false));
331
332 for (const auto& partition : partitions) {
333 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
334 .WillOnce(Invoke([this](auto partition, auto) {
335 mapped_devices_.erase(partition);
336 return true;
337 }));
338 }
339 }
340
Yifan Hong537802d2018-08-15 13:15:42 -0700341 void ExpectDevicesAreMapped(const std::set<std::string>& partitions) {
342 ASSERT_EQ(partitions.size(), mapped_devices_.size());
343 for (const auto& partition : partitions) {
344 EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
345 << "Expect that " << partition << " is mapped, but it is not.";
346 }
347 }
348
Yifan Hongd4db07e2018-10-18 17:46:27 -0700349 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
Yifan Hong549eb362018-10-19 15:11:12 -0700350 ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
351 }
352
353 virtual void ExpectStoreMetadataMatch(
354 const Matcher<MetadataBuilder*>& matcher) {
355 EXPECT_CALL(dynamicControl(),
Yifan Hong30eb7b52018-11-20 11:05:46 -0800356 StoreMetadata(GetSuperDevice(target()), matcher, target()))
Yifan Hong549eb362018-10-19 15:11:12 -0700357 .WillOnce(Return(true));
358 }
359
Yifan Hong537802d2018-08-15 13:15:42 -0700360 uint32_t source() { return slots_.source; }
361
362 uint32_t target() { return slots_.target; }
363
364 // Return partition names with suffix of source().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700365 PartitionNameSuffix S(const std::string& name) {
366 return PartitionNameSuffix(name + std::string(kSlotSuffixes[source()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700367 }
368
369 // Return partition names with suffix of target().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700370 PartitionNameSuffix T(const std::string& name) {
371 return PartitionNameSuffix(name + std::string(kSlotSuffixes[target()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700372 }
373
374 // Set source and target slots to use before testing.
375 void SetSlots(const TestParam& slots) {
376 slots_ = slots;
377
378 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
379 return source();
380 }));
381 // Should not store metadata to source slot.
Yifan Hong30eb7b52018-11-20 11:05:46 -0800382 EXPECT_CALL(dynamicControl(),
383 StoreMetadata(GetSuperDevice(source()), _, source()))
Yifan Hong537802d2018-08-15 13:15:42 -0700384 .Times(0);
Yifan Hongd4db07e2018-10-18 17:46:27 -0700385 // Should not load metadata from target slot.
386 EXPECT_CALL(dynamicControl(),
Yifan Hong30eb7b52018-11-20 11:05:46 -0800387 LoadMetadataBuilder(GetSuperDevice(target()), target(), _))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700388 .Times(0);
389 }
390
391 bool InitPartitionMetadata(uint32_t slot, PartitionSizes partition_sizes) {
392 auto m = toMetadata(partition_sizes);
393 LOG(INFO) << m;
394 return bootctl_.InitPartitionMetadata(slot, m);
Yifan Hong537802d2018-08-15 13:15:42 -0700395 }
396
397 BootControlAndroid bootctl_; // BootControlAndroid under test.
398 TestParam slots_;
399 // mapped devices through MapPartitionOnDeviceMapper.
400 std::map<std::string, std::string> mapped_devices_;
401};
402
403class BootControlAndroidTestP
404 : public BootControlAndroidTest,
405 public ::testing::WithParamInterface<TestParam> {
406 public:
407 void SetUp() override {
408 BootControlAndroidTest::SetUp();
409 SetSlots(GetParam());
410 }
411};
412
Yifan Hong537802d2018-08-15 13:15:42 -0700413// Test resize case. Grow if target metadata contains a partition with a size
414// less than expected.
415TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700416 SetMetadata(source(),
417 {{S("system"), 2_GiB},
418 {S("vendor"), 1_GiB},
419 {T("system"), 2_GiB},
420 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700421 ExpectStoreMetadata({{S("system"), 2_GiB},
422 {S("vendor"), 1_GiB},
423 {T("system"), 3_GiB},
424 {T("vendor"), 1_GiB}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800425 ExpectUnmap({T("system"), T("vendor")});
Yifan Hong537802d2018-08-15 13:15:42 -0700426
Yifan Hongd4db07e2018-10-18 17:46:27 -0700427 EXPECT_TRUE(
428 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700429}
430
431// Test resize case. Shrink if target metadata contains a partition with a size
432// greater than expected.
433TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700434 SetMetadata(source(),
435 {{S("system"), 2_GiB},
436 {S("vendor"), 1_GiB},
437 {T("system"), 2_GiB},
438 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700439 ExpectStoreMetadata({{S("system"), 2_GiB},
440 {S("vendor"), 1_GiB},
441 {T("system"), 2_GiB},
442 {T("vendor"), 150_MiB}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800443 ExpectUnmap({T("system"), T("vendor")});
Yifan Hong537802d2018-08-15 13:15:42 -0700444
Yifan Hongd4db07e2018-10-18 17:46:27 -0700445 EXPECT_TRUE(InitPartitionMetadata(target(),
446 {{"system", 2_GiB}, {"vendor", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700447}
448
449// Test adding partitions on the first run.
450TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700451 SetMetadata(source(), PartitionSuffixSizes{});
Yifan Hong549eb362018-10-19 15:11:12 -0700452 ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800453 ExpectUnmap({T("system"), T("vendor")});
Yifan Hong537802d2018-08-15 13:15:42 -0700454
Yifan Hongd4db07e2018-10-18 17:46:27 -0700455 EXPECT_TRUE(
456 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700457}
458
459// Test subsequent add case.
460TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
461 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700462 ExpectStoreMetadata(
463 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800464 ExpectUnmap({T("system"), T("vendor")});
Yifan Hong537802d2018-08-15 13:15:42 -0700465
Yifan Hongd4db07e2018-10-18 17:46:27 -0700466 EXPECT_TRUE(
467 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700468}
469
470// Test delete one partition.
471TEST_P(BootControlAndroidTestP, DeletePartition) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700472 SetMetadata(source(),
473 {{S("system"), 2_GiB},
474 {S("vendor"), 1_GiB},
475 {T("system"), 2_GiB},
476 {T("vendor"), 1_GiB}});
477 // No T("vendor")
478 ExpectStoreMetadata(
479 {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800480 ExpectUnmap({T("system")});
Yifan Hong537802d2018-08-15 13:15:42 -0700481
Yifan Hongd4db07e2018-10-18 17:46:27 -0700482 EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700483}
484
485// Test delete all partitions.
486TEST_P(BootControlAndroidTestP, DeleteAll) {
Yifan Hong537802d2018-08-15 13:15:42 -0700487 SetMetadata(source(),
488 {{S("system"), 2_GiB},
489 {S("vendor"), 1_GiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700490 {T("system"), 2_GiB},
491 {T("vendor"), 1_GiB}});
492 ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
493
494 EXPECT_TRUE(InitPartitionMetadata(target(), {}));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700495}
496
497// Test corrupt source metadata case.
498TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
Yifan Hong6e706b12018-11-09 16:50:51 -0800499 EXPECT_CALL(dynamicControl(),
Yifan Hong30eb7b52018-11-20 11:05:46 -0800500 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
Yifan Hong6e706b12018-11-09 16:50:51 -0800501 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
Yifan Hong1d9077f2018-12-07 12:09:37 -0800502 ExpectUnmap({T("system")});
503
Yifan Hongd4db07e2018-10-18 17:46:27 -0700504 EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
505 << "Should not be able to continue with corrupt source metadata";
Yifan Hong537802d2018-08-15 13:15:42 -0700506}
507
508// Test that InitPartitionMetadata fail if there is not enough space on the
509// device.
510TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700511 SetMetadata(source(),
512 {{S("system"), 3_GiB},
513 {S("vendor"), 2_GiB},
514 {T("system"), 0},
515 {T("vendor"), 0}});
516 EXPECT_FALSE(
517 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
Yifan Hong537802d2018-08-15 13:15:42 -0700518 << "Should not be able to fit 11GiB data into 10GiB space";
519}
520
Yifan Hongd4db07e2018-10-18 17:46:27 -0700521TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
522 SetMetadata(source(),
523 {{S("system"), 1_GiB},
524 {S("vendor"), 1_GiB},
525 {T("system"), 0},
526 {T("vendor"), 0}});
527 EXPECT_FALSE(
528 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
529 << "Should not be able to grow over size of super / 2";
530}
531
Yifan Hong1d9077f2018-12-07 12:09:37 -0800532// Test applying retrofit update on a build with dynamic partitions enabled.
533TEST_P(BootControlAndroidTestP,
534 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
535 SetMetadata(source(),
536 {{S("system"), 2_GiB},
537 {S("vendor"), 1_GiB},
538 {T("system"), 2_GiB},
539 {T("vendor"), 1_GiB}});
540 // Should not try to unmap any target partition.
541 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _)).Times(0);
542 // Should not store metadata to target slot.
543 EXPECT_CALL(dynamicControl(),
544 StoreMetadata(GetSuperDevice(target()), _, target()))
545 .Times(0);
546
547 // Not calling through BootControlAndroidTest::InitPartitionMetadata(), since
548 // we don't want any default group in the PartitionMetadata.
549 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}));
550
551 // Should use dynamic source partitions.
552 EXPECT_CALL(dynamicControl(), GetState(S("system")))
553 .Times(1)
554 .WillOnce(Return(DmDeviceState::ACTIVE));
555 std::string source_device;
556 EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &source_device));
557 EXPECT_EQ(GetDmDevice(S("system")), source_device);
558
559 // Should use static target partitions without querying dynamic control.
560 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
561 std::string target_device;
562 EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &target_device));
563 EXPECT_EQ(GetDevice(T("system")), target_device);
564}
565
Yifan Hongd4db07e2018-10-18 17:46:27 -0700566INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
Yifan Hong537802d2018-08-15 13:15:42 -0700567 BootControlAndroidTestP,
568 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
569
Yifan Hongd4db07e2018-10-18 17:46:27 -0700570const PartitionSuffixSizes update_sizes_0() {
571 // Initial state is 0 for "other" slot.
Yifan Hong537802d2018-08-15 13:15:42 -0700572 return {
573 {"grown_a", 2_GiB},
574 {"shrunk_a", 1_GiB},
575 {"same_a", 100_MiB},
576 {"deleted_a", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700577 // no added_a
578 {"grown_b", 200_MiB},
579 // simulate system_other
580 {"shrunk_b", 0},
581 {"same_b", 0},
582 {"deleted_b", 0},
583 // no added_b
584 };
585}
586
587const PartitionSuffixSizes update_sizes_1() {
588 return {
589 {"grown_a", 2_GiB},
590 {"shrunk_a", 1_GiB},
591 {"same_a", 100_MiB},
592 {"deleted_a", 150_MiB},
593 // no added_a
Yifan Hong537802d2018-08-15 13:15:42 -0700594 {"grown_b", 3_GiB},
595 {"shrunk_b", 150_MiB},
596 {"same_b", 100_MiB},
597 {"added_b", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700598 // no deleted_b
Yifan Hong537802d2018-08-15 13:15:42 -0700599 };
600}
601
Yifan Hongd4db07e2018-10-18 17:46:27 -0700602const PartitionSuffixSizes update_sizes_2() {
603 return {
604 {"grown_a", 4_GiB},
605 {"shrunk_a", 100_MiB},
606 {"same_a", 100_MiB},
607 {"deleted_a", 64_MiB},
608 // no added_a
609 {"grown_b", 3_GiB},
610 {"shrunk_b", 150_MiB},
611 {"same_b", 100_MiB},
612 {"added_b", 150_MiB},
613 // no deleted_b
614 };
Yifan Hong537802d2018-08-15 13:15:42 -0700615}
616
617// Test case for first update after the device is manufactured, in which
618// case the "other" slot is likely of size "0" (except system, which is
619// non-zero because of system_other partition)
620TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
621 SetSlots({0, 1});
622
623 SetMetadata(source(), update_sizes_0());
624 SetMetadata(target(), update_sizes_0());
Yifan Hong549eb362018-10-19 15:11:12 -0700625 ExpectStoreMetadata(update_sizes_1());
Yifan Hong1d9077f2018-12-07 12:09:37 -0800626 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
Yifan Hong537802d2018-08-15 13:15:42 -0700627
Yifan Hongd4db07e2018-10-18 17:46:27 -0700628 EXPECT_TRUE(InitPartitionMetadata(target(),
629 {{"grown", 3_GiB},
630 {"shrunk", 150_MiB},
631 {"same", 100_MiB},
632 {"added", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700633}
634
635// After first update, test for the second update. In the second update, the
636// "added" partition is deleted and "deleted" partition is re-added.
637TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
638 SetSlots({1, 0});
639
640 SetMetadata(source(), update_sizes_1());
641 SetMetadata(target(), update_sizes_0());
642
Yifan Hong549eb362018-10-19 15:11:12 -0700643 ExpectStoreMetadata(update_sizes_2());
Yifan Hong1d9077f2018-12-07 12:09:37 -0800644 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
Yifan Hong537802d2018-08-15 13:15:42 -0700645
Yifan Hongd4db07e2018-10-18 17:46:27 -0700646 EXPECT_TRUE(InitPartitionMetadata(target(),
647 {{"grown", 4_GiB},
648 {"shrunk", 100_MiB},
649 {"same", 100_MiB},
650 {"deleted", 64_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700651}
652
653TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
654 SetSlots({1, 1});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700655 EXPECT_FALSE(InitPartitionMetadata(target(), {}))
Yifan Hong537802d2018-08-15 13:15:42 -0700656 << "Should not be able to apply to current slot.";
657}
658
Yifan Hongd4db07e2018-10-18 17:46:27 -0700659class BootControlAndroidGroupTestP : public BootControlAndroidTestP {
660 public:
661 void SetUp() override {
662 BootControlAndroidTestP::SetUp();
663 SetMetadata(
664 source(),
665 {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
666 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB),
667 SimpleGroup(T("android"), 3_GiB, T("system"), 0),
668 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}});
669 }
670
671 // Return a simple group with only one partition.
672 PartitionMetadata::Group SimpleGroup(const std::string& group,
673 uint64_t group_size,
674 const std::string& partition,
675 uint64_t partition_size) {
676 return {.name = group,
677 .size = group_size,
678 .partitions = {{.name = partition, .size = partition_size}}};
679 }
680
681 void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) {
682 ExpectStoreMetadataMatch(MetadataMatches(partition_metadata));
683 }
684
685 // Expect that target slot is stored with target groups.
686 void ExpectStoreMetadataMatch(
687 const Matcher<MetadataBuilder*>& matcher) override {
688 BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf(
689 MetadataMatches(PartitionMetadata{
690 .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
691 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}),
692 matcher));
693 }
694};
695
696// Allow to resize within group.
697TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
698 ExpectStoreMetadata(PartitionMetadata{
699 .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
700 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800701 ExpectUnmap({T("system"), T("vendor")});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700702
703 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
704 target(),
705 PartitionMetadata{
706 .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
707 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700708}
709
710TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
711 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
712 target(),
713 PartitionMetadata{
714 .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
715 SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}))
716 << "Should not be able to grow over maximum size of group";
717}
718
719TEST_P(BootControlAndroidGroupTestP, GroupTooBig) {
720 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
721 target(),
722 PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
723 {.name = "oem", .size = 3_GiB}}}))
724 << "Should not be able to grow over size of super / 2";
725}
726
727TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
728 ExpectStoreMetadata(PartitionMetadata{
729 .groups = {
730 {.name = T("android"),
731 .size = 3_GiB,
732 .partitions = {{.name = T("system"), .size = 2_GiB},
733 {.name = T("product_services"), .size = 1_GiB}}}}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800734 ExpectUnmap({T("system"), T("vendor"), T("product_services")});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700735
736 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
737 target(),
738 PartitionMetadata{
739 .groups = {
740 {.name = "android",
741 .size = 3_GiB,
742 .partitions = {{.name = "system", .size = 2_GiB},
743 {.name = "product_services", .size = 1_GiB}}},
744 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700745}
746
747TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
748 ExpectStoreMetadata(PartitionMetadata{
749 .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800750 ExpectUnmap({T("vendor")});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700751
752 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
753 target(),
754 PartitionMetadata{
755 .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
756 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700757}
758
759TEST_P(BootControlAndroidGroupTestP, AddGroup) {
760 ExpectStoreMetadata(PartitionMetadata{
761 .groups = {
762 SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800763 ExpectUnmap({T("system"), T("vendor"), T("new_partition")});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700764
765 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
766 target(),
767 PartitionMetadata{
768 .groups = {
769 SimpleGroup("android", 2_GiB, "system", 2_GiB),
770 SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
771 SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700772}
773
774TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
775 ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
Yifan Hong1d9077f2018-12-07 12:09:37 -0800776 ExpectUnmap({T("system")});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700777 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
778 target(),
779 PartitionMetadata{
780 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700781}
782
783TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
784 ExpectStoreMetadata(PartitionMetadata{
785 .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
786 SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
Yifan Hong1d9077f2018-12-07 12:09:37 -0800787 ExpectUnmap({T("system"), T("vendor")});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700788
789 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
790 target(),
791 PartitionMetadata{
792 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
793 SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700794}
795
796INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
797 BootControlAndroidGroupTestP,
798 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
799
Yifan Hong537802d2018-08-15 13:15:42 -0700800} // namespace chromeos_update_engine