blob: c1e0dafca0045c046f1b3d4ac586e68525f82884 [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;
Yifan Hongc049f932019-07-23 15:06:05 -070037using std::string;
38using testing::_;
39using testing::AnyNumber;
Yifan Hong3a1a5612019-11-05 16:34:32 -080040using testing::AnyOf;
Yifan Hongc049f932019-07-23 15:06:05 -070041using testing::Invoke;
42using testing::NiceMock;
43using testing::Not;
Yifan Hong29692902020-03-26 12:47:05 -070044using testing::Optional;
Yifan Hongc049f932019-07-23 15:06:05 -070045using testing::Return;
46
47namespace chromeos_update_engine {
48
49class DynamicPartitionControlAndroidTest : public ::testing::Test {
50 public:
51 void SetUp() override {
52 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
53
54 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
55 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
Yifan Hong413d5722019-07-23 14:21:09 -070056 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
57 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
Yifan Hongc049f932019-07-23 15:06:05 -070058
59 ON_CALL(dynamicControl(), GetDeviceDir(_))
60 .WillByDefault(Invoke([](auto path) {
61 *path = kFakeDevicePath;
62 return true;
63 }));
Yifan Hong700d7c12019-07-23 20:49:16 -070064
65 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
66 .WillByDefault(Return(kFakeSuper));
Yifan Hong3a1a5612019-11-05 16:34:32 -080067
68 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
69 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
70 *device = GetDmDevice(partition_name_suffix);
71 return true;
72 }));
Yifan Hong29692902020-03-26 12:47:05 -070073
74 ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
75 .WillByDefault(Return(true));
Yifan Hong302fa702020-04-16 09:48:29 -070076
77 ON_CALL(dynamicControl(), IsRecovery()).WillByDefault(Return(false));
78
79 ON_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
80 .WillByDefault(Invoke([&](uint32_t source_slot,
81 uint32_t target_slot,
82 const DeltaArchiveManifest& manifest,
83 bool delete_source) {
84 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
85 source_slot, target_slot, manifest, delete_source);
86 }));
Yifan Hongc049f932019-07-23 15:06:05 -070087 }
88
89 // Return the mocked DynamicPartitionControlInterface.
90 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
91 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
92 }
93
Yifan Hong700d7c12019-07-23 20:49:16 -070094 std::string GetSuperDevice(uint32_t slot) {
95 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
96 }
97
Yifan Hongc049f932019-07-23 15:06:05 -070098 uint32_t source() { return slots_.source; }
99 uint32_t target() { return slots_.target; }
100
101 // Return partition names with suffix of source().
102 std::string S(const std::string& name) {
103 return name + kSlotSuffixes[source()];
104 }
105
106 // Return partition names with suffix of target().
107 std::string T(const std::string& name) {
108 return name + kSlotSuffixes[target()];
109 }
110
111 // Set the fake metadata to return when LoadMetadataBuilder is called on
112 // |slot|.
Yifan Hong29692902020-03-26 12:47:05 -0700113 void SetMetadata(uint32_t slot,
114 const PartitionSuffixSizes& sizes,
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700115 uint32_t partition_attr = 0,
116 uint64_t super_size = kDefaultSuperSize) {
Yifan Hongc049f932019-07-23 15:06:05 -0700117 EXPECT_CALL(dynamicControl(),
Tianjie24f96092020-06-30 12:26:25 -0700118 LoadMetadataBuilder(GetSuperDevice(slot), slot))
119 .Times(AnyNumber())
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700120 .WillRepeatedly(Invoke([=](auto, auto) {
Tianjie24f96092020-06-30 12:26:25 -0700121 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700122 partition_attr,
123 super_size);
Tianjie24f96092020-06-30 12:26:25 -0700124 }));
125
126 EXPECT_CALL(dynamicControl(),
Yifan Hongc049f932019-07-23 15:06:05 -0700127 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
128 .Times(AnyNumber())
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700129 .WillRepeatedly(Invoke([=](auto, auto, auto) {
Yifan Hong29692902020-03-26 12:47:05 -0700130 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
Yifan Hong8d6df9a2020-08-13 13:59:54 -0700131 partition_attr,
132 super_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700133 }));
134 }
135
136 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
137 EXPECT_CALL(dynamicControl(),
138 StoreMetadata(GetSuperDevice(target()),
139 MetadataMatches(partition_sizes),
140 target()))
141 .WillOnce(Return(true));
142 }
143
144 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
145 // slot with each partition in |partitions|.
146 void ExpectUnmap(const std::set<std::string>& partitions) {
147 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
148 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
149 .WillByDefault(Return(false));
150
151 for (const auto& partition : partitions) {
152 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
153 .WillOnce(Return(true));
154 }
155 }
156 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
157 return dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800158 source(),
159 target(),
160 PartitionSizesToManifest(partition_sizes),
161 true,
162 nullptr);
Yifan Hongc049f932019-07-23 15:06:05 -0700163 }
164 void SetSlots(const TestParam& slots) { slots_ = slots; }
165
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000166 void SetSnapshotEnabled(bool enabled) {
167 dynamicControl().target_supports_snapshot_ = enabled;
168 }
169
Yifan Hongc049f932019-07-23 15:06:05 -0700170 struct Listener : public ::testing::MatchResultListener {
171 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
172 };
173
174 testing::AssertionResult UpdatePartitionMetadata(
175 const PartitionSuffixSizes& source_metadata,
176 const PartitionSizes& update_metadata,
177 const PartitionSuffixSizes& expected) {
178 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700179 PartitionSuffixSizesToManifest(source_metadata),
180 PartitionSizesToManifest(update_metadata),
181 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700182 }
183 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700184 const DeltaArchiveManifest& source_manifest,
185 const DeltaArchiveManifest& update_manifest,
186 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700187 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700188 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700189 }
190 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700191 const DeltaArchiveManifest& source_manifest,
192 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700193 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700194 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700195 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700196 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700197 return testing::AssertionFailure()
198 << "UpdatePartitionMetadataInternal failed";
199 }
200 std::stringstream ss;
201 Listener listener(&ss);
202 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
203 return testing::AssertionSuccess() << ss.str();
204 } else {
205 return testing::AssertionFailure() << ss.str();
206 }
207 }
208
209 std::unique_ptr<DynamicPartitionControlAndroid> module_;
210 TestParam slots_;
211};
212
213class DynamicPartitionControlAndroidTestP
214 : public DynamicPartitionControlAndroidTest,
215 public ::testing::WithParamInterface<TestParam> {
216 public:
217 void SetUp() override {
218 DynamicPartitionControlAndroidTest::SetUp();
219 SetSlots(GetParam());
220 }
221};
222
223// Test resize case. Grow if target metadata contains a partition with a size
224// less than expected.
225TEST_P(DynamicPartitionControlAndroidTestP,
226 NeedGrowIfSizeNotMatchWhenResizing) {
227 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
228 {S("vendor"), 1_GiB},
229 {T("system"), 2_GiB},
230 {T("vendor"), 1_GiB}};
231 PartitionSuffixSizes expected{{S("system"), 2_GiB},
232 {S("vendor"), 1_GiB},
233 {T("system"), 3_GiB},
234 {T("vendor"), 1_GiB}};
235 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
236 EXPECT_TRUE(
237 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
238}
239
240// Test resize case. Shrink if target metadata contains a partition with a size
241// greater than expected.
242TEST_P(DynamicPartitionControlAndroidTestP,
243 NeedShrinkIfSizeNotMatchWhenResizing) {
244 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
245 {S("vendor"), 1_GiB},
246 {T("system"), 2_GiB},
247 {T("vendor"), 1_GiB}};
248 PartitionSuffixSizes expected{{S("system"), 2_GiB},
249 {S("vendor"), 1_GiB},
250 {T("system"), 2_GiB},
251 {T("vendor"), 150_MiB}};
252 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
253 EXPECT_TRUE(
254 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
255}
256
257// Test adding partitions on the first run.
258TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
259 PartitionSuffixSizes source_metadata{};
260 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
261 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
262 EXPECT_TRUE(
263 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
264}
265
266// Test subsequent add case.
267TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
268 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
269 {T("system"), 2_GiB}};
270 PartitionSuffixSizes expected{
271 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
272 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
273 EXPECT_TRUE(
274 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
275}
276
277// Test delete one partition.
278TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
279 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
280 {S("vendor"), 1_GiB},
281 {T("system"), 2_GiB},
282 {T("vendor"), 1_GiB}};
283 // No T("vendor")
284 PartitionSuffixSizes expected{
285 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
286 PartitionSizes update_metadata{{"system", 2_GiB}};
287 EXPECT_TRUE(
288 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
289}
290
291// Test delete all partitions.
292TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
293 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
294 {S("vendor"), 1_GiB},
295 {T("system"), 2_GiB},
296 {T("vendor"), 1_GiB}};
297 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
298 PartitionSizes update_metadata{};
299 EXPECT_TRUE(
300 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
301}
302
303// Test corrupt source metadata case.
304TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
305 EXPECT_CALL(dynamicControl(),
306 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
307 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
308 ExpectUnmap({T("system")});
309
310 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
311 << "Should not be able to continue with corrupt source metadata";
312}
313
314// Test that UpdatePartitionMetadata fails if there is not enough space on the
315// device.
316TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
317 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
318 {S("vendor"), 2_GiB},
319 {T("system"), 0},
320 {T("vendor"), 0}};
321 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
322
323 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
324 << "Should not be able to fit 11GiB data into 10GiB space";
325}
326
327TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
328 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
329 {S("vendor"), 1_GiB},
330 {T("system"), 0},
331 {T("vendor"), 0}};
332 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
333 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
334 << "Should not be able to grow over size of super / 2";
335}
336
Yifan Hong3a1a5612019-11-05 16:34:32 -0800337TEST_P(DynamicPartitionControlAndroidTestP,
338 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
339 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
340 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
341 // Static partition {system,bar}_{a,b} exists.
342 EXPECT_CALL(dynamicControl(),
343 DeviceExists(AnyOf(GetDevice(S("bar")),
344 GetDevice(T("bar")),
345 GetDevice(S("system")),
346 GetDevice(T("system")))))
347 .WillRepeatedly(Return(true));
348
349 SetMetadata(source(),
350 {{S("system"), 2_GiB},
351 {S("vendor"), 1_GiB},
352 {T("system"), 2_GiB},
353 {T("vendor"), 1_GiB}});
354
355 // Not calling through
356 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
357 // don't want any default group in the PartitionMetadata.
358 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800359 source(), target(), {}, true, nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800360
361 // Should use dynamic source partitions.
362 EXPECT_CALL(dynamicControl(), GetState(S("system")))
363 .Times(1)
364 .WillOnce(Return(DmDeviceState::ACTIVE));
365 string system_device;
366 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
367 "system", source(), source(), &system_device));
368 EXPECT_EQ(GetDmDevice(S("system")), system_device);
369
370 // Should use static target partitions without querying dynamic control.
371 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
372 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
373 "system", target(), source(), &system_device));
374 EXPECT_EQ(GetDevice(T("system")), system_device);
375
376 // Static partition "bar".
377 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
378 std::string bar_device;
379 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
380 "bar", source(), source(), &bar_device));
381 EXPECT_EQ(GetDevice(S("bar")), bar_device);
382
383 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
384 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
385 "bar", target(), source(), &bar_device));
386 EXPECT_EQ(GetDevice(T("bar")), bar_device);
387}
388
389TEST_P(DynamicPartitionControlAndroidTestP,
390 GetPartitionDeviceWhenResumingUpdate) {
391 // Static partition bar_{a,b} exists.
392 EXPECT_CALL(dynamicControl(),
393 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
394 .WillRepeatedly(Return(true));
395
396 // Both of the two slots contain valid partition metadata, since this is
397 // resuming an update.
398 SetMetadata(source(),
399 {{S("system"), 2_GiB},
400 {S("vendor"), 1_GiB},
401 {T("system"), 2_GiB},
402 {T("vendor"), 1_GiB}});
403 SetMetadata(target(),
404 {{S("system"), 2_GiB},
405 {S("vendor"), 1_GiB},
406 {T("system"), 2_GiB},
407 {T("vendor"), 1_GiB}});
408
409 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
410 source(),
411 target(),
412 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
Yifan Hongf033ecb2020-01-07 18:13:56 -0800413 false,
414 nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800415
416 // Dynamic partition "system".
417 EXPECT_CALL(dynamicControl(), GetState(S("system")))
418 .Times(1)
419 .WillOnce(Return(DmDeviceState::ACTIVE));
420 string system_device;
421 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
422 "system", source(), source(), &system_device));
423 EXPECT_EQ(GetDmDevice(S("system")), system_device);
424
425 EXPECT_CALL(dynamicControl(), GetState(T("system")))
426 .Times(AnyNumber())
427 .WillOnce(Return(DmDeviceState::ACTIVE));
428 EXPECT_CALL(dynamicControl(),
429 MapPartitionOnDeviceMapper(
430 GetSuperDevice(target()), T("system"), target(), _, _))
431 .Times(AnyNumber())
432 .WillRepeatedly(
433 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
434 *device = "/fake/remapped/" + name;
435 return true;
436 }));
437 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
438 "system", target(), source(), &system_device));
439 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
440
441 // Static partition "bar".
442 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
443 std::string bar_device;
444 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
445 "bar", source(), source(), &bar_device));
446 EXPECT_EQ(GetDevice(S("bar")), bar_device);
447
448 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
449 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
450 "bar", target(), source(), &bar_device));
451 EXPECT_EQ(GetDevice(T("bar")), bar_device);
452}
453
Yifan Hongc049f932019-07-23 15:06:05 -0700454INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
455 DynamicPartitionControlAndroidTestP,
456 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
457
458class DynamicPartitionControlAndroidGroupTestP
459 : public DynamicPartitionControlAndroidTestP {
460 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700461 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700462 void SetUp() override {
463 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700464 AddGroupAndPartition(
465 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
466 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
467 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
468 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700469 }
470
Yifan Hong13d41cb2019-09-16 13:18:22 -0700471 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
472 const string& group,
473 uint64_t group_size,
474 const string& partition,
475 uint64_t partition_size) {
476 auto* g = AddGroup(manifest, group, group_size);
477 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700478 }
479};
480
481// Allow to resize within group.
482TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700483 DeltaArchiveManifest expected;
484 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
485 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700486
Yifan Hong13d41cb2019-09-16 13:18:22 -0700487 DeltaArchiveManifest update_manifest;
488 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
489 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700490
491 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700492 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700493}
494
495TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700496 DeltaArchiveManifest update_manifest;
497 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
498 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
499 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700500 << "Should not be able to grow over maximum size of group";
501}
502
503TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700504 DeltaArchiveManifest update_manifest;
505 AddGroup(&update_manifest, "android", 3_GiB);
506 AddGroup(&update_manifest, "oem", 3_GiB);
507 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700508 << "Should not be able to grow over size of super / 2";
509}
510
511TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700512 DeltaArchiveManifest expected;
513 auto* g = AddGroup(&expected, T("android"), 3_GiB);
514 AddPartition(&expected, g, T("system"), 2_GiB);
515 AddPartition(&expected, g, T("system_ext"), 1_GiB);
516
517 DeltaArchiveManifest update_manifest;
518 g = AddGroup(&update_manifest, "android", 3_GiB);
519 AddPartition(&update_manifest, g, "system", 2_GiB);
520 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
521 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
522
Yifan Hongc049f932019-07-23 15:06:05 -0700523 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700524 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700525}
526
527TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700528 DeltaArchiveManifest expected;
529 AddGroup(&expected, T("android"), 3_GiB);
530
531 DeltaArchiveManifest update_manifest;
532 AddGroup(&update_manifest, "android", 3_GiB);
533 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
534
Yifan Hongc049f932019-07-23 15:06:05 -0700535 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700536 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700537}
538
539TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700540 DeltaArchiveManifest expected;
541 AddGroupAndPartition(
542 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
543
544 DeltaArchiveManifest update_manifest;
545 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
546 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
547 AddGroupAndPartition(
548 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700549 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700550 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700551}
552
553TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700554 DeltaArchiveManifest update_manifest;
555 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700556
557 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700558 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700559}
560
561TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700562 DeltaArchiveManifest expected;
563 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
564 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
565 DeltaArchiveManifest update_manifest;
566 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
567 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700568 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700569 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700570}
571
572INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
573 DynamicPartitionControlAndroidGroupTestP,
574 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
575
576const PartitionSuffixSizes update_sizes_0() {
577 // Initial state is 0 for "other" slot.
578 return {
579 {"grown_a", 2_GiB},
580 {"shrunk_a", 1_GiB},
581 {"same_a", 100_MiB},
582 {"deleted_a", 150_MiB},
583 // no added_a
584 {"grown_b", 200_MiB},
585 // simulate system_other
586 {"shrunk_b", 0},
587 {"same_b", 0},
588 {"deleted_b", 0},
589 // no added_b
590 };
591}
592
593const PartitionSuffixSizes update_sizes_1() {
594 return {
595 {"grown_a", 2_GiB},
596 {"shrunk_a", 1_GiB},
597 {"same_a", 100_MiB},
598 {"deleted_a", 150_MiB},
599 // no added_a
600 {"grown_b", 3_GiB},
601 {"shrunk_b", 150_MiB},
602 {"same_b", 100_MiB},
603 {"added_b", 150_MiB},
604 // no deleted_b
605 };
606}
607
608const PartitionSuffixSizes update_sizes_2() {
609 return {
610 {"grown_a", 4_GiB},
611 {"shrunk_a", 100_MiB},
612 {"same_a", 100_MiB},
613 {"deleted_a", 64_MiB},
614 // no added_a
615 {"grown_b", 3_GiB},
616 {"shrunk_b", 150_MiB},
617 {"same_b", 100_MiB},
618 {"added_b", 150_MiB},
619 // no deleted_b
620 };
621}
622
623// Test case for first update after the device is manufactured, in which
624// case the "other" slot is likely of size "0" (except system, which is
625// non-zero because of system_other partition)
626TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
627 SetSlots({0, 1});
628
629 SetMetadata(source(), update_sizes_0());
630 SetMetadata(target(), update_sizes_0());
631 ExpectStoreMetadata(update_sizes_1());
632 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
633
634 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
635 {"shrunk", 150_MiB},
636 {"same", 100_MiB},
637 {"added", 150_MiB}}));
638}
639
640// After first update, test for the second update. In the second update, the
641// "added" partition is deleted and "deleted" partition is re-added.
642TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
643 SetSlots({1, 0});
644
645 SetMetadata(source(), update_sizes_1());
646 SetMetadata(target(), update_sizes_0());
647
648 ExpectStoreMetadata(update_sizes_2());
649 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
650
651 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
652 {"shrunk", 100_MiB},
653 {"same", 100_MiB},
654 {"deleted", 64_MiB}}));
655}
656
Yifan Hong3a1a5612019-11-05 16:34:32 -0800657TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
658 SetSlots({1, 1});
659 EXPECT_FALSE(PreparePartitionsForUpdate({}))
660 << "Should not be able to apply to current slot.";
661}
662
Yifan Hongf5261562020-03-10 10:28:10 -0700663TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
Yifan Hong6eec9952019-12-04 13:12:01 -0800664 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800665 source(),
666 target(),
667 PartitionSizesToManifest({{"foo", 4_MiB}}),
668 false,
669 nullptr));
Yifan Hong6eec9952019-12-04 13:12:01 -0800670 dynamicControl().set_fake_mapped_devices({T("foo")});
671
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000672 InstallOperation iop;
Yifan Hongf5261562020-03-10 10:28:10 -0700673 InstallOperation optimized;
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000674 Extent *se, *de;
675
676 // Not a SOURCE_COPY operation, cannot skip.
677 iop.set_type(InstallOperation::REPLACE);
Yifan Hongf5261562020-03-10 10:28:10 -0700678 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000679
680 iop.set_type(InstallOperation::SOURCE_COPY);
681
682 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700683 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000684
685 // Enable GetVirtualAbFeatureFlag in the mock interface.
686 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
687 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
688
689 // By default target_supports_snapshot_ is set to false. Cannot skip
690 // operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700691 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000692
693 SetSnapshotEnabled(true);
694
695 // Empty source and destination. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700696 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
697 EXPECT_TRUE(optimized.src_extents().empty());
698 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000699
700 se = iop.add_src_extents();
701 se->set_start_block(0);
702 se->set_num_blocks(1);
703
704 // There is something in sources, but destinations are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700705 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000706
707 InstallOperation iop2;
708
709 de = iop2.add_dst_extents();
710 de->set_start_block(0);
711 de->set_num_blocks(1);
712
713 // There is something in destinations, but sources are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700714 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000715
716 de = iop.add_dst_extents();
717 de->set_start_block(0);
718 de->set_num_blocks(1);
719
720 // Sources and destinations are identical. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700721 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
722 EXPECT_TRUE(optimized.src_extents().empty());
723 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000724
725 se = iop.add_src_extents();
726 se->set_start_block(1);
727 se->set_num_blocks(5);
728
729 // There is something in source, but not in destination. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700730 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000731
732 de = iop.add_dst_extents();
733 de->set_start_block(1);
734 de->set_num_blocks(5);
735
736 // There is source and destination are equal. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700737 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
738 EXPECT_TRUE(optimized.src_extents().empty());
739 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000740
741 de = iop.add_dst_extents();
742 de->set_start_block(6);
743 de->set_num_blocks(5);
744
745 // There is something extra in dest. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700746 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000747
748 se = iop.add_src_extents();
749 se->set_start_block(6);
750 se->set_num_blocks(5);
751
752 // Source and dest are identical again. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700753 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
754 EXPECT_TRUE(optimized.src_extents().empty());
755 EXPECT_TRUE(optimized.dst_extents().empty());
756
757 iop.Clear();
758 iop.set_type(InstallOperation::SOURCE_COPY);
759 se = iop.add_src_extents();
760 se->set_start_block(1);
761 se->set_num_blocks(1);
762 se = iop.add_src_extents();
763 se->set_start_block(3);
764 se->set_num_blocks(2);
765 se = iop.add_src_extents();
766 se->set_start_block(7);
767 se->set_num_blocks(2);
768 de = iop.add_dst_extents();
769 de->set_start_block(2);
770 de->set_num_blocks(5);
771
772 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
773 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
774 ASSERT_EQ(2, optimized.src_extents_size());
775 ASSERT_EQ(2, optimized.dst_extents_size());
776 EXPECT_EQ(1u, optimized.src_extents(0).start_block());
777 EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
778 EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
779 EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
780 EXPECT_EQ(7u, optimized.src_extents(1).start_block());
781 EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
782 EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
783 EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
Yifan Hong6eec9952019-12-04 13:12:01 -0800784
785 // Don't skip for static partitions.
Yifan Hongf5261562020-03-10 10:28:10 -0700786 EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000787}
788
Yifan Hong6a6d0f12020-03-11 13:20:52 -0700789TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
790 MockPrefs prefs;
791 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
792}
793
Yifan Hong29692902020-03-26 12:47:05 -0700794TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
795 // clang-format off
796 std::string fstab_content =
797 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical\n" // NOLINT(whitespace/line_length)
798 "/dev/block/by-name/system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other\n"; // NOLINT(whitespace/line_length)
799 // clang-format on
800 ScopedTempFile fstab;
801 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
802 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
803 Optional(false));
804}
805
806TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
807 // clang-format off
808 std::string fstab_content =
809 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical,avb_keys=/foo\n"; // NOLINT(whitespace/line_length)
810 // clang-format on
811 ScopedTempFile fstab;
812 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
813 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
814 Optional(true));
815}
816
817TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
818 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
819 .WillByDefault(Invoke([&](auto source_slot,
820 auto target_slot,
821 const auto& name,
822 auto path,
823 auto should_unmap) {
824 return dynamicControl().RealGetSystemOtherPath(
825 source_slot, target_slot, name, path, should_unmap);
826 }));
827 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
828 .WillByDefault(Return(false));
829 EXPECT_TRUE(
830 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
831}
832
833TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
834 SetMetadata(source(), {{S("system"), 100_MiB}});
835 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
836 .WillByDefault(Return(true));
837 std::string path;
838 bool should_unmap;
839 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
840 source(), target(), T("system"), &path, &should_unmap));
841 ASSERT_TRUE(path.empty()) << path;
842 ASSERT_FALSE(should_unmap);
843 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
844 .WillByDefault(Invoke([&](auto source_slot,
845 auto target_slot,
846 const auto& name,
847 auto path,
848 auto should_unmap) {
849 return dynamicControl().RealGetSystemOtherPath(
850 source_slot, target_slot, name, path, should_unmap);
851 }));
852 EXPECT_TRUE(
853 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
854}
855
856TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
857 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
858 SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
859 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
860 .WillByDefault(Return(true));
861 std::string path;
862 bool should_unmap;
863 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
864 source(), target(), T("system"), &path, &should_unmap));
865 ASSERT_TRUE(path.empty()) << path;
866 ASSERT_FALSE(should_unmap);
867 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
868 .WillByDefault(Invoke([&](auto source_slot,
869 auto target_slot,
870 const auto& name,
871 auto path,
872 auto should_unmap) {
873 return dynamicControl().RealGetSystemOtherPath(
874 source_slot, target_slot, name, path, should_unmap);
875 }));
876 EXPECT_TRUE(
877 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
878}
879
880TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
881 constexpr uint64_t file_size = 1_MiB;
882 static_assert(file_size > AVB_FOOTER_SIZE);
883 ScopedTempFile system_other;
884 brillo::Blob original(file_size, 'X');
885 ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
886 std::string mnt_path;
887 ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
888 ASSERT_TRUE(dev.is_bound());
889
890 brillo::Blob device_content;
891 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
892 ASSERT_EQ(original, device_content);
893
894 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
895 SetMetadata(source(), sizes);
896 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
897 .WillByDefault(Return(true));
898 EXPECT_CALL(dynamicControl(),
899 GetSystemOtherPath(source(), target(), T("system"), _, _))
900 .WillRepeatedly(
901 Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
902 *path = mnt_path;
903 *should_unmap = false;
904 return true;
905 }));
906 ASSERT_TRUE(
907 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
908
909 device_content.clear();
910 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
911 brillo::Blob new_expected(original);
912 // Clear the last AVB_FOOTER_SIZE bytes.
913 new_expected.resize(file_size - AVB_FOOTER_SIZE);
914 new_expected.resize(file_size, '\0');
915 ASSERT_EQ(new_expected, device_content);
916}
917
Yifan Hong302fa702020-04-16 09:48:29 -0700918class FakeAutoDevice : public android::snapshot::AutoDevice {
919 public:
920 FakeAutoDevice() : AutoDevice("") {}
921};
922
923class SnapshotPartitionTestP : public DynamicPartitionControlAndroidTestP {
924 public:
925 void SetUp() override {
926 DynamicPartitionControlAndroidTestP::SetUp();
927 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
928 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
929
930 snapshot_ = new NiceMock<MockSnapshotManager>();
931 dynamicControl().snapshot_.reset(snapshot_); // takes ownership
932 EXPECT_CALL(*snapshot_, BeginUpdate()).WillOnce(Return(true));
933 EXPECT_CALL(*snapshot_, EnsureMetadataMounted())
934 .WillRepeatedly(
935 Invoke([]() { return std::make_unique<FakeAutoDevice>(); }));
936
937 manifest_ =
938 PartitionSizesToManifest({{"system", 3_GiB}, {"vendor", 1_GiB}});
939 }
940 void ExpectCreateUpdateSnapshots(android::snapshot::Return val) {
941 manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
942 EXPECT_CALL(*snapshot_, CreateUpdateSnapshots(_))
943 .WillRepeatedly(Invoke([&, val](const auto& manifest) {
944 // Deep comparison requires full protobuf library. Comparing the
945 // pointers are sufficient.
946 EXPECT_EQ(&manifest_, &manifest);
947 LOG(WARNING) << "CreateUpdateSnapshots returning " << val.string();
948 return val;
949 }));
950 }
951 bool PreparePartitionsForUpdate(uint64_t* required_size) {
952 return dynamicControl().PreparePartitionsForUpdate(
953 source(), target(), manifest_, true /* update */, required_size);
954 }
955 MockSnapshotManager* snapshot_ = nullptr;
956 DeltaArchiveManifest manifest_;
957};
958
959// Test happy path of PreparePartitionsForUpdate on a Virtual A/B device.
960TEST_P(SnapshotPartitionTestP, PreparePartitions) {
961 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
962 uint64_t required_size = 0;
963 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
964 EXPECT_EQ(0u, required_size);
965}
966
967// Test that if not enough space, required size returned by SnapshotManager is
968// passed up.
969TEST_P(SnapshotPartitionTestP, PreparePartitionsNoSpace) {
970 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
971 uint64_t required_size = 0;
972 EXPECT_FALSE(PreparePartitionsForUpdate(&required_size));
973 EXPECT_EQ(1_GiB, required_size);
974}
975
976// Test that in recovery, use empty space in super partition for a snapshot
977// update first.
978TEST_P(SnapshotPartitionTestP, RecoveryUseSuperEmpty) {
979 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
980 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
981 // Must not call PrepareDynamicPartitionsForUpdate if
982 // PrepareSnapshotPartitionsForUpdate succeeds.
983 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
984 .Times(0);
985 uint64_t required_size = 0;
986 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
987 EXPECT_EQ(0u, required_size);
988}
989
990// Test that in recovery, if CreateUpdateSnapshots throws an error, try
991// the flashing path for full updates.
992TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
993 // Expectation on PreparePartitionsForUpdate
994 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
995 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
996 EXPECT_CALL(*snapshot_, CancelUpdate()).WillOnce(Return(true));
997 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
998 .WillRepeatedly(Invoke([&](auto source_slot,
999 auto target_slot,
1000 const auto& manifest,
1001 auto delete_source) {
1002 EXPECT_EQ(source(), source_slot);
1003 EXPECT_EQ(target(), target_slot);
1004 // Deep comparison requires full protobuf library. Comparing the
1005 // pointers are sufficient.
1006 EXPECT_EQ(&manifest_, &manifest);
1007 EXPECT_TRUE(delete_source);
1008 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
1009 source_slot, target_slot, manifest, delete_source);
1010 }));
Yifan Hong8d6df9a2020-08-13 13:59:54 -07001011 // Only one slot of space in super
1012 uint64_t super_size = kDefaultGroupSize + 1_MiB;
Yifan Hong302fa702020-04-16 09:48:29 -07001013 // Expectation on PrepareDynamicPartitionsForUpdate
Yifan Hong8d6df9a2020-08-13 13:59:54 -07001014 SetMetadata(
1015 source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size);
Yifan Hong302fa702020-04-16 09:48:29 -07001016 ExpectUnmap({T("system"), T("vendor")});
1017 // Expect that the source partitions aren't present in target super metadata.
1018 ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
1019
1020 uint64_t required_size = 0;
1021 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1022 EXPECT_EQ(0u, required_size);
1023}
1024
1025INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
1026 SnapshotPartitionTestP,
1027 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
1028
Yifan Hongc049f932019-07-23 15:06:05 -07001029} // namespace chromeos_update_engine