blob: 457ea10862f0a5b6f14d06904d5b2fcf9cf5c9fe [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
Yifan Hong6a6d0f12020-03-11 13:20:52 -070027#include "update_engine/common/mock_prefs.h"
Yifan Hongc049f932019-07-23 15:06:05 -070028#include "update_engine/dynamic_partition_test_utils.h"
29#include "update_engine/mock_dynamic_partition_control.h"
30
Yifan Hong3a1a5612019-11-05 16:34:32 -080031using android::dm::DmDeviceState;
Yifan Hongc049f932019-07-23 15:06:05 -070032using std::string;
33using testing::_;
34using testing::AnyNumber;
Yifan Hong3a1a5612019-11-05 16:34:32 -080035using testing::AnyOf;
Yifan Hongc049f932019-07-23 15:06:05 -070036using testing::Invoke;
37using testing::NiceMock;
38using testing::Not;
39using testing::Return;
40
41namespace chromeos_update_engine {
42
43class DynamicPartitionControlAndroidTest : public ::testing::Test {
44 public:
45 void SetUp() override {
46 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
47
48 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
49 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
Yifan Hong413d5722019-07-23 14:21:09 -070050 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
51 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
Yifan Hongc049f932019-07-23 15:06:05 -070052
53 ON_CALL(dynamicControl(), GetDeviceDir(_))
54 .WillByDefault(Invoke([](auto path) {
55 *path = kFakeDevicePath;
56 return true;
57 }));
Yifan Hong700d7c12019-07-23 20:49:16 -070058
59 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
60 .WillByDefault(Return(kFakeSuper));
Yifan Hong3a1a5612019-11-05 16:34:32 -080061
62 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
63 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
64 *device = GetDmDevice(partition_name_suffix);
65 return true;
66 }));
Yifan Hongc049f932019-07-23 15:06:05 -070067 }
68
69 // Return the mocked DynamicPartitionControlInterface.
70 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
71 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
72 }
73
Yifan Hong700d7c12019-07-23 20:49:16 -070074 std::string GetSuperDevice(uint32_t slot) {
75 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
76 }
77
Yifan Hongc049f932019-07-23 15:06:05 -070078 uint32_t source() { return slots_.source; }
79 uint32_t target() { return slots_.target; }
80
81 // Return partition names with suffix of source().
82 std::string S(const std::string& name) {
83 return name + kSlotSuffixes[source()];
84 }
85
86 // Return partition names with suffix of target().
87 std::string T(const std::string& name) {
88 return name + kSlotSuffixes[target()];
89 }
90
91 // Set the fake metadata to return when LoadMetadataBuilder is called on
92 // |slot|.
93 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
94 EXPECT_CALL(dynamicControl(),
95 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
96 .Times(AnyNumber())
97 .WillRepeatedly(Invoke([sizes](auto, auto, auto) {
Yifan Hong13d41cb2019-09-16 13:18:22 -070098 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
Yifan Hongc049f932019-07-23 15:06:05 -070099 }));
100 }
101
102 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
103 EXPECT_CALL(dynamicControl(),
104 StoreMetadata(GetSuperDevice(target()),
105 MetadataMatches(partition_sizes),
106 target()))
107 .WillOnce(Return(true));
108 }
109
110 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
111 // slot with each partition in |partitions|.
112 void ExpectUnmap(const std::set<std::string>& partitions) {
113 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
114 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
115 .WillByDefault(Return(false));
116
117 for (const auto& partition : partitions) {
118 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
119 .WillOnce(Return(true));
120 }
121 }
122 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
123 return dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800124 source(),
125 target(),
126 PartitionSizesToManifest(partition_sizes),
127 true,
128 nullptr);
Yifan Hongc049f932019-07-23 15:06:05 -0700129 }
130 void SetSlots(const TestParam& slots) { slots_ = slots; }
131
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000132 void SetSnapshotEnabled(bool enabled) {
133 dynamicControl().target_supports_snapshot_ = enabled;
134 }
135
Yifan Hongc049f932019-07-23 15:06:05 -0700136 struct Listener : public ::testing::MatchResultListener {
137 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
138 };
139
140 testing::AssertionResult UpdatePartitionMetadata(
141 const PartitionSuffixSizes& source_metadata,
142 const PartitionSizes& update_metadata,
143 const PartitionSuffixSizes& expected) {
144 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700145 PartitionSuffixSizesToManifest(source_metadata),
146 PartitionSizesToManifest(update_metadata),
147 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700148 }
149 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700150 const DeltaArchiveManifest& source_manifest,
151 const DeltaArchiveManifest& update_manifest,
152 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700153 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700154 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700155 }
156 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700157 const DeltaArchiveManifest& source_manifest,
158 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700159 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700160 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700161 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700162 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700163 return testing::AssertionFailure()
164 << "UpdatePartitionMetadataInternal failed";
165 }
166 std::stringstream ss;
167 Listener listener(&ss);
168 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
169 return testing::AssertionSuccess() << ss.str();
170 } else {
171 return testing::AssertionFailure() << ss.str();
172 }
173 }
174
175 std::unique_ptr<DynamicPartitionControlAndroid> module_;
176 TestParam slots_;
177};
178
179class DynamicPartitionControlAndroidTestP
180 : public DynamicPartitionControlAndroidTest,
181 public ::testing::WithParamInterface<TestParam> {
182 public:
183 void SetUp() override {
184 DynamicPartitionControlAndroidTest::SetUp();
185 SetSlots(GetParam());
186 }
187};
188
189// Test resize case. Grow if target metadata contains a partition with a size
190// less than expected.
191TEST_P(DynamicPartitionControlAndroidTestP,
192 NeedGrowIfSizeNotMatchWhenResizing) {
193 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
194 {S("vendor"), 1_GiB},
195 {T("system"), 2_GiB},
196 {T("vendor"), 1_GiB}};
197 PartitionSuffixSizes expected{{S("system"), 2_GiB},
198 {S("vendor"), 1_GiB},
199 {T("system"), 3_GiB},
200 {T("vendor"), 1_GiB}};
201 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
202 EXPECT_TRUE(
203 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
204}
205
206// Test resize case. Shrink if target metadata contains a partition with a size
207// greater than expected.
208TEST_P(DynamicPartitionControlAndroidTestP,
209 NeedShrinkIfSizeNotMatchWhenResizing) {
210 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
211 {S("vendor"), 1_GiB},
212 {T("system"), 2_GiB},
213 {T("vendor"), 1_GiB}};
214 PartitionSuffixSizes expected{{S("system"), 2_GiB},
215 {S("vendor"), 1_GiB},
216 {T("system"), 2_GiB},
217 {T("vendor"), 150_MiB}};
218 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
219 EXPECT_TRUE(
220 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
221}
222
223// Test adding partitions on the first run.
224TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
225 PartitionSuffixSizes source_metadata{};
226 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
227 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
228 EXPECT_TRUE(
229 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
230}
231
232// Test subsequent add case.
233TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
234 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
235 {T("system"), 2_GiB}};
236 PartitionSuffixSizes expected{
237 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
238 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
239 EXPECT_TRUE(
240 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
241}
242
243// Test delete one partition.
244TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
245 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
246 {S("vendor"), 1_GiB},
247 {T("system"), 2_GiB},
248 {T("vendor"), 1_GiB}};
249 // No T("vendor")
250 PartitionSuffixSizes expected{
251 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
252 PartitionSizes update_metadata{{"system", 2_GiB}};
253 EXPECT_TRUE(
254 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
255}
256
257// Test delete all partitions.
258TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
259 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
260 {S("vendor"), 1_GiB},
261 {T("system"), 2_GiB},
262 {T("vendor"), 1_GiB}};
263 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
264 PartitionSizes update_metadata{};
265 EXPECT_TRUE(
266 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
267}
268
269// Test corrupt source metadata case.
270TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
271 EXPECT_CALL(dynamicControl(),
272 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
273 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
274 ExpectUnmap({T("system")});
275
276 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
277 << "Should not be able to continue with corrupt source metadata";
278}
279
280// Test that UpdatePartitionMetadata fails if there is not enough space on the
281// device.
282TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
283 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
284 {S("vendor"), 2_GiB},
285 {T("system"), 0},
286 {T("vendor"), 0}};
287 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
288
289 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
290 << "Should not be able to fit 11GiB data into 10GiB space";
291}
292
293TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
294 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
295 {S("vendor"), 1_GiB},
296 {T("system"), 0},
297 {T("vendor"), 0}};
298 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
299 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
300 << "Should not be able to grow over size of super / 2";
301}
302
Yifan Hong3a1a5612019-11-05 16:34:32 -0800303TEST_P(DynamicPartitionControlAndroidTestP,
304 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
305 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
306 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
307 // Static partition {system,bar}_{a,b} exists.
308 EXPECT_CALL(dynamicControl(),
309 DeviceExists(AnyOf(GetDevice(S("bar")),
310 GetDevice(T("bar")),
311 GetDevice(S("system")),
312 GetDevice(T("system")))))
313 .WillRepeatedly(Return(true));
314
315 SetMetadata(source(),
316 {{S("system"), 2_GiB},
317 {S("vendor"), 1_GiB},
318 {T("system"), 2_GiB},
319 {T("vendor"), 1_GiB}});
320
321 // Not calling through
322 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
323 // don't want any default group in the PartitionMetadata.
324 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800325 source(), target(), {}, true, nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800326
327 // Should use dynamic source partitions.
328 EXPECT_CALL(dynamicControl(), GetState(S("system")))
329 .Times(1)
330 .WillOnce(Return(DmDeviceState::ACTIVE));
331 string system_device;
332 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
333 "system", source(), source(), &system_device));
334 EXPECT_EQ(GetDmDevice(S("system")), system_device);
335
336 // Should use static target partitions without querying dynamic control.
337 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
338 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
339 "system", target(), source(), &system_device));
340 EXPECT_EQ(GetDevice(T("system")), system_device);
341
342 // Static partition "bar".
343 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
344 std::string bar_device;
345 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
346 "bar", source(), source(), &bar_device));
347 EXPECT_EQ(GetDevice(S("bar")), bar_device);
348
349 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
350 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
351 "bar", target(), source(), &bar_device));
352 EXPECT_EQ(GetDevice(T("bar")), bar_device);
353}
354
355TEST_P(DynamicPartitionControlAndroidTestP,
356 GetPartitionDeviceWhenResumingUpdate) {
357 // Static partition bar_{a,b} exists.
358 EXPECT_CALL(dynamicControl(),
359 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
360 .WillRepeatedly(Return(true));
361
362 // Both of the two slots contain valid partition metadata, since this is
363 // resuming an update.
364 SetMetadata(source(),
365 {{S("system"), 2_GiB},
366 {S("vendor"), 1_GiB},
367 {T("system"), 2_GiB},
368 {T("vendor"), 1_GiB}});
369 SetMetadata(target(),
370 {{S("system"), 2_GiB},
371 {S("vendor"), 1_GiB},
372 {T("system"), 2_GiB},
373 {T("vendor"), 1_GiB}});
374
375 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
376 source(),
377 target(),
378 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
Yifan Hongf033ecb2020-01-07 18:13:56 -0800379 false,
380 nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800381
382 // Dynamic partition "system".
383 EXPECT_CALL(dynamicControl(), GetState(S("system")))
384 .Times(1)
385 .WillOnce(Return(DmDeviceState::ACTIVE));
386 string system_device;
387 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
388 "system", source(), source(), &system_device));
389 EXPECT_EQ(GetDmDevice(S("system")), system_device);
390
391 EXPECT_CALL(dynamicControl(), GetState(T("system")))
392 .Times(AnyNumber())
393 .WillOnce(Return(DmDeviceState::ACTIVE));
394 EXPECT_CALL(dynamicControl(),
395 MapPartitionOnDeviceMapper(
396 GetSuperDevice(target()), T("system"), target(), _, _))
397 .Times(AnyNumber())
398 .WillRepeatedly(
399 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
400 *device = "/fake/remapped/" + name;
401 return true;
402 }));
403 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
404 "system", target(), source(), &system_device));
405 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
406
407 // Static partition "bar".
408 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
409 std::string bar_device;
410 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
411 "bar", source(), source(), &bar_device));
412 EXPECT_EQ(GetDevice(S("bar")), bar_device);
413
414 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
415 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
416 "bar", target(), source(), &bar_device));
417 EXPECT_EQ(GetDevice(T("bar")), bar_device);
418}
419
Yifan Hongc049f932019-07-23 15:06:05 -0700420INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
421 DynamicPartitionControlAndroidTestP,
422 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
423
424class DynamicPartitionControlAndroidGroupTestP
425 : public DynamicPartitionControlAndroidTestP {
426 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700427 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700428 void SetUp() override {
429 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700430 AddGroupAndPartition(
431 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
432 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
433 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
434 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700435 }
436
Yifan Hong13d41cb2019-09-16 13:18:22 -0700437 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
438 const string& group,
439 uint64_t group_size,
440 const string& partition,
441 uint64_t partition_size) {
442 auto* g = AddGroup(manifest, group, group_size);
443 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700444 }
445};
446
447// Allow to resize within group.
448TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700449 DeltaArchiveManifest expected;
450 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
451 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700452
Yifan Hong13d41cb2019-09-16 13:18:22 -0700453 DeltaArchiveManifest update_manifest;
454 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
455 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700456
457 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700458 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700459}
460
461TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700462 DeltaArchiveManifest update_manifest;
463 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
464 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
465 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700466 << "Should not be able to grow over maximum size of group";
467}
468
469TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700470 DeltaArchiveManifest update_manifest;
471 AddGroup(&update_manifest, "android", 3_GiB);
472 AddGroup(&update_manifest, "oem", 3_GiB);
473 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700474 << "Should not be able to grow over size of super / 2";
475}
476
477TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700478 DeltaArchiveManifest expected;
479 auto* g = AddGroup(&expected, T("android"), 3_GiB);
480 AddPartition(&expected, g, T("system"), 2_GiB);
481 AddPartition(&expected, g, T("system_ext"), 1_GiB);
482
483 DeltaArchiveManifest update_manifest;
484 g = AddGroup(&update_manifest, "android", 3_GiB);
485 AddPartition(&update_manifest, g, "system", 2_GiB);
486 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
487 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
488
Yifan Hongc049f932019-07-23 15:06:05 -0700489 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700490 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700491}
492
493TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700494 DeltaArchiveManifest expected;
495 AddGroup(&expected, T("android"), 3_GiB);
496
497 DeltaArchiveManifest update_manifest;
498 AddGroup(&update_manifest, "android", 3_GiB);
499 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
500
Yifan Hongc049f932019-07-23 15:06:05 -0700501 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700502 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700503}
504
505TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700506 DeltaArchiveManifest expected;
507 AddGroupAndPartition(
508 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
509
510 DeltaArchiveManifest update_manifest;
511 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
512 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
513 AddGroupAndPartition(
514 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700515 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700516 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700517}
518
519TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700520 DeltaArchiveManifest update_manifest;
521 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700522
523 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700524 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700525}
526
527TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700528 DeltaArchiveManifest expected;
529 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
530 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
531 DeltaArchiveManifest update_manifest;
532 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
533 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700534 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700535 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700536}
537
538INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
539 DynamicPartitionControlAndroidGroupTestP,
540 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
541
542const PartitionSuffixSizes update_sizes_0() {
543 // Initial state is 0 for "other" slot.
544 return {
545 {"grown_a", 2_GiB},
546 {"shrunk_a", 1_GiB},
547 {"same_a", 100_MiB},
548 {"deleted_a", 150_MiB},
549 // no added_a
550 {"grown_b", 200_MiB},
551 // simulate system_other
552 {"shrunk_b", 0},
553 {"same_b", 0},
554 {"deleted_b", 0},
555 // no added_b
556 };
557}
558
559const PartitionSuffixSizes update_sizes_1() {
560 return {
561 {"grown_a", 2_GiB},
562 {"shrunk_a", 1_GiB},
563 {"same_a", 100_MiB},
564 {"deleted_a", 150_MiB},
565 // no added_a
566 {"grown_b", 3_GiB},
567 {"shrunk_b", 150_MiB},
568 {"same_b", 100_MiB},
569 {"added_b", 150_MiB},
570 // no deleted_b
571 };
572}
573
574const PartitionSuffixSizes update_sizes_2() {
575 return {
576 {"grown_a", 4_GiB},
577 {"shrunk_a", 100_MiB},
578 {"same_a", 100_MiB},
579 {"deleted_a", 64_MiB},
580 // no added_a
581 {"grown_b", 3_GiB},
582 {"shrunk_b", 150_MiB},
583 {"same_b", 100_MiB},
584 {"added_b", 150_MiB},
585 // no deleted_b
586 };
587}
588
589// Test case for first update after the device is manufactured, in which
590// case the "other" slot is likely of size "0" (except system, which is
591// non-zero because of system_other partition)
592TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
593 SetSlots({0, 1});
594
595 SetMetadata(source(), update_sizes_0());
596 SetMetadata(target(), update_sizes_0());
597 ExpectStoreMetadata(update_sizes_1());
598 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
599
600 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
601 {"shrunk", 150_MiB},
602 {"same", 100_MiB},
603 {"added", 150_MiB}}));
604}
605
606// After first update, test for the second update. In the second update, the
607// "added" partition is deleted and "deleted" partition is re-added.
608TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
609 SetSlots({1, 0});
610
611 SetMetadata(source(), update_sizes_1());
612 SetMetadata(target(), update_sizes_0());
613
614 ExpectStoreMetadata(update_sizes_2());
615 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
616
617 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
618 {"shrunk", 100_MiB},
619 {"same", 100_MiB},
620 {"deleted", 64_MiB}}));
621}
622
Yifan Hong3a1a5612019-11-05 16:34:32 -0800623TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
624 SetSlots({1, 1});
625 EXPECT_FALSE(PreparePartitionsForUpdate({}))
626 << "Should not be able to apply to current slot.";
627}
628
Yifan Hongf5261562020-03-10 10:28:10 -0700629TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
Yifan Hong6eec9952019-12-04 13:12:01 -0800630 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800631 source(),
632 target(),
633 PartitionSizesToManifest({{"foo", 4_MiB}}),
634 false,
635 nullptr));
Yifan Hong6eec9952019-12-04 13:12:01 -0800636 dynamicControl().set_fake_mapped_devices({T("foo")});
637
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000638 InstallOperation iop;
Yifan Hongf5261562020-03-10 10:28:10 -0700639 InstallOperation optimized;
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000640 Extent *se, *de;
641
642 // Not a SOURCE_COPY operation, cannot skip.
643 iop.set_type(InstallOperation::REPLACE);
Yifan Hongf5261562020-03-10 10:28:10 -0700644 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000645
646 iop.set_type(InstallOperation::SOURCE_COPY);
647
648 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700649 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000650
651 // Enable GetVirtualAbFeatureFlag in the mock interface.
652 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
653 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
654
655 // By default target_supports_snapshot_ is set to false. Cannot skip
656 // operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700657 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000658
659 SetSnapshotEnabled(true);
660
661 // Empty source and destination. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700662 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
663 EXPECT_TRUE(optimized.src_extents().empty());
664 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000665
666 se = iop.add_src_extents();
667 se->set_start_block(0);
668 se->set_num_blocks(1);
669
670 // There is something in sources, but destinations are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700671 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000672
673 InstallOperation iop2;
674
675 de = iop2.add_dst_extents();
676 de->set_start_block(0);
677 de->set_num_blocks(1);
678
679 // There is something in destinations, but sources are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700680 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000681
682 de = iop.add_dst_extents();
683 de->set_start_block(0);
684 de->set_num_blocks(1);
685
686 // Sources and destinations are identical. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700687 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
688 EXPECT_TRUE(optimized.src_extents().empty());
689 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000690
691 se = iop.add_src_extents();
692 se->set_start_block(1);
693 se->set_num_blocks(5);
694
695 // There is something in source, but not in destination. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700696 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000697
698 de = iop.add_dst_extents();
699 de->set_start_block(1);
700 de->set_num_blocks(5);
701
702 // There is source and destination are equal. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700703 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
704 EXPECT_TRUE(optimized.src_extents().empty());
705 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000706
707 de = iop.add_dst_extents();
708 de->set_start_block(6);
709 de->set_num_blocks(5);
710
711 // There is something extra in dest. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700712 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000713
714 se = iop.add_src_extents();
715 se->set_start_block(6);
716 se->set_num_blocks(5);
717
718 // Source and dest are identical again. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700719 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
720 EXPECT_TRUE(optimized.src_extents().empty());
721 EXPECT_TRUE(optimized.dst_extents().empty());
722
723 iop.Clear();
724 iop.set_type(InstallOperation::SOURCE_COPY);
725 se = iop.add_src_extents();
726 se->set_start_block(1);
727 se->set_num_blocks(1);
728 se = iop.add_src_extents();
729 se->set_start_block(3);
730 se->set_num_blocks(2);
731 se = iop.add_src_extents();
732 se->set_start_block(7);
733 se->set_num_blocks(2);
734 de = iop.add_dst_extents();
735 de->set_start_block(2);
736 de->set_num_blocks(5);
737
738 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
739 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
740 ASSERT_EQ(2, optimized.src_extents_size());
741 ASSERT_EQ(2, optimized.dst_extents_size());
742 EXPECT_EQ(1u, optimized.src_extents(0).start_block());
743 EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
744 EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
745 EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
746 EXPECT_EQ(7u, optimized.src_extents(1).start_block());
747 EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
748 EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
749 EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
Yifan Hong6eec9952019-12-04 13:12:01 -0800750
751 // Don't skip for static partitions.
Yifan Hongf5261562020-03-10 10:28:10 -0700752 EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000753}
754
Yifan Hong6a6d0f12020-03-11 13:20:52 -0700755TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
756 MockPrefs prefs;
757 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
758}
759
Yifan Hongc049f932019-07-23 15:06:05 -0700760} // namespace chromeos_update_engine