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