blob: 3e01be23a77eeb141be64f3837ef09865595661f [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
248 uint32_t source() { return slots_.source; }
249
250 uint32_t target() { return slots_.target; }
251
252 // Return partition names with suffix of source().
253 std::string S(const std::string& name) {
254 return name + std::string(kSlotSuffixes[source()]);
255 }
256
257 // Return partition names with suffix of target().
258 std::string T(const std::string& name) {
259 return name + std::string(kSlotSuffixes[target()]);
260 }
261
262 // Set source and target slots to use before testing.
263 void SetSlots(const TestParam& slots) {
264 slots_ = slots;
265
266 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
267 return source();
268 }));
269 // Should not store metadata to source slot.
270 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, source()))
271 .Times(0);
272 }
273
274 BootControlAndroid bootctl_; // BootControlAndroid under test.
275 TestParam slots_;
276 // mapped devices through MapPartitionOnDeviceMapper.
277 std::map<std::string, std::string> mapped_devices_;
278};
279
280class BootControlAndroidTestP
281 : public BootControlAndroidTest,
282 public ::testing::WithParamInterface<TestParam> {
283 public:
284 void SetUp() override {
285 BootControlAndroidTest::SetUp();
286 SetSlots(GetParam());
287 }
288};
289
290// Test no resize if no dynamic partitions at all.
291TEST_P(BootControlAndroidTestP, NoResizeIfNoDynamicPartitions) {
292 SetMetadata(source(), {});
293 SetMetadata(target(), {});
294 // Should not need to resize and store metadata
295 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
296 .Times(0);
297 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_a"))))
298 .Times(AnyNumber())
299 .WillRepeatedly(Return(true));
300 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_b"))))
301 .Times(AnyNumber())
302 .WillRepeatedly(Return(true));
303
304 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {{"static", 1_GiB}}));
305 ExpectDevicesAreMapped({});
306}
307
308// Test no resize if update manifest does not contain any dynamic partitions
309TEST_P(BootControlAndroidTestP, NoResizeIfEmptyMetadata) {
310 SetMetadata(source(),
311 {{S("system"), 4_GiB},
312 {S("vendor"), 100_MiB},
313 {T("system"), 3_GiB},
314 {T("vendor"), 150_MiB}});
315 SetMetadata(target(),
316 {{S("system"), 2_GiB},
317 {S("vendor"), 1_GiB},
318 {T("system"), 3_GiB},
319 {T("vendor"), 150_MiB}});
320 // Should not need to resize and store metadata
321 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
322 .Times(0);
323 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_a"))))
324 .Times(AnyNumber())
325 .WillRepeatedly(Return(true));
326 EXPECT_CALL(dynamicControl(), DeviceExists(Eq(GetDevice("static_b"))))
327 .Times(AnyNumber())
328 .WillRepeatedly(Return(true));
329
330 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {{"static", 1_GiB}}));
331 ExpectDevicesAreMapped({});
332}
333
334// Do not resize if manifest size matches size in target metadata. When resuming
335// from an update, do not redo the resize if not needed.
336TEST_P(BootControlAndroidTestP, NoResizeIfSizeMatchWhenResizing) {
337 SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
338 SetMetadata(target(),
339 {{S("system"), 2_GiB},
340 {S("vendor"), 1_GiB},
341 {T("system"), 3_GiB},
342 {T("vendor"), 1_GiB}});
343 // Should not need to resize and store metadata
344 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
345 .Times(0);
346 ExpectRemap({T("system"), T("vendor")});
347
348 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
349 target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
350 ExpectDevicesAreMapped({T("system"), T("vendor")});
351}
352
353// Do not resize if manifest size matches size in target metadata. When resuming
354// from an update, do not redo the resize if not needed.
355TEST_P(BootControlAndroidTestP, NoResizeIfSizeMatchWhenAdding) {
356 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
357 SetMetadata(
358 target(),
359 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
360 // Should not need to resize and store metadata
361 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
362 .Times(0);
363 ExpectRemap({T("system"), T("vendor")});
364
365 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
366 target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
367 ExpectDevicesAreMapped({T("system"), T("vendor")});
368}
369
370// Do not resize if manifest size matches size in target metadata. When resuming
371// from an update, do not redo the resize if not needed.
372TEST_P(BootControlAndroidTestP, NoResizeIfSizeMatchWhenDeleting) {
373 SetMetadata(source(),
374 {{S("system"), 2_GiB},
375 {S("vendor"), 1_GiB},
376 {T("system"), 2_GiB},
377 {T("vendor"), 1_GiB}});
378 SetMetadata(target(),
379 {{S("system"), 2_GiB},
380 {S("vendor"), 1_GiB},
381 {T("system"), 2_GiB},
382 {T("vendor"), 0}});
383 // Should not need to resize and store metadata
384 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, target()))
385 .Times(0);
386 ExpectUnmap({T("system"), T("vendor")});
387 ExpectMap({T("system")});
388
389 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
390 target(), {{"system", 2_GiB}, {"vendor", 0}}));
391 ExpectDevicesAreMapped({T("system")});
392}
393
394// Test resize case. Grow if target metadata contains a partition with a size
395// less than expected.
396TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
397 PartitionSizes initial{{S("system"), 2_GiB},
398 {S("vendor"), 1_GiB},
399 {T("system"), 2_GiB},
400 {T("vendor"), 1_GiB}};
401 SetMetadata(source(), initial);
402 SetMetadata(target(), initial);
403 EXPECT_CALL(dynamicControl(),
404 StoreMetadata(GetSuperDevice(),
405 MetadataMatches({{S("system"), 2_GiB},
406 {S("vendor"), 1_GiB},
407 {T("system"), 3_GiB},
408 {T("vendor"), 1_GiB}}),
409 target()))
410 .WillOnce(Return(true));
411 ExpectRemap({T("system"), T("vendor")});
412
413 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
414 target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
415 ExpectDevicesAreMapped({T("system"), T("vendor")});
416}
417
418// Test resize case. Shrink if target metadata contains a partition with a size
419// greater than expected.
420TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
421 PartitionSizes initial{{S("system"), 2_GiB},
422 {S("vendor"), 1_GiB},
423 {T("system"), 2_GiB},
424 {T("vendor"), 1_GiB}};
425 SetMetadata(source(), initial);
426 SetMetadata(target(), initial);
427 EXPECT_CALL(dynamicControl(),
428 StoreMetadata(GetSuperDevice(),
429 MetadataMatches({{S("system"), 2_GiB},
430 {S("vendor"), 1_GiB},
431 {T("system"), 2_GiB},
432 {T("vendor"), 150_MiB}}),
433 target()))
434 .WillOnce(Return(true));
435 ExpectRemap({T("system"), T("vendor")});
436
437 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
438 target(), {{"system", 2_GiB}, {"vendor", 150_MiB}}));
439 ExpectDevicesAreMapped({T("system"), T("vendor")});
440}
441
442// Test adding partitions on the first run.
443TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
444 SetMetadata(source(), {});
445 SetMetadata(target(), {});
446 EXPECT_CALL(dynamicControl(),
447 StoreMetadata(
448 GetSuperDevice(),
449 MetadataMatches({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}}),
450 target()))
451 .WillOnce(Return(true));
452 ExpectRemap({T("system"), T("vendor")});
453
454 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
455 target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
456 ExpectDevicesAreMapped({T("system"), T("vendor")});
457}
458
459// Test subsequent add case.
460TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
461 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
462 SetMetadata(target(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
463 EXPECT_CALL(dynamicControl(),
464 StoreMetadata(GetSuperDevice(),
465 MetadataMatches({{S("system"), 2_GiB},
466 {T("system"), 2_GiB},
467 {T("vendor"), 1_GiB}}),
468 target()))
469 .WillOnce(Return(true));
470 ExpectRemap({T("system"), T("vendor")});
471
472 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
473 target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
474 ExpectDevicesAreMapped({T("system"), T("vendor")});
475}
476
477// Test delete one partition.
478TEST_P(BootControlAndroidTestP, DeletePartition) {
479 PartitionSizes initial{{S("system"), 2_GiB},
480 {S("vendor"), 1_GiB},
481 {T("system"), 2_GiB},
482 {T("vendor"), 1_GiB}};
483 SetMetadata(source(), initial);
484 SetMetadata(target(), initial);
485 EXPECT_CALL(dynamicControl(),
486 StoreMetadata(GetSuperDevice(),
487 MetadataMatches({{S("system"), 2_GiB},
488 {S("vendor"), 1_GiB},
489 {T("system"), 2_GiB},
490 {T("vendor"), 0}}),
491 target()))
492 .WillOnce(Return(true));
493 ExpectUnmap({T("system"), T("vendor")});
494 ExpectMap({T("system")});
495
496 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
497 target(), {{"system", 2_GiB}, {"vendor", 0}}));
498 ExpectDevicesAreMapped({T("system")});
499}
500
501// Test delete all partitions.
502TEST_P(BootControlAndroidTestP, DeleteAll) {
503 PartitionSizes initial{{S("system"), 2_GiB},
504 {S("vendor"), 1_GiB},
505 {T("system"), 2_GiB},
506 {T("vendor"), 1_GiB}};
507 SetMetadata(source(), initial);
508 SetMetadata(target(), initial);
509 EXPECT_CALL(dynamicControl(),
510 StoreMetadata(GetSuperDevice(),
511 MetadataMatches({{S("system"), 2_GiB},
512 {S("vendor"), 1_GiB},
513 {T("system"), 0},
514 {T("vendor"), 0}}),
515 target()))
516 .WillOnce(Return(true));
517 ExpectUnmap({T("system"), T("vendor")});
518 ExpectMap({});
519
520 EXPECT_TRUE(
521 bootctl_.InitPartitionMetadata(target(), {{"system", 0}, {"vendor", 0}}));
522 ExpectDevicesAreMapped({});
523}
524
525// Test corrupt source metadata case. This shouldn't happen in practice,
526// because the device is already booted normally.
527TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
528 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), source()))
529 .WillOnce(Invoke([](auto, auto) { return nullptr; }));
530 EXPECT_FALSE(bootctl_.InitPartitionMetadata(target(), {}))
531 << "Should not be able to continue with corrupt source metadata";
532}
533
534// Test corrupt target metadata case. This may happen in practice.
535// BootControlAndroid should copy from source metadata and make necessary
536// modifications on it.
537TEST_P(BootControlAndroidTestP, CorruptedTargetMetadata) {
538 SetMetadata(source(),
539 {{S("system"), 2_GiB},
540 {S("vendor"), 1_GiB},
541 {T("system"), 0},
542 {T("vendor"), 0}});
543 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), target()))
544 .WillOnce(Invoke([](auto, auto) { return nullptr; }));
545 EXPECT_CALL(dynamicControl(),
546 StoreMetadata(GetSuperDevice(),
547 MetadataMatches({{S("system"), 2_GiB},
548 {S("vendor"), 1_GiB},
549 {T("system"), 3_GiB},
550 {T("vendor"), 150_MiB}}),
551 target()))
552 .WillOnce(Return(true));
553 ExpectRemap({T("system"), T("vendor")});
554 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
555 target(), {{"system", 3_GiB}, {"vendor", 150_MiB}}));
556 ExpectDevicesAreMapped({T("system"), T("vendor")});
557}
558
559// Test that InitPartitionMetadata fail if there is not enough space on the
560// device.
561TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
562 PartitionSizes initial{{S("system"), 3_GiB},
563 {S("vendor"), 2_GiB},
564 {T("system"), 0},
565 {T("vendor"), 0}};
566 SetMetadata(source(), initial);
567 SetMetadata(target(), initial);
568 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
569 target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
570 << "Should not be able to fit 11GiB data into 10GiB space";
571}
572
573INSTANTIATE_TEST_CASE_P(ParamTest,
574 BootControlAndroidTestP,
575 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
576
577const PartitionSizes update_sizes_0() {
578 return {{"grown_a", 2_GiB},
579 {"shrunk_a", 1_GiB},
580 {"same_a", 100_MiB},
581 {"deleted_a", 150_MiB},
582 {"grown_b", 200_MiB},
583 {"shrunk_b", 0},
584 {"same_b", 0}};
585}
586
587const PartitionSizes 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 {"grown_b", 3_GiB},
594 {"shrunk_b", 150_MiB},
595 {"same_b", 100_MiB},
596 {"added_b", 150_MiB},
597 {"deleted_b", 0},
598 };
599}
600
601const PartitionSizes update_sizes_2() {
602 return {{"grown_a", 4_GiB},
603 {"shrunk_a", 100_MiB},
604 {"same_a", 100_MiB},
605 {"added_a", 0_MiB},
606 {"deleted_a", 64_MiB},
607 {"grown_b", 3_GiB},
608 {"shrunk_b", 150_MiB},
609 {"same_b", 100_MiB},
610 {"added_b", 150_MiB},
611 {"deleted_b", 0}};
612}
613
614// Test case for first update after the device is manufactured, in which
615// case the "other" slot is likely of size "0" (except system, which is
616// non-zero because of system_other partition)
617TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
618 SetSlots({0, 1});
619
620 SetMetadata(source(), update_sizes_0());
621 SetMetadata(target(), update_sizes_0());
622 EXPECT_CALL(
623 dynamicControl(),
624 StoreMetadata(
625 GetSuperDevice(), MetadataMatches(update_sizes_1()), target()))
626 .WillOnce(Return(true));
627 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b", "deleted_b"});
628 ExpectMap({"grown_b", "shrunk_b", "same_b", "added_b"});
629
630 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(),
631 {{"grown", 3_GiB},
632 {"shrunk", 150_MiB},
633 {"same", 100_MiB},
634 {"added", 150_MiB},
635 {"deleted", 0_MiB}}));
636 ExpectDevicesAreMapped({"grown_b", "shrunk_b", "same_b", "added_b"});
637}
638
639// After first update, test for the second update. In the second update, the
640// "added" partition is deleted and "deleted" partition is re-added.
641TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
642 SetSlots({1, 0});
643
644 SetMetadata(source(), update_sizes_1());
645 SetMetadata(target(), update_sizes_0());
646
647 EXPECT_CALL(
648 dynamicControl(),
649 StoreMetadata(
650 GetSuperDevice(), MetadataMatches(update_sizes_2()), target()))
651 .WillOnce(Return(true));
652 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "added_a", "deleted_a"});
653 ExpectMap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
654
655 EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(),
656 {{"grown", 4_GiB},
657 {"shrunk", 100_MiB},
658 {"same", 100_MiB},
659 {"added", 0_MiB},
660 {"deleted", 64_MiB}}));
661 ExpectDevicesAreMapped({"grown_a", "shrunk_a", "same_a", "deleted_a"});
662}
663
664TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
665 SetSlots({1, 1});
666 EXPECT_FALSE(bootctl_.InitPartitionMetadata(target(), {}))
667 << "Should not be able to apply to current slot.";
668}
669
670} // namespace chromeos_update_engine