blob: 373817084f62af8d7cf5025fb80b9e3e3071c53c [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,
116 uint32_t partition_attr = 0) {
Yifan Hongc049f932019-07-23 15:06:05 -0700117 EXPECT_CALL(dynamicControl(),
118 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
119 .Times(AnyNumber())
Yifan Hong29692902020-03-26 12:47:05 -0700120 .WillRepeatedly(Invoke([sizes, partition_attr](auto, auto, auto) {
121 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
122 partition_attr);
Yifan Hongc049f932019-07-23 15:06:05 -0700123 }));
124 }
125
126 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
127 EXPECT_CALL(dynamicControl(),
128 StoreMetadata(GetSuperDevice(target()),
129 MetadataMatches(partition_sizes),
130 target()))
131 .WillOnce(Return(true));
132 }
133
134 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
135 // slot with each partition in |partitions|.
136 void ExpectUnmap(const std::set<std::string>& partitions) {
137 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
138 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
139 .WillByDefault(Return(false));
140
141 for (const auto& partition : partitions) {
142 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
143 .WillOnce(Return(true));
144 }
145 }
146 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
147 return dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800148 source(),
149 target(),
150 PartitionSizesToManifest(partition_sizes),
151 true,
152 nullptr);
Yifan Hongc049f932019-07-23 15:06:05 -0700153 }
154 void SetSlots(const TestParam& slots) { slots_ = slots; }
155
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000156 void SetSnapshotEnabled(bool enabled) {
157 dynamicControl().target_supports_snapshot_ = enabled;
158 }
159
Yifan Hongc049f932019-07-23 15:06:05 -0700160 struct Listener : public ::testing::MatchResultListener {
161 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
162 };
163
164 testing::AssertionResult UpdatePartitionMetadata(
165 const PartitionSuffixSizes& source_metadata,
166 const PartitionSizes& update_metadata,
167 const PartitionSuffixSizes& expected) {
168 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700169 PartitionSuffixSizesToManifest(source_metadata),
170 PartitionSizesToManifest(update_metadata),
171 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700172 }
173 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700174 const DeltaArchiveManifest& source_manifest,
175 const DeltaArchiveManifest& update_manifest,
176 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700177 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700178 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700179 }
180 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700181 const DeltaArchiveManifest& source_manifest,
182 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700183 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700184 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700185 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700186 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700187 return testing::AssertionFailure()
188 << "UpdatePartitionMetadataInternal failed";
189 }
190 std::stringstream ss;
191 Listener listener(&ss);
192 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
193 return testing::AssertionSuccess() << ss.str();
194 } else {
195 return testing::AssertionFailure() << ss.str();
196 }
197 }
198
199 std::unique_ptr<DynamicPartitionControlAndroid> module_;
200 TestParam slots_;
201};
202
203class DynamicPartitionControlAndroidTestP
204 : public DynamicPartitionControlAndroidTest,
205 public ::testing::WithParamInterface<TestParam> {
206 public:
207 void SetUp() override {
208 DynamicPartitionControlAndroidTest::SetUp();
209 SetSlots(GetParam());
210 }
211};
212
213// Test resize case. Grow if target metadata contains a partition with a size
214// less than expected.
215TEST_P(DynamicPartitionControlAndroidTestP,
216 NeedGrowIfSizeNotMatchWhenResizing) {
217 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
218 {S("vendor"), 1_GiB},
219 {T("system"), 2_GiB},
220 {T("vendor"), 1_GiB}};
221 PartitionSuffixSizes expected{{S("system"), 2_GiB},
222 {S("vendor"), 1_GiB},
223 {T("system"), 3_GiB},
224 {T("vendor"), 1_GiB}};
225 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
226 EXPECT_TRUE(
227 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
228}
229
230// Test resize case. Shrink if target metadata contains a partition with a size
231// greater than expected.
232TEST_P(DynamicPartitionControlAndroidTestP,
233 NeedShrinkIfSizeNotMatchWhenResizing) {
234 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
235 {S("vendor"), 1_GiB},
236 {T("system"), 2_GiB},
237 {T("vendor"), 1_GiB}};
238 PartitionSuffixSizes expected{{S("system"), 2_GiB},
239 {S("vendor"), 1_GiB},
240 {T("system"), 2_GiB},
241 {T("vendor"), 150_MiB}};
242 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
243 EXPECT_TRUE(
244 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
245}
246
247// Test adding partitions on the first run.
248TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
249 PartitionSuffixSizes source_metadata{};
250 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
251 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
252 EXPECT_TRUE(
253 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
254}
255
256// Test subsequent add case.
257TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
258 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
259 {T("system"), 2_GiB}};
260 PartitionSuffixSizes expected{
261 {S("system"), 2_GiB}, {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 delete one partition.
268TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
269 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
270 {S("vendor"), 1_GiB},
271 {T("system"), 2_GiB},
272 {T("vendor"), 1_GiB}};
273 // No T("vendor")
274 PartitionSuffixSizes expected{
275 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
276 PartitionSizes update_metadata{{"system", 2_GiB}};
277 EXPECT_TRUE(
278 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
279}
280
281// Test delete all partitions.
282TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
283 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
284 {S("vendor"), 1_GiB},
285 {T("system"), 2_GiB},
286 {T("vendor"), 1_GiB}};
287 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
288 PartitionSizes update_metadata{};
289 EXPECT_TRUE(
290 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
291}
292
293// Test corrupt source metadata case.
294TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
295 EXPECT_CALL(dynamicControl(),
296 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
297 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
298 ExpectUnmap({T("system")});
299
300 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
301 << "Should not be able to continue with corrupt source metadata";
302}
303
304// Test that UpdatePartitionMetadata fails if there is not enough space on the
305// device.
306TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
307 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
308 {S("vendor"), 2_GiB},
309 {T("system"), 0},
310 {T("vendor"), 0}};
311 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
312
313 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
314 << "Should not be able to fit 11GiB data into 10GiB space";
315}
316
317TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
318 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
319 {S("vendor"), 1_GiB},
320 {T("system"), 0},
321 {T("vendor"), 0}};
322 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
323 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
324 << "Should not be able to grow over size of super / 2";
325}
326
Yifan Hong3a1a5612019-11-05 16:34:32 -0800327TEST_P(DynamicPartitionControlAndroidTestP,
328 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
329 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
330 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
331 // Static partition {system,bar}_{a,b} exists.
332 EXPECT_CALL(dynamicControl(),
333 DeviceExists(AnyOf(GetDevice(S("bar")),
334 GetDevice(T("bar")),
335 GetDevice(S("system")),
336 GetDevice(T("system")))))
337 .WillRepeatedly(Return(true));
338
339 SetMetadata(source(),
340 {{S("system"), 2_GiB},
341 {S("vendor"), 1_GiB},
342 {T("system"), 2_GiB},
343 {T("vendor"), 1_GiB}});
344
345 // Not calling through
346 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
347 // don't want any default group in the PartitionMetadata.
348 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800349 source(), target(), {}, true, nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800350
351 // Should use dynamic source partitions.
352 EXPECT_CALL(dynamicControl(), GetState(S("system")))
353 .Times(1)
354 .WillOnce(Return(DmDeviceState::ACTIVE));
355 string system_device;
356 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
357 "system", source(), source(), &system_device));
358 EXPECT_EQ(GetDmDevice(S("system")), system_device);
359
360 // Should use static target partitions without querying dynamic control.
361 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
362 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
363 "system", target(), source(), &system_device));
364 EXPECT_EQ(GetDevice(T("system")), system_device);
365
366 // Static partition "bar".
367 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
368 std::string bar_device;
369 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
370 "bar", source(), source(), &bar_device));
371 EXPECT_EQ(GetDevice(S("bar")), bar_device);
372
373 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
374 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
375 "bar", target(), source(), &bar_device));
376 EXPECT_EQ(GetDevice(T("bar")), bar_device);
377}
378
379TEST_P(DynamicPartitionControlAndroidTestP,
380 GetPartitionDeviceWhenResumingUpdate) {
381 // Static partition bar_{a,b} exists.
382 EXPECT_CALL(dynamicControl(),
383 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
384 .WillRepeatedly(Return(true));
385
386 // Both of the two slots contain valid partition metadata, since this is
387 // resuming an update.
388 SetMetadata(source(),
389 {{S("system"), 2_GiB},
390 {S("vendor"), 1_GiB},
391 {T("system"), 2_GiB},
392 {T("vendor"), 1_GiB}});
393 SetMetadata(target(),
394 {{S("system"), 2_GiB},
395 {S("vendor"), 1_GiB},
396 {T("system"), 2_GiB},
397 {T("vendor"), 1_GiB}});
398
399 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
400 source(),
401 target(),
402 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
Yifan Hongf033ecb2020-01-07 18:13:56 -0800403 false,
404 nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800405
406 // Dynamic partition "system".
407 EXPECT_CALL(dynamicControl(), GetState(S("system")))
408 .Times(1)
409 .WillOnce(Return(DmDeviceState::ACTIVE));
410 string system_device;
411 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
412 "system", source(), source(), &system_device));
413 EXPECT_EQ(GetDmDevice(S("system")), system_device);
414
415 EXPECT_CALL(dynamicControl(), GetState(T("system")))
416 .Times(AnyNumber())
417 .WillOnce(Return(DmDeviceState::ACTIVE));
418 EXPECT_CALL(dynamicControl(),
419 MapPartitionOnDeviceMapper(
420 GetSuperDevice(target()), T("system"), target(), _, _))
421 .Times(AnyNumber())
422 .WillRepeatedly(
423 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
424 *device = "/fake/remapped/" + name;
425 return true;
426 }));
427 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
428 "system", target(), source(), &system_device));
429 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
430
431 // Static partition "bar".
432 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
433 std::string bar_device;
434 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
435 "bar", source(), source(), &bar_device));
436 EXPECT_EQ(GetDevice(S("bar")), bar_device);
437
438 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
439 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
440 "bar", target(), source(), &bar_device));
441 EXPECT_EQ(GetDevice(T("bar")), bar_device);
442}
443
Yifan Hongc049f932019-07-23 15:06:05 -0700444INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
445 DynamicPartitionControlAndroidTestP,
446 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
447
448class DynamicPartitionControlAndroidGroupTestP
449 : public DynamicPartitionControlAndroidTestP {
450 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700451 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700452 void SetUp() override {
453 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700454 AddGroupAndPartition(
455 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
456 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
457 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
458 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700459 }
460
Yifan Hong13d41cb2019-09-16 13:18:22 -0700461 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
462 const string& group,
463 uint64_t group_size,
464 const string& partition,
465 uint64_t partition_size) {
466 auto* g = AddGroup(manifest, group, group_size);
467 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700468 }
469};
470
471// Allow to resize within group.
472TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700473 DeltaArchiveManifest expected;
474 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
475 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700476
Yifan Hong13d41cb2019-09-16 13:18:22 -0700477 DeltaArchiveManifest update_manifest;
478 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
479 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700480
481 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700482 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700483}
484
485TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700486 DeltaArchiveManifest update_manifest;
487 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
488 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
489 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700490 << "Should not be able to grow over maximum size of group";
491}
492
493TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700494 DeltaArchiveManifest update_manifest;
495 AddGroup(&update_manifest, "android", 3_GiB);
496 AddGroup(&update_manifest, "oem", 3_GiB);
497 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700498 << "Should not be able to grow over size of super / 2";
499}
500
501TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700502 DeltaArchiveManifest expected;
503 auto* g = AddGroup(&expected, T("android"), 3_GiB);
504 AddPartition(&expected, g, T("system"), 2_GiB);
505 AddPartition(&expected, g, T("system_ext"), 1_GiB);
506
507 DeltaArchiveManifest update_manifest;
508 g = AddGroup(&update_manifest, "android", 3_GiB);
509 AddPartition(&update_manifest, g, "system", 2_GiB);
510 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
511 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
512
Yifan Hongc049f932019-07-23 15:06:05 -0700513 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700514 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700515}
516
517TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700518 DeltaArchiveManifest expected;
519 AddGroup(&expected, T("android"), 3_GiB);
520
521 DeltaArchiveManifest update_manifest;
522 AddGroup(&update_manifest, "android", 3_GiB);
523 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
524
Yifan Hongc049f932019-07-23 15:06:05 -0700525 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700526 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700527}
528
529TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700530 DeltaArchiveManifest expected;
531 AddGroupAndPartition(
532 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
533
534 DeltaArchiveManifest update_manifest;
535 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
536 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
537 AddGroupAndPartition(
538 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700539 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700540 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700541}
542
543TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700544 DeltaArchiveManifest update_manifest;
545 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700546
547 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700548 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700549}
550
551TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700552 DeltaArchiveManifest expected;
553 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
554 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
555 DeltaArchiveManifest update_manifest;
556 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
557 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700558 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700559 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700560}
561
562INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
563 DynamicPartitionControlAndroidGroupTestP,
564 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
565
566const PartitionSuffixSizes update_sizes_0() {
567 // Initial state is 0 for "other" slot.
568 return {
569 {"grown_a", 2_GiB},
570 {"shrunk_a", 1_GiB},
571 {"same_a", 100_MiB},
572 {"deleted_a", 150_MiB},
573 // no added_a
574 {"grown_b", 200_MiB},
575 // simulate system_other
576 {"shrunk_b", 0},
577 {"same_b", 0},
578 {"deleted_b", 0},
579 // no added_b
580 };
581}
582
583const PartitionSuffixSizes update_sizes_1() {
584 return {
585 {"grown_a", 2_GiB},
586 {"shrunk_a", 1_GiB},
587 {"same_a", 100_MiB},
588 {"deleted_a", 150_MiB},
589 // no added_a
590 {"grown_b", 3_GiB},
591 {"shrunk_b", 150_MiB},
592 {"same_b", 100_MiB},
593 {"added_b", 150_MiB},
594 // no deleted_b
595 };
596}
597
598const PartitionSuffixSizes update_sizes_2() {
599 return {
600 {"grown_a", 4_GiB},
601 {"shrunk_a", 100_MiB},
602 {"same_a", 100_MiB},
603 {"deleted_a", 64_MiB},
604 // no added_a
605 {"grown_b", 3_GiB},
606 {"shrunk_b", 150_MiB},
607 {"same_b", 100_MiB},
608 {"added_b", 150_MiB},
609 // no deleted_b
610 };
611}
612
613// Test case for first update after the device is manufactured, in which
614// case the "other" slot is likely of size "0" (except system, which is
615// non-zero because of system_other partition)
616TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
617 SetSlots({0, 1});
618
619 SetMetadata(source(), update_sizes_0());
620 SetMetadata(target(), update_sizes_0());
621 ExpectStoreMetadata(update_sizes_1());
622 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
623
624 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
625 {"shrunk", 150_MiB},
626 {"same", 100_MiB},
627 {"added", 150_MiB}}));
628}
629
630// After first update, test for the second update. In the second update, the
631// "added" partition is deleted and "deleted" partition is re-added.
632TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
633 SetSlots({1, 0});
634
635 SetMetadata(source(), update_sizes_1());
636 SetMetadata(target(), update_sizes_0());
637
638 ExpectStoreMetadata(update_sizes_2());
639 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
640
641 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
642 {"shrunk", 100_MiB},
643 {"same", 100_MiB},
644 {"deleted", 64_MiB}}));
645}
646
Yifan Hong3a1a5612019-11-05 16:34:32 -0800647TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
648 SetSlots({1, 1});
649 EXPECT_FALSE(PreparePartitionsForUpdate({}))
650 << "Should not be able to apply to current slot.";
651}
652
Yifan Hongf5261562020-03-10 10:28:10 -0700653TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
Yifan Hong6eec9952019-12-04 13:12:01 -0800654 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800655 source(),
656 target(),
657 PartitionSizesToManifest({{"foo", 4_MiB}}),
658 false,
659 nullptr));
Yifan Hong6eec9952019-12-04 13:12:01 -0800660 dynamicControl().set_fake_mapped_devices({T("foo")});
661
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000662 InstallOperation iop;
Yifan Hongf5261562020-03-10 10:28:10 -0700663 InstallOperation optimized;
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000664 Extent *se, *de;
665
666 // Not a SOURCE_COPY operation, cannot skip.
667 iop.set_type(InstallOperation::REPLACE);
Yifan Hongf5261562020-03-10 10:28:10 -0700668 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000669
670 iop.set_type(InstallOperation::SOURCE_COPY);
671
672 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700673 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000674
675 // Enable GetVirtualAbFeatureFlag in the mock interface.
676 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
677 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
678
679 // By default target_supports_snapshot_ is set to false. Cannot skip
680 // operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700681 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000682
683 SetSnapshotEnabled(true);
684
685 // Empty source and destination. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700686 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
687 EXPECT_TRUE(optimized.src_extents().empty());
688 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000689
690 se = iop.add_src_extents();
691 se->set_start_block(0);
692 se->set_num_blocks(1);
693
694 // There is something in sources, but destinations are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700695 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000696
697 InstallOperation iop2;
698
699 de = iop2.add_dst_extents();
700 de->set_start_block(0);
701 de->set_num_blocks(1);
702
703 // There is something in destinations, but sources are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700704 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000705
706 de = iop.add_dst_extents();
707 de->set_start_block(0);
708 de->set_num_blocks(1);
709
710 // Sources and destinations are identical. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700711 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
712 EXPECT_TRUE(optimized.src_extents().empty());
713 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000714
715 se = iop.add_src_extents();
716 se->set_start_block(1);
717 se->set_num_blocks(5);
718
719 // There is something in source, but not in destination. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700720 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000721
722 de = iop.add_dst_extents();
723 de->set_start_block(1);
724 de->set_num_blocks(5);
725
726 // There is source and destination are equal. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700727 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
728 EXPECT_TRUE(optimized.src_extents().empty());
729 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000730
731 de = iop.add_dst_extents();
732 de->set_start_block(6);
733 de->set_num_blocks(5);
734
735 // There is something extra in dest. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700736 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000737
738 se = iop.add_src_extents();
739 se->set_start_block(6);
740 se->set_num_blocks(5);
741
742 // Source and dest are identical again. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700743 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
744 EXPECT_TRUE(optimized.src_extents().empty());
745 EXPECT_TRUE(optimized.dst_extents().empty());
746
747 iop.Clear();
748 iop.set_type(InstallOperation::SOURCE_COPY);
749 se = iop.add_src_extents();
750 se->set_start_block(1);
751 se->set_num_blocks(1);
752 se = iop.add_src_extents();
753 se->set_start_block(3);
754 se->set_num_blocks(2);
755 se = iop.add_src_extents();
756 se->set_start_block(7);
757 se->set_num_blocks(2);
758 de = iop.add_dst_extents();
759 de->set_start_block(2);
760 de->set_num_blocks(5);
761
762 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
763 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
764 ASSERT_EQ(2, optimized.src_extents_size());
765 ASSERT_EQ(2, optimized.dst_extents_size());
766 EXPECT_EQ(1u, optimized.src_extents(0).start_block());
767 EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
768 EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
769 EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
770 EXPECT_EQ(7u, optimized.src_extents(1).start_block());
771 EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
772 EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
773 EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
Yifan Hong6eec9952019-12-04 13:12:01 -0800774
775 // Don't skip for static partitions.
Yifan Hongf5261562020-03-10 10:28:10 -0700776 EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000777}
778
Yifan Hong6a6d0f12020-03-11 13:20:52 -0700779TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
780 MockPrefs prefs;
781 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
782}
783
Yifan Hong29692902020-03-26 12:47:05 -0700784TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
785 // clang-format off
786 std::string fstab_content =
787 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical\n" // NOLINT(whitespace/line_length)
788 "/dev/block/by-name/system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other\n"; // NOLINT(whitespace/line_length)
789 // clang-format on
790 ScopedTempFile fstab;
791 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
792 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
793 Optional(false));
794}
795
796TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
797 // clang-format off
798 std::string fstab_content =
799 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical,avb_keys=/foo\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(true));
805}
806
807TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
808 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
809 .WillByDefault(Invoke([&](auto source_slot,
810 auto target_slot,
811 const auto& name,
812 auto path,
813 auto should_unmap) {
814 return dynamicControl().RealGetSystemOtherPath(
815 source_slot, target_slot, name, path, should_unmap);
816 }));
817 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
818 .WillByDefault(Return(false));
819 EXPECT_TRUE(
820 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
821}
822
823TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
824 SetMetadata(source(), {{S("system"), 100_MiB}});
825 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
826 .WillByDefault(Return(true));
827 std::string path;
828 bool should_unmap;
829 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
830 source(), target(), T("system"), &path, &should_unmap));
831 ASSERT_TRUE(path.empty()) << path;
832 ASSERT_FALSE(should_unmap);
833 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
834 .WillByDefault(Invoke([&](auto source_slot,
835 auto target_slot,
836 const auto& name,
837 auto path,
838 auto should_unmap) {
839 return dynamicControl().RealGetSystemOtherPath(
840 source_slot, target_slot, name, path, should_unmap);
841 }));
842 EXPECT_TRUE(
843 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
844}
845
846TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
847 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
848 SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
849 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
850 .WillByDefault(Return(true));
851 std::string path;
852 bool should_unmap;
853 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
854 source(), target(), T("system"), &path, &should_unmap));
855 ASSERT_TRUE(path.empty()) << path;
856 ASSERT_FALSE(should_unmap);
857 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
858 .WillByDefault(Invoke([&](auto source_slot,
859 auto target_slot,
860 const auto& name,
861 auto path,
862 auto should_unmap) {
863 return dynamicControl().RealGetSystemOtherPath(
864 source_slot, target_slot, name, path, should_unmap);
865 }));
866 EXPECT_TRUE(
867 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
868}
869
870TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
871 constexpr uint64_t file_size = 1_MiB;
872 static_assert(file_size > AVB_FOOTER_SIZE);
873 ScopedTempFile system_other;
874 brillo::Blob original(file_size, 'X');
875 ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
876 std::string mnt_path;
877 ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
878 ASSERT_TRUE(dev.is_bound());
879
880 brillo::Blob device_content;
881 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
882 ASSERT_EQ(original, device_content);
883
884 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
885 SetMetadata(source(), sizes);
886 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
887 .WillByDefault(Return(true));
888 EXPECT_CALL(dynamicControl(),
889 GetSystemOtherPath(source(), target(), T("system"), _, _))
890 .WillRepeatedly(
891 Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
892 *path = mnt_path;
893 *should_unmap = false;
894 return true;
895 }));
896 ASSERT_TRUE(
897 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
898
899 device_content.clear();
900 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
901 brillo::Blob new_expected(original);
902 // Clear the last AVB_FOOTER_SIZE bytes.
903 new_expected.resize(file_size - AVB_FOOTER_SIZE);
904 new_expected.resize(file_size, '\0');
905 ASSERT_EQ(new_expected, device_content);
906}
907
Yifan Hong302fa702020-04-16 09:48:29 -0700908class FakeAutoDevice : public android::snapshot::AutoDevice {
909 public:
910 FakeAutoDevice() : AutoDevice("") {}
911};
912
913class SnapshotPartitionTestP : public DynamicPartitionControlAndroidTestP {
914 public:
915 void SetUp() override {
916 DynamicPartitionControlAndroidTestP::SetUp();
917 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
918 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
919
920 snapshot_ = new NiceMock<MockSnapshotManager>();
921 dynamicControl().snapshot_.reset(snapshot_); // takes ownership
922 EXPECT_CALL(*snapshot_, BeginUpdate()).WillOnce(Return(true));
923 EXPECT_CALL(*snapshot_, EnsureMetadataMounted())
924 .WillRepeatedly(
925 Invoke([]() { return std::make_unique<FakeAutoDevice>(); }));
926
927 manifest_ =
928 PartitionSizesToManifest({{"system", 3_GiB}, {"vendor", 1_GiB}});
929 }
930 void ExpectCreateUpdateSnapshots(android::snapshot::Return val) {
931 manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
932 EXPECT_CALL(*snapshot_, CreateUpdateSnapshots(_))
933 .WillRepeatedly(Invoke([&, val](const auto& manifest) {
934 // Deep comparison requires full protobuf library. Comparing the
935 // pointers are sufficient.
936 EXPECT_EQ(&manifest_, &manifest);
937 LOG(WARNING) << "CreateUpdateSnapshots returning " << val.string();
938 return val;
939 }));
940 }
941 bool PreparePartitionsForUpdate(uint64_t* required_size) {
942 return dynamicControl().PreparePartitionsForUpdate(
943 source(), target(), manifest_, true /* update */, required_size);
944 }
945 MockSnapshotManager* snapshot_ = nullptr;
946 DeltaArchiveManifest manifest_;
947};
948
949// Test happy path of PreparePartitionsForUpdate on a Virtual A/B device.
950TEST_P(SnapshotPartitionTestP, PreparePartitions) {
951 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
952 uint64_t required_size = 0;
953 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
954 EXPECT_EQ(0u, required_size);
955}
956
957// Test that if not enough space, required size returned by SnapshotManager is
958// passed up.
959TEST_P(SnapshotPartitionTestP, PreparePartitionsNoSpace) {
960 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
961 uint64_t required_size = 0;
962 EXPECT_FALSE(PreparePartitionsForUpdate(&required_size));
963 EXPECT_EQ(1_GiB, required_size);
964}
965
966// Test that in recovery, use empty space in super partition for a snapshot
967// update first.
968TEST_P(SnapshotPartitionTestP, RecoveryUseSuperEmpty) {
969 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
970 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
971 // Must not call PrepareDynamicPartitionsForUpdate if
972 // PrepareSnapshotPartitionsForUpdate succeeds.
973 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
974 .Times(0);
975 uint64_t required_size = 0;
976 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
977 EXPECT_EQ(0u, required_size);
978}
979
980// Test that in recovery, if CreateUpdateSnapshots throws an error, try
981// the flashing path for full updates.
982TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
983 // Expectation on PreparePartitionsForUpdate
984 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
985 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
986 EXPECT_CALL(*snapshot_, CancelUpdate()).WillOnce(Return(true));
987 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
988 .WillRepeatedly(Invoke([&](auto source_slot,
989 auto target_slot,
990 const auto& manifest,
991 auto delete_source) {
992 EXPECT_EQ(source(), source_slot);
993 EXPECT_EQ(target(), target_slot);
994 // Deep comparison requires full protobuf library. Comparing the
995 // pointers are sufficient.
996 EXPECT_EQ(&manifest_, &manifest);
997 EXPECT_TRUE(delete_source);
998 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
999 source_slot, target_slot, manifest, delete_source);
1000 }));
1001 // Expectation on PrepareDynamicPartitionsForUpdate
1002 SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
1003 ExpectUnmap({T("system"), T("vendor")});
1004 // Expect that the source partitions aren't present in target super metadata.
1005 ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
1006
1007 uint64_t required_size = 0;
1008 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1009 EXPECT_EQ(0u, required_size);
1010}
1011
1012INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
1013 SnapshotPartitionTestP,
1014 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
1015
Yifan Hongc049f932019-07-23 15:06:05 -07001016} // namespace chromeos_update_engine