blob: 223e177d2e59f30b496ff903701beb6fca786016 [file] [log] [blame]
Yifan Hongc049f932019-07-23 15:06:05 -07001//
2// Copyright (C) 2019 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/dynamic_partition_control_android.h"
18
19#include <set>
20#include <vector>
21
22#include <base/logging.h>
23#include <base/strings/string_util.h>
24#include <gmock/gmock.h>
25#include <gtest/gtest.h>
Yifan Hong29692902020-03-26 12:47:05 -070026#include <libavb/libavb.h>
Yifan Hong302fa702020-04-16 09:48:29 -070027#include <libsnapshot/mock_snapshot.h>
Yifan Hongc049f932019-07-23 15:06:05 -070028
Yifan Hong6a6d0f12020-03-11 13:20:52 -070029#include "update_engine/common/mock_prefs.h"
Yifan Hong29692902020-03-26 12:47:05 -070030#include "update_engine/common/test_utils.h"
Yifan Hongc049f932019-07-23 15:06:05 -070031#include "update_engine/dynamic_partition_test_utils.h"
32#include "update_engine/mock_dynamic_partition_control.h"
33
Yifan Hong3a1a5612019-11-05 16:34:32 -080034using android::dm::DmDeviceState;
Yifan Hong302fa702020-04-16 09:48:29 -070035using android::snapshot::MockSnapshotManager;
Yifan Hong29692902020-03-26 12:47:05 -070036using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
37using chromeos_update_engine::test_utils::ScopedTempFile;
Yifan Hongc049f932019-07-23 15:06:05 -070038using std::string;
39using testing::_;
40using testing::AnyNumber;
Yifan Hong3a1a5612019-11-05 16:34:32 -080041using testing::AnyOf;
Yifan Hongc049f932019-07-23 15:06:05 -070042using testing::Invoke;
43using testing::NiceMock;
44using testing::Not;
Yifan Hong29692902020-03-26 12:47:05 -070045using testing::Optional;
Yifan Hongc049f932019-07-23 15:06:05 -070046using testing::Return;
47
48namespace chromeos_update_engine {
49
50class DynamicPartitionControlAndroidTest : public ::testing::Test {
51 public:
52 void SetUp() override {
53 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
54
55 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
56 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
Yifan Hong413d5722019-07-23 14:21:09 -070057 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
58 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
Yifan Hongc049f932019-07-23 15:06:05 -070059
60 ON_CALL(dynamicControl(), GetDeviceDir(_))
61 .WillByDefault(Invoke([](auto path) {
62 *path = kFakeDevicePath;
63 return true;
64 }));
Yifan Hong700d7c12019-07-23 20:49:16 -070065
66 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
67 .WillByDefault(Return(kFakeSuper));
Yifan Hong3a1a5612019-11-05 16:34:32 -080068
69 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
70 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
71 *device = GetDmDevice(partition_name_suffix);
72 return true;
73 }));
Yifan Hong29692902020-03-26 12:47:05 -070074
75 ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
76 .WillByDefault(Return(true));
Yifan Hong302fa702020-04-16 09:48:29 -070077
78 ON_CALL(dynamicControl(), IsRecovery()).WillByDefault(Return(false));
79
80 ON_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
81 .WillByDefault(Invoke([&](uint32_t source_slot,
82 uint32_t target_slot,
83 const DeltaArchiveManifest& manifest,
84 bool delete_source) {
85 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
86 source_slot, target_slot, manifest, delete_source);
87 }));
Yifan Hongc049f932019-07-23 15:06:05 -070088 }
89
90 // Return the mocked DynamicPartitionControlInterface.
91 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
92 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
93 }
94
Yifan Hong700d7c12019-07-23 20:49:16 -070095 std::string GetSuperDevice(uint32_t slot) {
96 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
97 }
98
Yifan Hongc049f932019-07-23 15:06:05 -070099 uint32_t source() { return slots_.source; }
100 uint32_t target() { return slots_.target; }
101
102 // Return partition names with suffix of source().
103 std::string S(const std::string& name) {
104 return name + kSlotSuffixes[source()];
105 }
106
107 // Return partition names with suffix of target().
108 std::string T(const std::string& name) {
109 return name + kSlotSuffixes[target()];
110 }
111
112 // Set the fake metadata to return when LoadMetadataBuilder is called on
113 // |slot|.
Yifan Hong29692902020-03-26 12:47:05 -0700114 void SetMetadata(uint32_t slot,
115 const PartitionSuffixSizes& sizes,
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700116 uint32_t partition_attr = 0,
117 uint64_t super_size = kDefaultSuperSize) {
Yifan Hongc049f932019-07-23 15:06:05 -0700118 EXPECT_CALL(dynamicControl(),
Tianjie24f96092020-06-30 12:26:25 -0700119 LoadMetadataBuilder(GetSuperDevice(slot), slot))
120 .Times(AnyNumber())
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700121 .WillRepeatedly(Invoke([=](auto, auto) {
Tianjie24f96092020-06-30 12:26:25 -0700122 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700123 partition_attr,
124 super_size);
Tianjie24f96092020-06-30 12:26:25 -0700125 }));
126
127 EXPECT_CALL(dynamicControl(),
Yifan Hongc049f932019-07-23 15:06:05 -0700128 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
129 .Times(AnyNumber())
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700130 .WillRepeatedly(Invoke([=](auto, auto, auto) {
Yifan Hong29692902020-03-26 12:47:05 -0700131 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700132 partition_attr,
133 super_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700134 }));
135 }
136
137 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
138 EXPECT_CALL(dynamicControl(),
139 StoreMetadata(GetSuperDevice(target()),
140 MetadataMatches(partition_sizes),
141 target()))
142 .WillOnce(Return(true));
143 }
144
145 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
146 // slot with each partition in |partitions|.
147 void ExpectUnmap(const std::set<std::string>& partitions) {
148 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
149 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
150 .WillByDefault(Return(false));
151
152 for (const auto& partition : partitions) {
153 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
154 .WillOnce(Return(true));
155 }
156 }
157 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
158 return dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800159 source(),
160 target(),
161 PartitionSizesToManifest(partition_sizes),
162 true,
163 nullptr);
Yifan Hongc049f932019-07-23 15:06:05 -0700164 }
165 void SetSlots(const TestParam& slots) { slots_ = slots; }
166
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000167 void SetSnapshotEnabled(bool enabled) {
168 dynamicControl().target_supports_snapshot_ = enabled;
169 }
170
Yifan Hongc049f932019-07-23 15:06:05 -0700171 struct Listener : public ::testing::MatchResultListener {
172 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
173 };
174
175 testing::AssertionResult UpdatePartitionMetadata(
176 const PartitionSuffixSizes& source_metadata,
177 const PartitionSizes& update_metadata,
178 const PartitionSuffixSizes& expected) {
179 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700180 PartitionSuffixSizesToManifest(source_metadata),
181 PartitionSizesToManifest(update_metadata),
182 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700183 }
184 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700185 const DeltaArchiveManifest& source_manifest,
186 const DeltaArchiveManifest& update_manifest,
187 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700188 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700189 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700190 }
191 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700192 const DeltaArchiveManifest& source_manifest,
193 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700194 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700195 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700196 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700197 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700198 return testing::AssertionFailure()
199 << "UpdatePartitionMetadataInternal failed";
200 }
201 std::stringstream ss;
202 Listener listener(&ss);
203 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
204 return testing::AssertionSuccess() << ss.str();
205 } else {
206 return testing::AssertionFailure() << ss.str();
207 }
208 }
209
210 std::unique_ptr<DynamicPartitionControlAndroid> module_;
211 TestParam slots_;
212};
213
214class DynamicPartitionControlAndroidTestP
215 : public DynamicPartitionControlAndroidTest,
216 public ::testing::WithParamInterface<TestParam> {
217 public:
218 void SetUp() override {
219 DynamicPartitionControlAndroidTest::SetUp();
220 SetSlots(GetParam());
221 }
222};
223
224// Test resize case. Grow if target metadata contains a partition with a size
225// less than expected.
226TEST_P(DynamicPartitionControlAndroidTestP,
227 NeedGrowIfSizeNotMatchWhenResizing) {
228 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
229 {S("vendor"), 1_GiB},
230 {T("system"), 2_GiB},
231 {T("vendor"), 1_GiB}};
232 PartitionSuffixSizes expected{{S("system"), 2_GiB},
233 {S("vendor"), 1_GiB},
234 {T("system"), 3_GiB},
235 {T("vendor"), 1_GiB}};
236 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
237 EXPECT_TRUE(
238 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
239}
240
241// Test resize case. Shrink if target metadata contains a partition with a size
242// greater than expected.
243TEST_P(DynamicPartitionControlAndroidTestP,
244 NeedShrinkIfSizeNotMatchWhenResizing) {
245 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
246 {S("vendor"), 1_GiB},
247 {T("system"), 2_GiB},
248 {T("vendor"), 1_GiB}};
249 PartitionSuffixSizes expected{{S("system"), 2_GiB},
250 {S("vendor"), 1_GiB},
251 {T("system"), 2_GiB},
252 {T("vendor"), 150_MiB}};
253 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
254 EXPECT_TRUE(
255 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
256}
257
258// Test adding partitions on the first run.
259TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
260 PartitionSuffixSizes source_metadata{};
261 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
262 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
263 EXPECT_TRUE(
264 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
265}
266
267// Test subsequent add case.
268TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
269 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
270 {T("system"), 2_GiB}};
271 PartitionSuffixSizes expected{
272 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
273 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
274 EXPECT_TRUE(
275 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
276}
277
278// Test delete one partition.
279TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
280 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
281 {S("vendor"), 1_GiB},
282 {T("system"), 2_GiB},
283 {T("vendor"), 1_GiB}};
284 // No T("vendor")
285 PartitionSuffixSizes expected{
286 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
287 PartitionSizes update_metadata{{"system", 2_GiB}};
288 EXPECT_TRUE(
289 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
290}
291
292// Test delete all partitions.
293TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
294 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
295 {S("vendor"), 1_GiB},
296 {T("system"), 2_GiB},
297 {T("vendor"), 1_GiB}};
298 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
299 PartitionSizes update_metadata{};
300 EXPECT_TRUE(
301 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
302}
303
304// Test corrupt source metadata case.
305TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
306 EXPECT_CALL(dynamicControl(),
307 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
308 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
309 ExpectUnmap({T("system")});
310
311 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
312 << "Should not be able to continue with corrupt source metadata";
313}
314
315// Test that UpdatePartitionMetadata fails if there is not enough space on the
316// device.
317TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
318 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
319 {S("vendor"), 2_GiB},
320 {T("system"), 0},
321 {T("vendor"), 0}};
322 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
323
324 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
325 << "Should not be able to fit 11GiB data into 10GiB space";
326}
327
328TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
329 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
330 {S("vendor"), 1_GiB},
331 {T("system"), 0},
332 {T("vendor"), 0}};
333 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
334 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
335 << "Should not be able to grow over size of super / 2";
336}
337
Yifan Hong3a1a5612019-11-05 16:34:32 -0800338TEST_P(DynamicPartitionControlAndroidTestP,
339 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
340 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
341 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
342 // Static partition {system,bar}_{a,b} exists.
343 EXPECT_CALL(dynamicControl(),
344 DeviceExists(AnyOf(GetDevice(S("bar")),
345 GetDevice(T("bar")),
346 GetDevice(S("system")),
347 GetDevice(T("system")))))
348 .WillRepeatedly(Return(true));
349
350 SetMetadata(source(),
351 {{S("system"), 2_GiB},
352 {S("vendor"), 1_GiB},
353 {T("system"), 2_GiB},
354 {T("vendor"), 1_GiB}});
355
356 // Not calling through
357 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
358 // don't want any default group in the PartitionMetadata.
359 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800360 source(), target(), {}, true, nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800361
362 // Should use dynamic source partitions.
363 EXPECT_CALL(dynamicControl(), GetState(S("system")))
364 .Times(1)
365 .WillOnce(Return(DmDeviceState::ACTIVE));
366 string system_device;
367 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
368 "system", source(), source(), &system_device));
369 EXPECT_EQ(GetDmDevice(S("system")), system_device);
370
371 // Should use static target partitions without querying dynamic control.
372 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
373 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
374 "system", target(), source(), &system_device));
375 EXPECT_EQ(GetDevice(T("system")), system_device);
376
377 // Static partition "bar".
378 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
379 std::string bar_device;
380 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
381 "bar", source(), source(), &bar_device));
382 EXPECT_EQ(GetDevice(S("bar")), bar_device);
383
384 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
385 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
386 "bar", target(), source(), &bar_device));
387 EXPECT_EQ(GetDevice(T("bar")), bar_device);
388}
389
390TEST_P(DynamicPartitionControlAndroidTestP,
391 GetPartitionDeviceWhenResumingUpdate) {
392 // Static partition bar_{a,b} exists.
393 EXPECT_CALL(dynamicControl(),
394 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
395 .WillRepeatedly(Return(true));
396
397 // Both of the two slots contain valid partition metadata, since this is
398 // resuming an update.
399 SetMetadata(source(),
400 {{S("system"), 2_GiB},
401 {S("vendor"), 1_GiB},
402 {T("system"), 2_GiB},
403 {T("vendor"), 1_GiB}});
404 SetMetadata(target(),
405 {{S("system"), 2_GiB},
406 {S("vendor"), 1_GiB},
407 {T("system"), 2_GiB},
408 {T("vendor"), 1_GiB}});
409
410 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
411 source(),
412 target(),
413 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
Yifan Hongf033ecb2020-01-07 18:13:56 -0800414 false,
415 nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800416
417 // Dynamic partition "system".
418 EXPECT_CALL(dynamicControl(), GetState(S("system")))
419 .Times(1)
420 .WillOnce(Return(DmDeviceState::ACTIVE));
421 string system_device;
422 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
423 "system", source(), source(), &system_device));
424 EXPECT_EQ(GetDmDevice(S("system")), system_device);
425
426 EXPECT_CALL(dynamicControl(), GetState(T("system")))
427 .Times(AnyNumber())
428 .WillOnce(Return(DmDeviceState::ACTIVE));
429 EXPECT_CALL(dynamicControl(),
430 MapPartitionOnDeviceMapper(
431 GetSuperDevice(target()), T("system"), target(), _, _))
432 .Times(AnyNumber())
433 .WillRepeatedly(
434 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
435 *device = "/fake/remapped/" + name;
436 return true;
437 }));
438 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
439 "system", target(), source(), &system_device));
440 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
441
442 // Static partition "bar".
443 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
444 std::string bar_device;
445 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
446 "bar", source(), source(), &bar_device));
447 EXPECT_EQ(GetDevice(S("bar")), bar_device);
448
449 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
450 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
451 "bar", target(), source(), &bar_device));
452 EXPECT_EQ(GetDevice(T("bar")), bar_device);
453}
454
Yifan Hongc049f932019-07-23 15:06:05 -0700455INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
456 DynamicPartitionControlAndroidTestP,
457 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
458
459class DynamicPartitionControlAndroidGroupTestP
460 : public DynamicPartitionControlAndroidTestP {
461 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700462 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700463 void SetUp() override {
464 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700465 AddGroupAndPartition(
466 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
467 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
468 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
469 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700470 }
471
Yifan Hong13d41cb2019-09-16 13:18:22 -0700472 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
473 const string& group,
474 uint64_t group_size,
475 const string& partition,
476 uint64_t partition_size) {
477 auto* g = AddGroup(manifest, group, group_size);
478 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700479 }
480};
481
482// Allow to resize within group.
483TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700484 DeltaArchiveManifest expected;
485 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
486 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700487
Yifan Hong13d41cb2019-09-16 13:18:22 -0700488 DeltaArchiveManifest update_manifest;
489 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
490 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700491
492 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700493 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700494}
495
496TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700497 DeltaArchiveManifest update_manifest;
498 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
499 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
500 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700501 << "Should not be able to grow over maximum size of group";
502}
503
504TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700505 DeltaArchiveManifest update_manifest;
506 AddGroup(&update_manifest, "android", 3_GiB);
507 AddGroup(&update_manifest, "oem", 3_GiB);
508 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700509 << "Should not be able to grow over size of super / 2";
510}
511
512TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700513 DeltaArchiveManifest expected;
514 auto* g = AddGroup(&expected, T("android"), 3_GiB);
515 AddPartition(&expected, g, T("system"), 2_GiB);
516 AddPartition(&expected, g, T("system_ext"), 1_GiB);
517
518 DeltaArchiveManifest update_manifest;
519 g = AddGroup(&update_manifest, "android", 3_GiB);
520 AddPartition(&update_manifest, g, "system", 2_GiB);
521 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
522 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
523
Yifan Hongc049f932019-07-23 15:06:05 -0700524 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700525 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700526}
527
528TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700529 DeltaArchiveManifest expected;
530 AddGroup(&expected, T("android"), 3_GiB);
531
532 DeltaArchiveManifest update_manifest;
533 AddGroup(&update_manifest, "android", 3_GiB);
534 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
535
Yifan Hongc049f932019-07-23 15:06:05 -0700536 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700537 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700538}
539
540TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700541 DeltaArchiveManifest expected;
542 AddGroupAndPartition(
543 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
544
545 DeltaArchiveManifest update_manifest;
546 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
547 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
548 AddGroupAndPartition(
549 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700550 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700551 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700552}
553
554TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700555 DeltaArchiveManifest update_manifest;
556 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700557
558 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700559 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700560}
561
562TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700563 DeltaArchiveManifest expected;
564 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
565 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
566 DeltaArchiveManifest update_manifest;
567 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
568 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700569 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700570 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700571}
572
573INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
574 DynamicPartitionControlAndroidGroupTestP,
575 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
576
577const PartitionSuffixSizes update_sizes_0() {
578 // Initial state is 0 for "other" slot.
579 return {
580 {"grown_a", 2_GiB},
581 {"shrunk_a", 1_GiB},
582 {"same_a", 100_MiB},
583 {"deleted_a", 150_MiB},
584 // no added_a
585 {"grown_b", 200_MiB},
586 // simulate system_other
587 {"shrunk_b", 0},
588 {"same_b", 0},
589 {"deleted_b", 0},
590 // no added_b
591 };
592}
593
594const PartitionSuffixSizes update_sizes_1() {
595 return {
596 {"grown_a", 2_GiB},
597 {"shrunk_a", 1_GiB},
598 {"same_a", 100_MiB},
599 {"deleted_a", 150_MiB},
600 // no added_a
601 {"grown_b", 3_GiB},
602 {"shrunk_b", 150_MiB},
603 {"same_b", 100_MiB},
604 {"added_b", 150_MiB},
605 // no deleted_b
606 };
607}
608
609const PartitionSuffixSizes update_sizes_2() {
610 return {
611 {"grown_a", 4_GiB},
612 {"shrunk_a", 100_MiB},
613 {"same_a", 100_MiB},
614 {"deleted_a", 64_MiB},
615 // no added_a
616 {"grown_b", 3_GiB},
617 {"shrunk_b", 150_MiB},
618 {"same_b", 100_MiB},
619 {"added_b", 150_MiB},
620 // no deleted_b
621 };
622}
623
624// Test case for first update after the device is manufactured, in which
625// case the "other" slot is likely of size "0" (except system, which is
626// non-zero because of system_other partition)
627TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
628 SetSlots({0, 1});
629
630 SetMetadata(source(), update_sizes_0());
631 SetMetadata(target(), update_sizes_0());
632 ExpectStoreMetadata(update_sizes_1());
633 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
634
635 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
636 {"shrunk", 150_MiB},
637 {"same", 100_MiB},
638 {"added", 150_MiB}}));
639}
640
641// After first update, test for the second update. In the second update, the
642// "added" partition is deleted and "deleted" partition is re-added.
643TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
644 SetSlots({1, 0});
645
646 SetMetadata(source(), update_sizes_1());
647 SetMetadata(target(), update_sizes_0());
648
649 ExpectStoreMetadata(update_sizes_2());
650 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
651
652 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
653 {"shrunk", 100_MiB},
654 {"same", 100_MiB},
655 {"deleted", 64_MiB}}));
656}
657
Yifan Hong3a1a5612019-11-05 16:34:32 -0800658TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
659 SetSlots({1, 1});
660 EXPECT_FALSE(PreparePartitionsForUpdate({}))
661 << "Should not be able to apply to current slot.";
662}
663
Yifan Hongf5261562020-03-10 10:28:10 -0700664TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
Yifan Hong6eec9952019-12-04 13:12:01 -0800665 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800666 source(),
667 target(),
668 PartitionSizesToManifest({{"foo", 4_MiB}}),
669 false,
670 nullptr));
Yifan Hong6eec9952019-12-04 13:12:01 -0800671 dynamicControl().set_fake_mapped_devices({T("foo")});
672
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000673 InstallOperation iop;
Yifan Hongf5261562020-03-10 10:28:10 -0700674 InstallOperation optimized;
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000675 Extent *se, *de;
676
677 // Not a SOURCE_COPY operation, cannot skip.
678 iop.set_type(InstallOperation::REPLACE);
Yifan Hongf5261562020-03-10 10:28:10 -0700679 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000680
681 iop.set_type(InstallOperation::SOURCE_COPY);
682
683 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700684 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000685
686 // Enable GetVirtualAbFeatureFlag in the mock interface.
687 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
688 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
689
690 // By default target_supports_snapshot_ is set to false. Cannot skip
691 // operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700692 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000693
694 SetSnapshotEnabled(true);
695
696 // Empty source and destination. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700697 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
698 EXPECT_TRUE(optimized.src_extents().empty());
699 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000700
701 se = iop.add_src_extents();
702 se->set_start_block(0);
703 se->set_num_blocks(1);
704
705 // There is something in sources, but destinations are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700706 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000707
708 InstallOperation iop2;
709
710 de = iop2.add_dst_extents();
711 de->set_start_block(0);
712 de->set_num_blocks(1);
713
714 // There is something in destinations, but sources are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700715 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000716
717 de = iop.add_dst_extents();
718 de->set_start_block(0);
719 de->set_num_blocks(1);
720
721 // Sources and destinations are identical. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700722 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
723 EXPECT_TRUE(optimized.src_extents().empty());
724 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000725
726 se = iop.add_src_extents();
727 se->set_start_block(1);
728 se->set_num_blocks(5);
729
730 // There is something in source, but not in destination. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700731 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000732
733 de = iop.add_dst_extents();
734 de->set_start_block(1);
735 de->set_num_blocks(5);
736
737 // There is source and destination are equal. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700738 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
739 EXPECT_TRUE(optimized.src_extents().empty());
740 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000741
742 de = iop.add_dst_extents();
743 de->set_start_block(6);
744 de->set_num_blocks(5);
745
746 // There is something extra in dest. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700747 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000748
749 se = iop.add_src_extents();
750 se->set_start_block(6);
751 se->set_num_blocks(5);
752
753 // Source and dest are identical again. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700754 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
755 EXPECT_TRUE(optimized.src_extents().empty());
756 EXPECT_TRUE(optimized.dst_extents().empty());
757
758 iop.Clear();
759 iop.set_type(InstallOperation::SOURCE_COPY);
760 se = iop.add_src_extents();
761 se->set_start_block(1);
762 se->set_num_blocks(1);
763 se = iop.add_src_extents();
764 se->set_start_block(3);
765 se->set_num_blocks(2);
766 se = iop.add_src_extents();
767 se->set_start_block(7);
768 se->set_num_blocks(2);
769 de = iop.add_dst_extents();
770 de->set_start_block(2);
771 de->set_num_blocks(5);
772
773 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
774 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
775 ASSERT_EQ(2, optimized.src_extents_size());
776 ASSERT_EQ(2, optimized.dst_extents_size());
777 EXPECT_EQ(1u, optimized.src_extents(0).start_block());
778 EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
779 EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
780 EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
781 EXPECT_EQ(7u, optimized.src_extents(1).start_block());
782 EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
783 EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
784 EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
Yifan Hong6eec9952019-12-04 13:12:01 -0800785
786 // Don't skip for static partitions.
Yifan Hongf5261562020-03-10 10:28:10 -0700787 EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000788}
789
Yifan Hong6a6d0f12020-03-11 13:20:52 -0700790TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
791 MockPrefs prefs;
792 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
793}
794
Yifan Hong29692902020-03-26 12:47:05 -0700795TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
796 // clang-format off
797 std::string fstab_content =
798 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical\n" // NOLINT(whitespace/line_length)
799 "/dev/block/by-name/system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other\n"; // NOLINT(whitespace/line_length)
800 // clang-format on
801 ScopedTempFile fstab;
802 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
803 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
804 Optional(false));
805}
806
807TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
808 // clang-format off
809 std::string fstab_content =
810 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical,avb_keys=/foo\n"; // NOLINT(whitespace/line_length)
811 // clang-format on
812 ScopedTempFile fstab;
813 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
814 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
815 Optional(true));
816}
817
818TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
819 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
820 .WillByDefault(Invoke([&](auto source_slot,
821 auto target_slot,
822 const auto& name,
823 auto path,
824 auto should_unmap) {
825 return dynamicControl().RealGetSystemOtherPath(
826 source_slot, target_slot, name, path, should_unmap);
827 }));
828 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
829 .WillByDefault(Return(false));
830 EXPECT_TRUE(
831 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
832}
833
834TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
835 SetMetadata(source(), {{S("system"), 100_MiB}});
836 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
837 .WillByDefault(Return(true));
838 std::string path;
839 bool should_unmap;
840 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
841 source(), target(), T("system"), &path, &should_unmap));
842 ASSERT_TRUE(path.empty()) << path;
843 ASSERT_FALSE(should_unmap);
844 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
845 .WillByDefault(Invoke([&](auto source_slot,
846 auto target_slot,
847 const auto& name,
848 auto path,
849 auto should_unmap) {
850 return dynamicControl().RealGetSystemOtherPath(
851 source_slot, target_slot, name, path, should_unmap);
852 }));
853 EXPECT_TRUE(
854 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
855}
856
857TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
858 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
859 SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
860 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
861 .WillByDefault(Return(true));
862 std::string path;
863 bool should_unmap;
864 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
865 source(), target(), T("system"), &path, &should_unmap));
866 ASSERT_TRUE(path.empty()) << path;
867 ASSERT_FALSE(should_unmap);
868 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
869 .WillByDefault(Invoke([&](auto source_slot,
870 auto target_slot,
871 const auto& name,
872 auto path,
873 auto should_unmap) {
874 return dynamicControl().RealGetSystemOtherPath(
875 source_slot, target_slot, name, path, should_unmap);
876 }));
877 EXPECT_TRUE(
878 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
879}
880
881TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
882 constexpr uint64_t file_size = 1_MiB;
883 static_assert(file_size > AVB_FOOTER_SIZE);
884 ScopedTempFile system_other;
885 brillo::Blob original(file_size, 'X');
886 ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
887 std::string mnt_path;
888 ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
889 ASSERT_TRUE(dev.is_bound());
890
891 brillo::Blob device_content;
892 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
893 ASSERT_EQ(original, device_content);
894
895 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
896 SetMetadata(source(), sizes);
897 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
898 .WillByDefault(Return(true));
899 EXPECT_CALL(dynamicControl(),
900 GetSystemOtherPath(source(), target(), T("system"), _, _))
901 .WillRepeatedly(
902 Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
903 *path = mnt_path;
904 *should_unmap = false;
905 return true;
906 }));
907 ASSERT_TRUE(
908 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
909
910 device_content.clear();
911 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
912 brillo::Blob new_expected(original);
913 // Clear the last AVB_FOOTER_SIZE bytes.
914 new_expected.resize(file_size - AVB_FOOTER_SIZE);
915 new_expected.resize(file_size, '\0');
916 ASSERT_EQ(new_expected, device_content);
917}
918
Yifan Hong302fa702020-04-16 09:48:29 -0700919class FakeAutoDevice : public android::snapshot::AutoDevice {
920 public:
921 FakeAutoDevice() : AutoDevice("") {}
922};
923
924class SnapshotPartitionTestP : public DynamicPartitionControlAndroidTestP {
925 public:
926 void SetUp() override {
927 DynamicPartitionControlAndroidTestP::SetUp();
928 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
929 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
930
931 snapshot_ = new NiceMock<MockSnapshotManager>();
932 dynamicControl().snapshot_.reset(snapshot_); // takes ownership
933 EXPECT_CALL(*snapshot_, BeginUpdate()).WillOnce(Return(true));
934 EXPECT_CALL(*snapshot_, EnsureMetadataMounted())
935 .WillRepeatedly(
936 Invoke([]() { return std::make_unique<FakeAutoDevice>(); }));
937
938 manifest_ =
939 PartitionSizesToManifest({{"system", 3_GiB}, {"vendor", 1_GiB}});
940 }
941 void ExpectCreateUpdateSnapshots(android::snapshot::Return val) {
942 manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
943 EXPECT_CALL(*snapshot_, CreateUpdateSnapshots(_))
944 .WillRepeatedly(Invoke([&, val](const auto& manifest) {
945 // Deep comparison requires full protobuf library. Comparing the
946 // pointers are sufficient.
947 EXPECT_EQ(&manifest_, &manifest);
948 LOG(WARNING) << "CreateUpdateSnapshots returning " << val.string();
949 return val;
950 }));
951 }
952 bool PreparePartitionsForUpdate(uint64_t* required_size) {
953 return dynamicControl().PreparePartitionsForUpdate(
954 source(), target(), manifest_, true /* update */, required_size);
955 }
956 MockSnapshotManager* snapshot_ = nullptr;
957 DeltaArchiveManifest manifest_;
958};
959
960// Test happy path of PreparePartitionsForUpdate on a Virtual A/B device.
961TEST_P(SnapshotPartitionTestP, PreparePartitions) {
962 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
963 uint64_t required_size = 0;
964 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
965 EXPECT_EQ(0u, required_size);
966}
967
968// Test that if not enough space, required size returned by SnapshotManager is
969// passed up.
970TEST_P(SnapshotPartitionTestP, PreparePartitionsNoSpace) {
971 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
972 uint64_t required_size = 0;
973 EXPECT_FALSE(PreparePartitionsForUpdate(&required_size));
974 EXPECT_EQ(1_GiB, required_size);
975}
976
977// Test that in recovery, use empty space in super partition for a snapshot
978// update first.
979TEST_P(SnapshotPartitionTestP, RecoveryUseSuperEmpty) {
980 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
981 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
982 // Must not call PrepareDynamicPartitionsForUpdate if
983 // PrepareSnapshotPartitionsForUpdate succeeds.
984 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
985 .Times(0);
986 uint64_t required_size = 0;
987 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
988 EXPECT_EQ(0u, required_size);
989}
990
991// Test that in recovery, if CreateUpdateSnapshots throws an error, try
992// the flashing path for full updates.
993TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
994 // Expectation on PreparePartitionsForUpdate
995 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
996 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
997 EXPECT_CALL(*snapshot_, CancelUpdate()).WillOnce(Return(true));
998 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
999 .WillRepeatedly(Invoke([&](auto source_slot,
1000 auto target_slot,
1001 const auto& manifest,
1002 auto delete_source) {
1003 EXPECT_EQ(source(), source_slot);
1004 EXPECT_EQ(target(), target_slot);
1005 // Deep comparison requires full protobuf library. Comparing the
1006 // pointers are sufficient.
1007 EXPECT_EQ(&manifest_, &manifest);
1008 EXPECT_TRUE(delete_source);
1009 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
1010 source_slot, target_slot, manifest, delete_source);
1011 }));
Yifan Hong8d6df9a2020-08-13 13:59:54 -07001012 // Only one slot of space in super
1013 uint64_t super_size = kDefaultGroupSize + 1_MiB;
Yifan Hong302fa702020-04-16 09:48:29 -07001014 // Expectation on PrepareDynamicPartitionsForUpdate
Yifan Hong8d6df9a2020-08-13 13:59:54 -07001015 SetMetadata(
1016 source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size);
Yifan Hong302fa702020-04-16 09:48:29 -07001017 ExpectUnmap({T("system"), T("vendor")});
1018 // Expect that the source partitions aren't present in target super metadata.
1019 ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
1020
1021 uint64_t required_size = 0;
1022 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1023 EXPECT_EQ(0u, required_size);
1024}
1025
1026INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
1027 SnapshotPartitionTestP,
1028 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
1029
Yifan Hongc049f932019-07-23 15:06:05 -07001030} // namespace chromeos_update_engine