blob: d62c3a678ac753d7d75a1c6055af071b7bc3fc1f [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>
20
21#include <android-base/strings.h>
David Andersond63cb3c2018-10-01 14:15:00 -070022#include <fs_mgr.h>
Yifan Hong537802d2018-08-15 13:15:42 -070023#include <gmock/gmock.h>
24#include <gtest/gtest.h>
25
26#include "update_engine/mock_boot_control_hal.h"
27#include "update_engine/mock_dynamic_partition_control.h"
28
29using android::base::Join;
30using android::fs_mgr::MetadataBuilder;
31using android::hardware::Void;
32using testing::_;
33using testing::AnyNumber;
34using testing::Contains;
35using testing::Eq;
36using testing::Invoke;
37using testing::Key;
38using testing::MakeMatcher;
39using testing::Matcher;
40using testing::MatcherInterface;
41using testing::MatchResultListener;
42using testing::NiceMock;
43using testing::Return;
44
45namespace chromeos_update_engine {
46
47constexpr const uint32_t kMaxNumSlots = 2;
48constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
49constexpr const char* kFakeDevicePath = "/fake/dev/path/";
50constexpr const char* kFakeMappedPath = "/fake/mapped/path/";
51constexpr const uint32_t kFakeMetadataSize = 65536;
Yifan Hong537802d2018-08-15 13:15:42 -070052
53// A map describing the size of each partition.
54using PartitionSizes = std::map<std::string, uint64_t>;
55
56// C++ standards do not allow uint64_t (aka unsigned long) to be the parameter
57// of user-defined literal operators.
58unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT
59 return x << 20;
60}
61unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
62 return x << 30;
63}
64
65template <typename U, typename V>
66std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
67 os << "{";
68 bool first = true;
69 for (const auto& pair : param) {
70 if (!first)
71 os << ", ";
72 os << pair.first << ":" << pair.second;
73 first = false;
74 }
75 return os << "}";
76}
77
78inline std::string GetDevice(const std::string& name) {
79 return kFakeDevicePath + name;
80}
81inline std::string GetSuperDevice() {
David Andersond63cb3c2018-10-01 14:15:00 -070082 return GetDevice(fs_mgr_get_super_partition_name());
Yifan Hong537802d2018-08-15 13:15:42 -070083}
84
85struct TestParam {
86 uint32_t source;
87 uint32_t target;
88};
89std::ostream& operator<<(std::ostream& os, const TestParam& param) {
90 return os << "{source: " << param.source << ", target:" << param.target
91 << "}";
92}
93
94std::unique_ptr<MetadataBuilder> NewFakeMetadata(const PartitionSizes& sizes) {
95 auto builder = MetadataBuilder::New(10_GiB, kFakeMetadataSize, kMaxNumSlots);
96 EXPECT_NE(nullptr, builder);
97 if (builder == nullptr)
98 return nullptr;
99 for (const auto& pair : sizes) {
David Anderson4b92c1c2018-10-03 14:15:25 -0700100 auto p = builder->AddPartition(pair.first, 0 /* attr */);
Yifan Hong537802d2018-08-15 13:15:42 -0700101 EXPECT_TRUE(p && builder->ResizePartition(p, pair.second));
102 }
103 return builder;
104}
105
106class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
107 public:
108 explicit MetadataMatcher(const PartitionSizes& partition_sizes)
109 : partition_sizes_(partition_sizes) {}
110 bool MatchAndExplain(MetadataBuilder* metadata,
111 MatchResultListener* listener) const override {
112 bool success = true;
113 for (const auto& pair : partition_sizes_) {
114 auto p = metadata->FindPartition(pair.first);
115 if (p == nullptr) {
116 if (success)
117 *listener << "; ";
118 *listener << "No partition " << pair.first;
119 success = false;
120 continue;
121 }
122 if (p->size() != pair.second) {
123 if (success)
124 *listener << "; ";
125 *listener << "Partition " << pair.first << " has size " << p->size()
126 << ", expected " << pair.second;
127 success = false;
128 }
129 }
130 return success;
131 }
132
133 void DescribeTo(std::ostream* os) const override {
134 *os << "expect: " << partition_sizes_;
135 }
136
137 void DescribeNegationTo(std::ostream* os) const override {
138 *os << "expect not: " << partition_sizes_;
139 }
140
141 private:
142 PartitionSizes partition_sizes_;
143};
144
145inline Matcher<MetadataBuilder*> MetadataMatches(
146 const PartitionSizes& partition_sizes) {
147 return MakeMatcher(new MetadataMatcher(partition_sizes));
148}
149
150class BootControlAndroidTest : public ::testing::Test {
151 protected:
152 void SetUp() override {
153 // Fake init bootctl_
154 bootctl_.module_ = new NiceMock<MockBootControlHal>();
155 bootctl_.dynamic_control_ =
156 std::make_unique<NiceMock<MockDynamicPartitionControl>>();
157
158 ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] {
159 return kMaxNumSlots;
160 }));
161 ON_CALL(module(), getSuffix(_, _))
162 .WillByDefault(Invoke([](auto slot, auto cb) {
163 EXPECT_LE(slot, kMaxNumSlots);
164 cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : "");
165 return Void();
166 }));
167
168 ON_CALL(dynamicControl(), IsDynamicPartitionsEnabled())
169 .WillByDefault(Return(true));
170 ON_CALL(dynamicControl(), GetDeviceDir(_))
171 .WillByDefault(Invoke([](auto path) {
172 *path = kFakeDevicePath;
173 return true;
174 }));
175 }
176
177 // Return the mocked HAL module.
178 NiceMock<MockBootControlHal>& module() {
179 return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
180 }
181
182 // Return the mocked DynamicPartitionControlInterface.
183 NiceMock<MockDynamicPartitionControl>& dynamicControl() {
184 return static_cast<NiceMock<MockDynamicPartitionControl>&>(
185 *bootctl_.dynamic_control_);
186 }
187
188 // Set the fake metadata to return when LoadMetadataBuilder is called on
189 // |slot|.
190 void SetMetadata(uint32_t slot, const PartitionSizes& sizes) {
191 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), slot))
192 .WillOnce(
193 Invoke([sizes](auto, auto) { return NewFakeMetadata(sizes); }));
194 }
195
196 // Expect that MapPartitionOnDeviceMapper is called on target() metadata slot
197 // with each partition in |partitions|.
198 void ExpectMap(const std::set<std::string>& partitions) {
199 // Error when MapPartitionOnDeviceMapper is called on unknown arguments.
200 ON_CALL(dynamicControl(), MapPartitionOnDeviceMapper(_, _, _, _))
201 .WillByDefault(Return(false));
202
203 for (const auto& partition : partitions) {
204 EXPECT_CALL(
205 dynamicControl(),
206 MapPartitionOnDeviceMapper(GetSuperDevice(), partition, target(), _))
207 .WillOnce(Invoke([this](auto, auto partition, auto, auto path) {
208 auto it = mapped_devices_.find(partition);
209 if (it != mapped_devices_.end()) {
210 *path = it->second;
211 return true;
212 }
213 mapped_devices_[partition] = *path = kFakeMappedPath + partition;
214 return true;
215 }));
216 }
217 }
218
219 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
220 // slot with each partition in |partitions|.
221 void ExpectUnmap(const std::set<std::string>& partitions) {
222 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
223 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
224 .WillByDefault(Return(false));
225
226 for (const auto& partition : partitions) {
227 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
228 .WillOnce(Invoke([this](auto partition, auto) {
229 mapped_devices_.erase(partition);
230 return true;
231 }));
232 }
233 }
234
235 void ExpectRemap(const std::set<std::string>& partitions) {
236 ExpectUnmap(partitions);
237 ExpectMap(partitions);
238 }
239
240 void ExpectDevicesAreMapped(const std::set<std::string>& partitions) {
241 ASSERT_EQ(partitions.size(), mapped_devices_.size());
242 for (const auto& partition : partitions) {
243 EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
244 << "Expect that " << partition << " is mapped, but it is not.";
245 }
246 }
247
Yifan Hong549eb362018-10-19 15:11:12 -0700248 void ExpectStoreMetadata(const PartitionSizes& partition_sizes) {
249 ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
250 }
251
252 virtual void ExpectStoreMetadataMatch(
253 const Matcher<MetadataBuilder*>& matcher) {
254 EXPECT_CALL(dynamicControl(),
255 StoreMetadata(GetSuperDevice(), matcher, target()))
256 .WillOnce(Return(true));
257 }
258
Yifan Hong537802d2018-08-15 13:15:42 -0700259 uint32_t source() { return slots_.source; }
260
261 uint32_t target() { return slots_.target; }
262
263 // Return partition names with suffix of source().
264 std::string S(const std::string& name) {
265 return name + std::string(kSlotSuffixes[source()]);
266 }
267
268 // Return partition names with suffix of target().
269 std::string T(const std::string& name) {
270 return name + std::string(kSlotSuffixes[target()]);
271 }
272
273 // Set source and target slots to use before testing.
274 void SetSlots(const TestParam& slots) {
275 slots_ = slots;
276
277 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
278 return source();
279 }));
280 // Should not store metadata to source slot.
281 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, source()))
282 .Times(0);
283 }
284
285 BootControlAndroid bootctl_; // BootControlAndroid under test.
286 TestParam slots_;
287 // mapped devices through MapPartitionOnDeviceMapper.
288 std::map<std::string, std::string> mapped_devices_;
289};
290
291class BootControlAndroidTestP
292 : public BootControlAndroidTest,
293 public ::testing::WithParamInterface<TestParam> {
294 public:
295 void SetUp() override {
296 BootControlAndroidTest::SetUp();
297 SetSlots(GetParam());
298 }
299};
300
301// Test no resize if no dynamic partitions at all.
302TEST_P(BootControlAndroidTestP, NoResizeIfNoDynamicPartitions) {
303 SetMetadata(source(), {});
304 SetMetadata(target(), {});
305 // Should not need to resize and store metadata
306 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
307 .Times(0);
308 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_a"))))
309 .Times(AnyNumber())
310 .WillRepeatedly(Return(true));
311 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_b"))))
312 .Times(AnyNumber())
313 .WillRepeatedly(Return(true));
314
315 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {{"static", 1_GiB}}));
316 ExpectDevicesAreMapped({});
317}
318
319// Test no resize if update manifest does not contain any dynamic partitions
320TEST_P(BootControlAndroidTestP, NoResizeIfEmptyMetadata) {
321 SetMetadata(source(),
322 {{S("system"), 4_GiB},
323 {S("vendor"), 100_MiB},
324 {T("system"), 3_GiB},
325 {T("vendor"), 150_MiB}});
326 SetMetadata(target(),
327 {{S("system"), 2_GiB},
328 {S("vendor"), 1_GiB},
329 {T("system"), 3_GiB},
330 {T("vendor"), 150_MiB}});
331 // Should not need to resize and store metadata
332 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
333 .Times(0);
334 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_a"))))
335 .Times(AnyNumber())
336 .WillRepeatedly(Return(true));
337 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_b"))))
338 .Times(AnyNumber())
339 .WillRepeatedly(Return(true));
340
341 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {{"static", 1_GiB}}));
342 ExpectDevicesAreMapped({});
343}
344
345// Do not resize if manifest size matches size in target metadata. When resuming
346// from an update, do not redo the resize if not needed.
347TEST_P(BootControlAndroidTestP, NoResizeIfSizeMatchWhenResizing) {
348 SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
349 SetMetadata(target(),
350 {{S("system"), 2_GiB},
351 {S("vendor"), 1_GiB},
352 {T("system"), 3_GiB},
353 {T("vendor"), 1_GiB}});
354 // Should not need to resize and store metadata
355 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
356 .Times(0);
357 ExpectRemap({T("system"), T("vendor")});
358
359 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
360 target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
361 ExpectDevicesAreMapped({T("system"), T("vendor")});
362}
363
364// Do not resize if manifest size matches size in target metadata. When resuming
365// from an update, do not redo the resize if not needed.
366TEST_P(BootControlAndroidTestP, NoResizeIfSizeMatchWhenAdding) {
367 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
368 SetMetadata(
369 target(),
370 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
371 // Should not need to resize and store metadata
372 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
373 .Times(0);
374 ExpectRemap({T("system"), T("vendor")});
375
376 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
377 target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
378 ExpectDevicesAreMapped({T("system"), T("vendor")});
379}
380
381// Do not resize if manifest size matches size in target metadata. When resuming
382// from an update, do not redo the resize if not needed.
383TEST_P(BootControlAndroidTestP, NoResizeIfSizeMatchWhenDeleting) {
384 SetMetadata(source(),
385 {{S("system"), 2_GiB},
386 {S("vendor"), 1_GiB},
387 {T("system"), 2_GiB},
388 {T("vendor"), 1_GiB}});
389 SetMetadata(target(),
390 {{S("system"), 2_GiB},
391 {S("vendor"), 1_GiB},
392 {T("system"), 2_GiB},
393 {T("vendor"), 0}});
394 // Should not need to resize and store metadata
395 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
396 .Times(0);
397 ExpectUnmap({T("system"), T("vendor")});
398 ExpectMap({T("system")});
399
400 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
401 target(), {{"system", 2_GiB}, {"vendor", 0}}));
402 ExpectDevicesAreMapped({T("system")});
403}
404
405// Test resize case. Grow if target metadata contains a partition with a size
406// less than expected.
407TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
408 PartitionSizes initial{{S("system"), 2_GiB},
409 {S("vendor"), 1_GiB},
410 {T("system"), 2_GiB},
411 {T("vendor"), 1_GiB}};
412 SetMetadata(source(), initial);
413 SetMetadata(target(), initial);
Yifan Hong549eb362018-10-19 15:11:12 -0700414 ExpectStoreMetadata({{S("system"), 2_GiB},
415 {S("vendor"), 1_GiB},
416 {T("system"), 3_GiB},
417 {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700418 ExpectRemap({T("system"), T("vendor")});
419
420 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
421 target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
422 ExpectDevicesAreMapped({T("system"), T("vendor")});
423}
424
425// Test resize case. Shrink if target metadata contains a partition with a size
426// greater than expected.
427TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
428 PartitionSizes initial{{S("system"), 2_GiB},
429 {S("vendor"), 1_GiB},
430 {T("system"), 2_GiB},
431 {T("vendor"), 1_GiB}};
432 SetMetadata(source(), initial);
433 SetMetadata(target(), initial);
Yifan Hong549eb362018-10-19 15:11:12 -0700434 ExpectStoreMetadata({{S("system"), 2_GiB},
435 {S("vendor"), 1_GiB},
436 {T("system"), 2_GiB},
437 {T("vendor"), 150_MiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700438 ExpectRemap({T("system"), T("vendor")});
439
440 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
441 target(), {{"system", 2_GiB}, {"vendor", 150_MiB}}));
442 ExpectDevicesAreMapped({T("system"), T("vendor")});
443}
444
445// Test adding partitions on the first run.
446TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
447 SetMetadata(source(), {});
448 SetMetadata(target(), {});
Yifan Hong549eb362018-10-19 15:11:12 -0700449 ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700450 ExpectRemap({T("system"), T("vendor")});
451
452 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
453 target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
454 ExpectDevicesAreMapped({T("system"), T("vendor")});
455}
456
457// Test subsequent add case.
458TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
459 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
460 SetMetadata(target(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700461 ExpectStoreMetadata(
462 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700463 ExpectRemap({T("system"), T("vendor")});
464
465 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
466 target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
467 ExpectDevicesAreMapped({T("system"), T("vendor")});
468}
469
470// Test delete one partition.
471TEST_P(BootControlAndroidTestP, DeletePartition) {
472 PartitionSizes initial{{S("system"), 2_GiB},
473 {S("vendor"), 1_GiB},
474 {T("system"), 2_GiB},
475 {T("vendor"), 1_GiB}};
476 SetMetadata(source(), initial);
477 SetMetadata(target(), initial);
Yifan Hong549eb362018-10-19 15:11:12 -0700478 ExpectStoreMetadata({{S("system"), 2_GiB},
479 {S("vendor"), 1_GiB},
480 {T("system"), 2_GiB},
481 {T("vendor"), 0}});
Yifan Hong537802d2018-08-15 13:15:42 -0700482 ExpectUnmap({T("system"), T("vendor")});
483 ExpectMap({T("system")});
484
485 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
486 target(), {{"system", 2_GiB}, {"vendor", 0}}));
487 ExpectDevicesAreMapped({T("system")});
488}
489
490// Test delete all partitions.
491TEST_P(BootControlAndroidTestP, DeleteAll) {
492 PartitionSizes initial{{S("system"), 2_GiB},
493 {S("vendor"), 1_GiB},
494 {T("system"), 2_GiB},
495 {T("vendor"), 1_GiB}};
496 SetMetadata(source(), initial);
497 SetMetadata(target(), initial);
Yifan Hong549eb362018-10-19 15:11:12 -0700498 ExpectStoreMetadata({{S("system"), 2_GiB},
499 {S("vendor"), 1_GiB},
500 {T("system"), 0},
501 {T("vendor"), 0}});
Yifan Hong537802d2018-08-15 13:15:42 -0700502 ExpectUnmap({T("system"), T("vendor")});
503 ExpectMap({});
504
505 EXPECT_TRUE(
506 bootctl_.InitPartitionMetadata(target(), {{"system", 0}, {"vendor", 0}}));
507 ExpectDevicesAreMapped({});
508}
509
510// Test corrupt source metadata case. This shouldn't happen in practice,
511// because the device is already booted normally.
512TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
513 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), source()))
514 .WillOnce(Invoke([](auto, auto) { return nullptr; }));
515 EXPECT_FALSE(bootctl_.InitPartitionMetadata(target(), {}))
516 << "Should not be able to continue with corrupt source metadata";
517}
518
519// Test corrupt target metadata case. This may happen in practice.
520// BootControlAndroid should copy from source metadata and make necessary
521// modifications on it.
522TEST_P(BootControlAndroidTestP, CorruptedTargetMetadata) {
523 SetMetadata(source(),
524 {{S("system"), 2_GiB},
525 {S("vendor"), 1_GiB},
526 {T("system"), 0},
527 {T("vendor"), 0}});
528 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), target()))
529 .WillOnce(Invoke([](auto, auto) { return nullptr; }));
Yifan Hong549eb362018-10-19 15:11:12 -0700530 ExpectStoreMetadata({{S("system"), 2_GiB},
531 {S("vendor"), 1_GiB},
532 {T("system"), 3_GiB},
533 {T("vendor"), 150_MiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700534 ExpectRemap({T("system"), T("vendor")});
535 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
536 target(), {{"system", 3_GiB}, {"vendor", 150_MiB}}));
537 ExpectDevicesAreMapped({T("system"), T("vendor")});
538}
539
540// Test that InitPartitionMetadata fail if there is not enough space on the
541// device.
542TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
543 PartitionSizes initial{{S("system"), 3_GiB},
544 {S("vendor"), 2_GiB},
545 {T("system"), 0},
546 {T("vendor"), 0}};
547 SetMetadata(source(), initial);
548 SetMetadata(target(), initial);
549 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
550 target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
551 << "Should not be able to fit 11GiB data into 10GiB space";
552}
553
554INSTANTIATE_TEST_CASE_P(ParamTest,
555 BootControlAndroidTestP,
556 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
557
558const PartitionSizes update_sizes_0() {
559 return {{"grown_a", 2_GiB},
560 {"shrunk_a", 1_GiB},
561 {"same_a", 100_MiB},
562 {"deleted_a", 150_MiB},
563 {"grown_b", 200_MiB},
564 {"shrunk_b", 0},
565 {"same_b", 0}};
566}
567
568const PartitionSizes update_sizes_1() {
569 return {
570 {"grown_a", 2_GiB},
571 {"shrunk_a", 1_GiB},
572 {"same_a", 100_MiB},
573 {"deleted_a", 150_MiB},
574 {"grown_b", 3_GiB},
575 {"shrunk_b", 150_MiB},
576 {"same_b", 100_MiB},
577 {"added_b", 150_MiB},
578 {"deleted_b", 0},
579 };
580}
581
582const PartitionSizes update_sizes_2() {
583 return {{"grown_a", 4_GiB},
584 {"shrunk_a", 100_MiB},
585 {"same_a", 100_MiB},
586 {"added_a", 0_MiB},
587 {"deleted_a", 64_MiB},
588 {"grown_b", 3_GiB},
589 {"shrunk_b", 150_MiB},
590 {"same_b", 100_MiB},
591 {"added_b", 150_MiB},
592 {"deleted_b", 0}};
593}
594
595// Test case for first update after the device is manufactured, in which
596// case the "other" slot is likely of size "0" (except system, which is
597// non-zero because of system_other partition)
598TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
599 SetSlots({0, 1});
600
601 SetMetadata(source(), update_sizes_0());
602 SetMetadata(target(), update_sizes_0());
Yifan Hong549eb362018-10-19 15:11:12 -0700603 ExpectStoreMetadata(update_sizes_1());
Yifan Hong537802d2018-08-15 13:15:42 -0700604 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b", "deleted_b"});
605 ExpectMap({"grown_b", "shrunk_b", "same_b", "added_b"});
606
607 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(),
608 {{"grown", 3_GiB},
609 {"shrunk", 150_MiB},
610 {"same", 100_MiB},
611 {"added", 150_MiB},
612 {"deleted", 0_MiB}}));
613 ExpectDevicesAreMapped({"grown_b", "shrunk_b", "same_b", "added_b"});
614}
615
616// After first update, test for the second update. In the second update, the
617// "added" partition is deleted and "deleted" partition is re-added.
618TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
619 SetSlots({1, 0});
620
621 SetMetadata(source(), update_sizes_1());
622 SetMetadata(target(), update_sizes_0());
623
Yifan Hong549eb362018-10-19 15:11:12 -0700624 ExpectStoreMetadata(update_sizes_2());
Yifan Hong537802d2018-08-15 13:15:42 -0700625 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "added_a", "deleted_a"});
626 ExpectMap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
627
628 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(),
629 {{"grown", 4_GiB},
630 {"shrunk", 100_MiB},
631 {"same", 100_MiB},
632 {"added", 0_MiB},
633 {"deleted", 64_MiB}}));
634 ExpectDevicesAreMapped({"grown_a", "shrunk_a", "same_a", "deleted_a"});
635}
636
637TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
638 SetSlots({1, 1});
639 EXPECT_FALSE(bootctl_.InitPartitionMetadata(target(), {}))
640 << "Should not be able to apply to current slot.";
641}
642
643} // namespace chromeos_update_engine