blob: 3e8375c16cd1f1902871e61adbe28f84557e9bcd [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>
26
27#include "update_engine/dynamic_partition_test_utils.h"
28#include "update_engine/mock_dynamic_partition_control.h"
29
Yifan Hong3a1a5612019-11-05 16:34:32 -080030using android::dm::DmDeviceState;
Yifan Hongc049f932019-07-23 15:06:05 -070031using std::string;
32using testing::_;
33using testing::AnyNumber;
Yifan Hong3a1a5612019-11-05 16:34:32 -080034using testing::AnyOf;
Yifan Hongc049f932019-07-23 15:06:05 -070035using testing::Invoke;
36using testing::NiceMock;
37using testing::Not;
38using testing::Return;
39
40namespace chromeos_update_engine {
41
42class DynamicPartitionControlAndroidTest : public ::testing::Test {
43 public:
44 void SetUp() override {
45 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
46
47 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
48 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
Yifan Hong413d5722019-07-23 14:21:09 -070049 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
50 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
Yifan Hongc049f932019-07-23 15:06:05 -070051
52 ON_CALL(dynamicControl(), GetDeviceDir(_))
53 .WillByDefault(Invoke([](auto path) {
54 *path = kFakeDevicePath;
55 return true;
56 }));
Yifan Hong700d7c12019-07-23 20:49:16 -070057
58 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
59 .WillByDefault(Return(kFakeSuper));
Yifan Hong3a1a5612019-11-05 16:34:32 -080060
61 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
62 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
63 *device = GetDmDevice(partition_name_suffix);
64 return true;
65 }));
Yifan Hongc049f932019-07-23 15:06:05 -070066 }
67
68 // Return the mocked DynamicPartitionControlInterface.
69 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
70 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
71 }
72
Yifan Hong700d7c12019-07-23 20:49:16 -070073 std::string GetSuperDevice(uint32_t slot) {
74 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
75 }
76
Yifan Hongc049f932019-07-23 15:06:05 -070077 uint32_t source() { return slots_.source; }
78 uint32_t target() { return slots_.target; }
79
80 // Return partition names with suffix of source().
81 std::string S(const std::string& name) {
82 return name + kSlotSuffixes[source()];
83 }
84
85 // Return partition names with suffix of target().
86 std::string T(const std::string& name) {
87 return name + kSlotSuffixes[target()];
88 }
89
90 // Set the fake metadata to return when LoadMetadataBuilder is called on
91 // |slot|.
92 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
93 EXPECT_CALL(dynamicControl(),
94 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
95 .Times(AnyNumber())
96 .WillRepeatedly(Invoke([sizes](auto, auto, auto) {
Yifan Hong13d41cb2019-09-16 13:18:22 -070097 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
Yifan Hongc049f932019-07-23 15:06:05 -070098 }));
99 }
100
101 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
102 EXPECT_CALL(dynamicControl(),
103 StoreMetadata(GetSuperDevice(target()),
104 MetadataMatches(partition_sizes),
105 target()))
106 .WillOnce(Return(true));
107 }
108
109 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
110 // slot with each partition in |partitions|.
111 void ExpectUnmap(const std::set<std::string>& partitions) {
112 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
113 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
114 .WillByDefault(Return(false));
115
116 for (const auto& partition : partitions) {
117 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
118 .WillOnce(Return(true));
119 }
120 }
121 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
122 return dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800123 source(),
124 target(),
125 PartitionSizesToManifest(partition_sizes),
126 true,
127 nullptr);
Yifan Hongc049f932019-07-23 15:06:05 -0700128 }
129 void SetSlots(const TestParam& slots) { slots_ = slots; }
130
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000131 void SetSnapshotEnabled(bool enabled) {
132 dynamicControl().target_supports_snapshot_ = enabled;
133 }
134
Yifan Hongc049f932019-07-23 15:06:05 -0700135 struct Listener : public ::testing::MatchResultListener {
136 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
137 };
138
139 testing::AssertionResult UpdatePartitionMetadata(
140 const PartitionSuffixSizes& source_metadata,
141 const PartitionSizes& update_metadata,
142 const PartitionSuffixSizes& expected) {
143 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700144 PartitionSuffixSizesToManifest(source_metadata),
145 PartitionSizesToManifest(update_metadata),
146 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700147 }
148 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700149 const DeltaArchiveManifest& source_manifest,
150 const DeltaArchiveManifest& update_manifest,
151 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700152 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700153 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700154 }
155 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700156 const DeltaArchiveManifest& source_manifest,
157 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700158 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700159 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700160 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700161 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700162 return testing::AssertionFailure()
163 << "UpdatePartitionMetadataInternal failed";
164 }
165 std::stringstream ss;
166 Listener listener(&ss);
167 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
168 return testing::AssertionSuccess() << ss.str();
169 } else {
170 return testing::AssertionFailure() << ss.str();
171 }
172 }
173
174 std::unique_ptr<DynamicPartitionControlAndroid> module_;
175 TestParam slots_;
176};
177
178class DynamicPartitionControlAndroidTestP
179 : public DynamicPartitionControlAndroidTest,
180 public ::testing::WithParamInterface<TestParam> {
181 public:
182 void SetUp() override {
183 DynamicPartitionControlAndroidTest::SetUp();
184 SetSlots(GetParam());
185 }
186};
187
188// Test resize case. Grow if target metadata contains a partition with a size
189// less than expected.
190TEST_P(DynamicPartitionControlAndroidTestP,
191 NeedGrowIfSizeNotMatchWhenResizing) {
192 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
193 {S("vendor"), 1_GiB},
194 {T("system"), 2_GiB},
195 {T("vendor"), 1_GiB}};
196 PartitionSuffixSizes expected{{S("system"), 2_GiB},
197 {S("vendor"), 1_GiB},
198 {T("system"), 3_GiB},
199 {T("vendor"), 1_GiB}};
200 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
201 EXPECT_TRUE(
202 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
203}
204
205// Test resize case. Shrink if target metadata contains a partition with a size
206// greater than expected.
207TEST_P(DynamicPartitionControlAndroidTestP,
208 NeedShrinkIfSizeNotMatchWhenResizing) {
209 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
210 {S("vendor"), 1_GiB},
211 {T("system"), 2_GiB},
212 {T("vendor"), 1_GiB}};
213 PartitionSuffixSizes expected{{S("system"), 2_GiB},
214 {S("vendor"), 1_GiB},
215 {T("system"), 2_GiB},
216 {T("vendor"), 150_MiB}};
217 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
218 EXPECT_TRUE(
219 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
220}
221
222// Test adding partitions on the first run.
223TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
224 PartitionSuffixSizes source_metadata{};
225 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
226 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
227 EXPECT_TRUE(
228 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
229}
230
231// Test subsequent add case.
232TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
233 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
234 {T("system"), 2_GiB}};
235 PartitionSuffixSizes expected{
236 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
237 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
238 EXPECT_TRUE(
239 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
240}
241
242// Test delete one partition.
243TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
244 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
245 {S("vendor"), 1_GiB},
246 {T("system"), 2_GiB},
247 {T("vendor"), 1_GiB}};
248 // No T("vendor")
249 PartitionSuffixSizes expected{
250 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
251 PartitionSizes update_metadata{{"system", 2_GiB}};
252 EXPECT_TRUE(
253 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
254}
255
256// Test delete all partitions.
257TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
258 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
259 {S("vendor"), 1_GiB},
260 {T("system"), 2_GiB},
261 {T("vendor"), 1_GiB}};
262 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
263 PartitionSizes update_metadata{};
264 EXPECT_TRUE(
265 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
266}
267
268// Test corrupt source metadata case.
269TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
270 EXPECT_CALL(dynamicControl(),
271 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
272 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
273 ExpectUnmap({T("system")});
274
275 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
276 << "Should not be able to continue with corrupt source metadata";
277}
278
279// Test that UpdatePartitionMetadata fails if there is not enough space on the
280// device.
281TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
282 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
283 {S("vendor"), 2_GiB},
284 {T("system"), 0},
285 {T("vendor"), 0}};
286 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
287
288 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
289 << "Should not be able to fit 11GiB data into 10GiB space";
290}
291
292TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
293 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
294 {S("vendor"), 1_GiB},
295 {T("system"), 0},
296 {T("vendor"), 0}};
297 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
298 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
299 << "Should not be able to grow over size of super / 2";
300}
301
Yifan Hong3a1a5612019-11-05 16:34:32 -0800302TEST_P(DynamicPartitionControlAndroidTestP,
303 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
304 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
305 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
306 // Static partition {system,bar}_{a,b} exists.
307 EXPECT_CALL(dynamicControl(),
308 DeviceExists(AnyOf(GetDevice(S("bar")),
309 GetDevice(T("bar")),
310 GetDevice(S("system")),
311 GetDevice(T("system")))))
312 .WillRepeatedly(Return(true));
313
314 SetMetadata(source(),
315 {{S("system"), 2_GiB},
316 {S("vendor"), 1_GiB},
317 {T("system"), 2_GiB},
318 {T("vendor"), 1_GiB}});
319
320 // Not calling through
321 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
322 // don't want any default group in the PartitionMetadata.
323 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800324 source(), target(), {}, true, nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800325
326 // Should use dynamic source partitions.
327 EXPECT_CALL(dynamicControl(), GetState(S("system")))
328 .Times(1)
329 .WillOnce(Return(DmDeviceState::ACTIVE));
330 string system_device;
331 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
332 "system", source(), source(), &system_device));
333 EXPECT_EQ(GetDmDevice(S("system")), system_device);
334
335 // Should use static target partitions without querying dynamic control.
336 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
337 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
338 "system", target(), source(), &system_device));
339 EXPECT_EQ(GetDevice(T("system")), system_device);
340
341 // Static partition "bar".
342 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
343 std::string bar_device;
344 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
345 "bar", source(), source(), &bar_device));
346 EXPECT_EQ(GetDevice(S("bar")), bar_device);
347
348 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
349 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
350 "bar", target(), source(), &bar_device));
351 EXPECT_EQ(GetDevice(T("bar")), bar_device);
352}
353
354TEST_P(DynamicPartitionControlAndroidTestP,
355 GetPartitionDeviceWhenResumingUpdate) {
356 // Static partition bar_{a,b} exists.
357 EXPECT_CALL(dynamicControl(),
358 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
359 .WillRepeatedly(Return(true));
360
361 // Both of the two slots contain valid partition metadata, since this is
362 // resuming an update.
363 SetMetadata(source(),
364 {{S("system"), 2_GiB},
365 {S("vendor"), 1_GiB},
366 {T("system"), 2_GiB},
367 {T("vendor"), 1_GiB}});
368 SetMetadata(target(),
369 {{S("system"), 2_GiB},
370 {S("vendor"), 1_GiB},
371 {T("system"), 2_GiB},
372 {T("vendor"), 1_GiB}});
373
374 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
375 source(),
376 target(),
377 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
Yifan Hongf033ecb2020-01-07 18:13:56 -0800378 false,
379 nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800380
381 // Dynamic partition "system".
382 EXPECT_CALL(dynamicControl(), GetState(S("system")))
383 .Times(1)
384 .WillOnce(Return(DmDeviceState::ACTIVE));
385 string system_device;
386 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
387 "system", source(), source(), &system_device));
388 EXPECT_EQ(GetDmDevice(S("system")), system_device);
389
390 EXPECT_CALL(dynamicControl(), GetState(T("system")))
391 .Times(AnyNumber())
392 .WillOnce(Return(DmDeviceState::ACTIVE));
393 EXPECT_CALL(dynamicControl(),
394 MapPartitionOnDeviceMapper(
395 GetSuperDevice(target()), T("system"), target(), _, _))
396 .Times(AnyNumber())
397 .WillRepeatedly(
398 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
399 *device = "/fake/remapped/" + name;
400 return true;
401 }));
402 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
403 "system", target(), source(), &system_device));
404 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
405
406 // Static partition "bar".
407 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
408 std::string bar_device;
409 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
410 "bar", source(), source(), &bar_device));
411 EXPECT_EQ(GetDevice(S("bar")), bar_device);
412
413 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
414 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
415 "bar", target(), source(), &bar_device));
416 EXPECT_EQ(GetDevice(T("bar")), bar_device);
417}
418
Yifan Hongc049f932019-07-23 15:06:05 -0700419INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
420 DynamicPartitionControlAndroidTestP,
421 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
422
423class DynamicPartitionControlAndroidGroupTestP
424 : public DynamicPartitionControlAndroidTestP {
425 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700426 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700427 void SetUp() override {
428 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700429 AddGroupAndPartition(
430 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
431 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
432 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
433 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700434 }
435
Yifan Hong13d41cb2019-09-16 13:18:22 -0700436 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
437 const string& group,
438 uint64_t group_size,
439 const string& partition,
440 uint64_t partition_size) {
441 auto* g = AddGroup(manifest, group, group_size);
442 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700443 }
444};
445
446// Allow to resize within group.
447TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700448 DeltaArchiveManifest expected;
449 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
450 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700451
Yifan Hong13d41cb2019-09-16 13:18:22 -0700452 DeltaArchiveManifest update_manifest;
453 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
454 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700455
456 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700457 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700458}
459
460TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700461 DeltaArchiveManifest update_manifest;
462 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
463 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
464 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700465 << "Should not be able to grow over maximum size of group";
466}
467
468TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700469 DeltaArchiveManifest update_manifest;
470 AddGroup(&update_manifest, "android", 3_GiB);
471 AddGroup(&update_manifest, "oem", 3_GiB);
472 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700473 << "Should not be able to grow over size of super / 2";
474}
475
476TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700477 DeltaArchiveManifest expected;
478 auto* g = AddGroup(&expected, T("android"), 3_GiB);
479 AddPartition(&expected, g, T("system"), 2_GiB);
480 AddPartition(&expected, g, T("system_ext"), 1_GiB);
481
482 DeltaArchiveManifest update_manifest;
483 g = AddGroup(&update_manifest, "android", 3_GiB);
484 AddPartition(&update_manifest, g, "system", 2_GiB);
485 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
486 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
487
Yifan Hongc049f932019-07-23 15:06:05 -0700488 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700489 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700490}
491
492TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700493 DeltaArchiveManifest expected;
494 AddGroup(&expected, T("android"), 3_GiB);
495
496 DeltaArchiveManifest update_manifest;
497 AddGroup(&update_manifest, "android", 3_GiB);
498 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
499
Yifan Hongc049f932019-07-23 15:06:05 -0700500 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700501 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700502}
503
504TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700505 DeltaArchiveManifest expected;
506 AddGroupAndPartition(
507 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
508
509 DeltaArchiveManifest update_manifest;
510 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
511 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
512 AddGroupAndPartition(
513 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700514 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700515 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700516}
517
518TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700519 DeltaArchiveManifest update_manifest;
520 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700521
522 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700523 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700524}
525
526TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700527 DeltaArchiveManifest expected;
528 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
529 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
530 DeltaArchiveManifest update_manifest;
531 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
532 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700533 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700534 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700535}
536
537INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
538 DynamicPartitionControlAndroidGroupTestP,
539 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
540
541const PartitionSuffixSizes update_sizes_0() {
542 // Initial state is 0 for "other" slot.
543 return {
544 {"grown_a", 2_GiB},
545 {"shrunk_a", 1_GiB},
546 {"same_a", 100_MiB},
547 {"deleted_a", 150_MiB},
548 // no added_a
549 {"grown_b", 200_MiB},
550 // simulate system_other
551 {"shrunk_b", 0},
552 {"same_b", 0},
553 {"deleted_b", 0},
554 // no added_b
555 };
556}
557
558const PartitionSuffixSizes update_sizes_1() {
559 return {
560 {"grown_a", 2_GiB},
561 {"shrunk_a", 1_GiB},
562 {"same_a", 100_MiB},
563 {"deleted_a", 150_MiB},
564 // no added_a
565 {"grown_b", 3_GiB},
566 {"shrunk_b", 150_MiB},
567 {"same_b", 100_MiB},
568 {"added_b", 150_MiB},
569 // no deleted_b
570 };
571}
572
573const PartitionSuffixSizes update_sizes_2() {
574 return {
575 {"grown_a", 4_GiB},
576 {"shrunk_a", 100_MiB},
577 {"same_a", 100_MiB},
578 {"deleted_a", 64_MiB},
579 // no added_a
580 {"grown_b", 3_GiB},
581 {"shrunk_b", 150_MiB},
582 {"same_b", 100_MiB},
583 {"added_b", 150_MiB},
584 // no deleted_b
585 };
586}
587
588// Test case for first update after the device is manufactured, in which
589// case the "other" slot is likely of size "0" (except system, which is
590// non-zero because of system_other partition)
591TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
592 SetSlots({0, 1});
593
594 SetMetadata(source(), update_sizes_0());
595 SetMetadata(target(), update_sizes_0());
596 ExpectStoreMetadata(update_sizes_1());
597 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
598
599 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
600 {"shrunk", 150_MiB},
601 {"same", 100_MiB},
602 {"added", 150_MiB}}));
603}
604
605// After first update, test for the second update. In the second update, the
606// "added" partition is deleted and "deleted" partition is re-added.
607TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
608 SetSlots({1, 0});
609
610 SetMetadata(source(), update_sizes_1());
611 SetMetadata(target(), update_sizes_0());
612
613 ExpectStoreMetadata(update_sizes_2());
614 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
615
616 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
617 {"shrunk", 100_MiB},
618 {"same", 100_MiB},
619 {"deleted", 64_MiB}}));
620}
621
Yifan Hong3a1a5612019-11-05 16:34:32 -0800622TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
623 SetSlots({1, 1});
624 EXPECT_FALSE(PreparePartitionsForUpdate({}))
625 << "Should not be able to apply to current slot.";
626}
627
Yifan Hong6eec9952019-12-04 13:12:01 -0800628TEST_P(DynamicPartitionControlAndroidTestP, ShouldSkipOperationTest) {
629 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800630 source(),
631 target(),
632 PartitionSizesToManifest({{"foo", 4_MiB}}),
633 false,
634 nullptr));
Yifan Hong6eec9952019-12-04 13:12:01 -0800635 dynamicControl().set_fake_mapped_devices({T("foo")});
636
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000637 InstallOperation iop;
638 Extent *se, *de;
639
640 // Not a SOURCE_COPY operation, cannot skip.
641 iop.set_type(InstallOperation::REPLACE);
Yifan Hong6eec9952019-12-04 13:12:01 -0800642 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000643
644 iop.set_type(InstallOperation::SOURCE_COPY);
645
646 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
Yifan Hong6eec9952019-12-04 13:12:01 -0800647 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000648
649 // Enable GetVirtualAbFeatureFlag in the mock interface.
650 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
651 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
652
653 // By default target_supports_snapshot_ is set to false. Cannot skip
654 // operation.
Yifan Hong6eec9952019-12-04 13:12:01 -0800655 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000656
657 SetSnapshotEnabled(true);
658
659 // Empty source and destination. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800660 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000661
662 se = iop.add_src_extents();
663 se->set_start_block(0);
664 se->set_num_blocks(1);
665
666 // There is something in sources, but destinations are empty. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800667 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000668
669 InstallOperation iop2;
670
671 de = iop2.add_dst_extents();
672 de->set_start_block(0);
673 de->set_num_blocks(1);
674
675 // There is something in destinations, but sources are empty. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800676 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop2));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000677
678 de = iop.add_dst_extents();
679 de->set_start_block(0);
680 de->set_num_blocks(1);
681
682 // Sources and destinations are identical. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800683 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000684
685 se = iop.add_src_extents();
686 se->set_start_block(1);
687 se->set_num_blocks(5);
688
689 // There is something in source, but not in destination. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800690 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000691
692 de = iop.add_dst_extents();
693 de->set_start_block(1);
694 de->set_num_blocks(5);
695
696 // There is source and destination are equal. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800697 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000698
699 de = iop.add_dst_extents();
700 de->set_start_block(6);
701 de->set_num_blocks(5);
702
703 // There is something extra in dest. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800704 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000705
706 se = iop.add_src_extents();
707 se->set_start_block(6);
708 se->set_num_blocks(5);
709
710 // Source and dest are identical again. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800711 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
712
713 // Don't skip for static partitions.
714 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("bar", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000715}
716
Yifan Hongc049f932019-07-23 15:06:05 -0700717} // namespace chromeos_update_engine