blob: 207a97e02c29521b275ab066ba451f19a914768b [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 Hongf0f4a912019-09-26 17:51:33 -0700123 source(), target(), PartitionSizesToManifest(partition_sizes), true);
Yifan Hongc049f932019-07-23 15:06:05 -0700124 }
125 void SetSlots(const TestParam& slots) { slots_ = slots; }
126
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000127 void SetSnapshotEnabled(bool enabled) {
128 dynamicControl().target_supports_snapshot_ = enabled;
129 }
130
Yifan Hongc049f932019-07-23 15:06:05 -0700131 struct Listener : public ::testing::MatchResultListener {
132 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
133 };
134
135 testing::AssertionResult UpdatePartitionMetadata(
136 const PartitionSuffixSizes& source_metadata,
137 const PartitionSizes& update_metadata,
138 const PartitionSuffixSizes& expected) {
139 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700140 PartitionSuffixSizesToManifest(source_metadata),
141 PartitionSizesToManifest(update_metadata),
142 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700143 }
144 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700145 const DeltaArchiveManifest& source_manifest,
146 const DeltaArchiveManifest& update_manifest,
147 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700148 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700149 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700150 }
151 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700152 const DeltaArchiveManifest& source_manifest,
153 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700154 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700155 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700156 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700157 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700158 return testing::AssertionFailure()
159 << "UpdatePartitionMetadataInternal failed";
160 }
161 std::stringstream ss;
162 Listener listener(&ss);
163 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
164 return testing::AssertionSuccess() << ss.str();
165 } else {
166 return testing::AssertionFailure() << ss.str();
167 }
168 }
169
170 std::unique_ptr<DynamicPartitionControlAndroid> module_;
171 TestParam slots_;
172};
173
174class DynamicPartitionControlAndroidTestP
175 : public DynamicPartitionControlAndroidTest,
176 public ::testing::WithParamInterface<TestParam> {
177 public:
178 void SetUp() override {
179 DynamicPartitionControlAndroidTest::SetUp();
180 SetSlots(GetParam());
181 }
182};
183
184// Test resize case. Grow if target metadata contains a partition with a size
185// less than expected.
186TEST_P(DynamicPartitionControlAndroidTestP,
187 NeedGrowIfSizeNotMatchWhenResizing) {
188 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
189 {S("vendor"), 1_GiB},
190 {T("system"), 2_GiB},
191 {T("vendor"), 1_GiB}};
192 PartitionSuffixSizes expected{{S("system"), 2_GiB},
193 {S("vendor"), 1_GiB},
194 {T("system"), 3_GiB},
195 {T("vendor"), 1_GiB}};
196 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
197 EXPECT_TRUE(
198 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
199}
200
201// Test resize case. Shrink if target metadata contains a partition with a size
202// greater than expected.
203TEST_P(DynamicPartitionControlAndroidTestP,
204 NeedShrinkIfSizeNotMatchWhenResizing) {
205 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
206 {S("vendor"), 1_GiB},
207 {T("system"), 2_GiB},
208 {T("vendor"), 1_GiB}};
209 PartitionSuffixSizes expected{{S("system"), 2_GiB},
210 {S("vendor"), 1_GiB},
211 {T("system"), 2_GiB},
212 {T("vendor"), 150_MiB}};
213 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
214 EXPECT_TRUE(
215 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
216}
217
218// Test adding partitions on the first run.
219TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
220 PartitionSuffixSizes source_metadata{};
221 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
222 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
223 EXPECT_TRUE(
224 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
225}
226
227// Test subsequent add case.
228TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
229 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
230 {T("system"), 2_GiB}};
231 PartitionSuffixSizes expected{
232 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
233 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
234 EXPECT_TRUE(
235 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
236}
237
238// Test delete one partition.
239TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
240 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
241 {S("vendor"), 1_GiB},
242 {T("system"), 2_GiB},
243 {T("vendor"), 1_GiB}};
244 // No T("vendor")
245 PartitionSuffixSizes expected{
246 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
247 PartitionSizes update_metadata{{"system", 2_GiB}};
248 EXPECT_TRUE(
249 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
250}
251
252// Test delete all partitions.
253TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
254 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
255 {S("vendor"), 1_GiB},
256 {T("system"), 2_GiB},
257 {T("vendor"), 1_GiB}};
258 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
259 PartitionSizes update_metadata{};
260 EXPECT_TRUE(
261 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
262}
263
264// Test corrupt source metadata case.
265TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
266 EXPECT_CALL(dynamicControl(),
267 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
268 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
269 ExpectUnmap({T("system")});
270
271 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
272 << "Should not be able to continue with corrupt source metadata";
273}
274
275// Test that UpdatePartitionMetadata fails if there is not enough space on the
276// device.
277TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
278 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
279 {S("vendor"), 2_GiB},
280 {T("system"), 0},
281 {T("vendor"), 0}};
282 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
283
284 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
285 << "Should not be able to fit 11GiB data into 10GiB space";
286}
287
288TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
289 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
290 {S("vendor"), 1_GiB},
291 {T("system"), 0},
292 {T("vendor"), 0}};
293 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
294 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
295 << "Should not be able to grow over size of super / 2";
296}
297
Yifan Hong3a1a5612019-11-05 16:34:32 -0800298TEST_P(DynamicPartitionControlAndroidTestP,
299 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
300 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
301 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
302 // Static partition {system,bar}_{a,b} exists.
303 EXPECT_CALL(dynamicControl(),
304 DeviceExists(AnyOf(GetDevice(S("bar")),
305 GetDevice(T("bar")),
306 GetDevice(S("system")),
307 GetDevice(T("system")))))
308 .WillRepeatedly(Return(true));
309
310 SetMetadata(source(),
311 {{S("system"), 2_GiB},
312 {S("vendor"), 1_GiB},
313 {T("system"), 2_GiB},
314 {T("vendor"), 1_GiB}});
315
316 // Not calling through
317 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
318 // don't want any default group in the PartitionMetadata.
319 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
320 source(), target(), {}, true));
321
322 // Should use dynamic source partitions.
323 EXPECT_CALL(dynamicControl(), GetState(S("system")))
324 .Times(1)
325 .WillOnce(Return(DmDeviceState::ACTIVE));
326 string system_device;
327 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
328 "system", source(), source(), &system_device));
329 EXPECT_EQ(GetDmDevice(S("system")), system_device);
330
331 // Should use static target partitions without querying dynamic control.
332 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
333 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
334 "system", target(), source(), &system_device));
335 EXPECT_EQ(GetDevice(T("system")), system_device);
336
337 // Static partition "bar".
338 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
339 std::string bar_device;
340 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
341 "bar", source(), source(), &bar_device));
342 EXPECT_EQ(GetDevice(S("bar")), bar_device);
343
344 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
345 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
346 "bar", target(), source(), &bar_device));
347 EXPECT_EQ(GetDevice(T("bar")), bar_device);
348}
349
350TEST_P(DynamicPartitionControlAndroidTestP,
351 GetPartitionDeviceWhenResumingUpdate) {
352 // Static partition bar_{a,b} exists.
353 EXPECT_CALL(dynamicControl(),
354 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
355 .WillRepeatedly(Return(true));
356
357 // Both of the two slots contain valid partition metadata, since this is
358 // resuming an update.
359 SetMetadata(source(),
360 {{S("system"), 2_GiB},
361 {S("vendor"), 1_GiB},
362 {T("system"), 2_GiB},
363 {T("vendor"), 1_GiB}});
364 SetMetadata(target(),
365 {{S("system"), 2_GiB},
366 {S("vendor"), 1_GiB},
367 {T("system"), 2_GiB},
368 {T("vendor"), 1_GiB}});
369
370 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
371 source(),
372 target(),
373 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
374 false));
375
376 // Dynamic partition "system".
377 EXPECT_CALL(dynamicControl(), GetState(S("system")))
378 .Times(1)
379 .WillOnce(Return(DmDeviceState::ACTIVE));
380 string system_device;
381 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
382 "system", source(), source(), &system_device));
383 EXPECT_EQ(GetDmDevice(S("system")), system_device);
384
385 EXPECT_CALL(dynamicControl(), GetState(T("system")))
386 .Times(AnyNumber())
387 .WillOnce(Return(DmDeviceState::ACTIVE));
388 EXPECT_CALL(dynamicControl(),
389 MapPartitionOnDeviceMapper(
390 GetSuperDevice(target()), T("system"), target(), _, _))
391 .Times(AnyNumber())
392 .WillRepeatedly(
393 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
394 *device = "/fake/remapped/" + name;
395 return true;
396 }));
397 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
398 "system", target(), source(), &system_device));
399 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
400
401 // Static partition "bar".
402 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
403 std::string bar_device;
404 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
405 "bar", source(), source(), &bar_device));
406 EXPECT_EQ(GetDevice(S("bar")), bar_device);
407
408 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
409 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
410 "bar", target(), source(), &bar_device));
411 EXPECT_EQ(GetDevice(T("bar")), bar_device);
412}
413
Yifan Hongc049f932019-07-23 15:06:05 -0700414INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
415 DynamicPartitionControlAndroidTestP,
416 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
417
418class DynamicPartitionControlAndroidGroupTestP
419 : public DynamicPartitionControlAndroidTestP {
420 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700421 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700422 void SetUp() override {
423 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700424 AddGroupAndPartition(
425 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
426 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
427 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
428 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700429 }
430
Yifan Hong13d41cb2019-09-16 13:18:22 -0700431 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
432 const string& group,
433 uint64_t group_size,
434 const string& partition,
435 uint64_t partition_size) {
436 auto* g = AddGroup(manifest, group, group_size);
437 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700438 }
439};
440
441// Allow to resize within group.
442TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700443 DeltaArchiveManifest expected;
444 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
445 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700446
Yifan Hong13d41cb2019-09-16 13:18:22 -0700447 DeltaArchiveManifest update_manifest;
448 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
449 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700450
451 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700452 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700453}
454
455TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700456 DeltaArchiveManifest update_manifest;
457 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
458 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
459 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700460 << "Should not be able to grow over maximum size of group";
461}
462
463TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700464 DeltaArchiveManifest update_manifest;
465 AddGroup(&update_manifest, "android", 3_GiB);
466 AddGroup(&update_manifest, "oem", 3_GiB);
467 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700468 << "Should not be able to grow over size of super / 2";
469}
470
471TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700472 DeltaArchiveManifest expected;
473 auto* g = AddGroup(&expected, T("android"), 3_GiB);
474 AddPartition(&expected, g, T("system"), 2_GiB);
475 AddPartition(&expected, g, T("system_ext"), 1_GiB);
476
477 DeltaArchiveManifest update_manifest;
478 g = AddGroup(&update_manifest, "android", 3_GiB);
479 AddPartition(&update_manifest, g, "system", 2_GiB);
480 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
481 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
482
Yifan Hongc049f932019-07-23 15:06:05 -0700483 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700484 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700485}
486
487TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700488 DeltaArchiveManifest expected;
489 AddGroup(&expected, T("android"), 3_GiB);
490
491 DeltaArchiveManifest update_manifest;
492 AddGroup(&update_manifest, "android", 3_GiB);
493 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
494
Yifan Hongc049f932019-07-23 15:06:05 -0700495 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700496 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700497}
498
499TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700500 DeltaArchiveManifest expected;
501 AddGroupAndPartition(
502 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
503
504 DeltaArchiveManifest update_manifest;
505 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
506 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
507 AddGroupAndPartition(
508 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700509 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700510 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700511}
512
513TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700514 DeltaArchiveManifest update_manifest;
515 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700516
517 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700518 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700519}
520
521TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700522 DeltaArchiveManifest expected;
523 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
524 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
525 DeltaArchiveManifest update_manifest;
526 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
527 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700528 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700529 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700530}
531
532INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
533 DynamicPartitionControlAndroidGroupTestP,
534 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
535
536const PartitionSuffixSizes update_sizes_0() {
537 // Initial state is 0 for "other" slot.
538 return {
539 {"grown_a", 2_GiB},
540 {"shrunk_a", 1_GiB},
541 {"same_a", 100_MiB},
542 {"deleted_a", 150_MiB},
543 // no added_a
544 {"grown_b", 200_MiB},
545 // simulate system_other
546 {"shrunk_b", 0},
547 {"same_b", 0},
548 {"deleted_b", 0},
549 // no added_b
550 };
551}
552
553const PartitionSuffixSizes update_sizes_1() {
554 return {
555 {"grown_a", 2_GiB},
556 {"shrunk_a", 1_GiB},
557 {"same_a", 100_MiB},
558 {"deleted_a", 150_MiB},
559 // no added_a
560 {"grown_b", 3_GiB},
561 {"shrunk_b", 150_MiB},
562 {"same_b", 100_MiB},
563 {"added_b", 150_MiB},
564 // no deleted_b
565 };
566}
567
568const PartitionSuffixSizes update_sizes_2() {
569 return {
570 {"grown_a", 4_GiB},
571 {"shrunk_a", 100_MiB},
572 {"same_a", 100_MiB},
573 {"deleted_a", 64_MiB},
574 // no added_a
575 {"grown_b", 3_GiB},
576 {"shrunk_b", 150_MiB},
577 {"same_b", 100_MiB},
578 {"added_b", 150_MiB},
579 // no deleted_b
580 };
581}
582
583// Test case for first update after the device is manufactured, in which
584// case the "other" slot is likely of size "0" (except system, which is
585// non-zero because of system_other partition)
586TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
587 SetSlots({0, 1});
588
589 SetMetadata(source(), update_sizes_0());
590 SetMetadata(target(), update_sizes_0());
591 ExpectStoreMetadata(update_sizes_1());
592 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
593
594 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
595 {"shrunk", 150_MiB},
596 {"same", 100_MiB},
597 {"added", 150_MiB}}));
598}
599
600// After first update, test for the second update. In the second update, the
601// "added" partition is deleted and "deleted" partition is re-added.
602TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
603 SetSlots({1, 0});
604
605 SetMetadata(source(), update_sizes_1());
606 SetMetadata(target(), update_sizes_0());
607
608 ExpectStoreMetadata(update_sizes_2());
609 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
610
611 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
612 {"shrunk", 100_MiB},
613 {"same", 100_MiB},
614 {"deleted", 64_MiB}}));
615}
616
Yifan Hong3a1a5612019-11-05 16:34:32 -0800617TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
618 SetSlots({1, 1});
619 EXPECT_FALSE(PreparePartitionsForUpdate({}))
620 << "Should not be able to apply to current slot.";
621}
622
Yifan Hong6eec9952019-12-04 13:12:01 -0800623TEST_P(DynamicPartitionControlAndroidTestP, ShouldSkipOperationTest) {
624 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
625 source(), target(), PartitionSizesToManifest({{"foo", 4_MiB}}), false));
626 dynamicControl().set_fake_mapped_devices({T("foo")});
627
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000628 InstallOperation iop;
629 Extent *se, *de;
630
631 // Not a SOURCE_COPY operation, cannot skip.
632 iop.set_type(InstallOperation::REPLACE);
Yifan Hong6eec9952019-12-04 13:12:01 -0800633 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000634
635 iop.set_type(InstallOperation::SOURCE_COPY);
636
637 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
Yifan Hong6eec9952019-12-04 13:12:01 -0800638 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000639
640 // Enable GetVirtualAbFeatureFlag in the mock interface.
641 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
642 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
643
644 // By default target_supports_snapshot_ is set to false. Cannot skip
645 // operation.
Yifan Hong6eec9952019-12-04 13:12:01 -0800646 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000647
648 SetSnapshotEnabled(true);
649
650 // Empty source and destination. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800651 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000652
653 se = iop.add_src_extents();
654 se->set_start_block(0);
655 se->set_num_blocks(1);
656
657 // There is something in sources, but destinations are empty. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800658 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000659
660 InstallOperation iop2;
661
662 de = iop2.add_dst_extents();
663 de->set_start_block(0);
664 de->set_num_blocks(1);
665
666 // There is something in destinations, but sources are empty. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800667 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop2));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000668
669 de = iop.add_dst_extents();
670 de->set_start_block(0);
671 de->set_num_blocks(1);
672
673 // Sources and destinations are identical. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800674 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000675
676 se = iop.add_src_extents();
677 se->set_start_block(1);
678 se->set_num_blocks(5);
679
680 // There is something in source, but not in destination. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800681 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000682
683 de = iop.add_dst_extents();
684 de->set_start_block(1);
685 de->set_num_blocks(5);
686
687 // There is source and destination are equal. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800688 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000689
690 de = iop.add_dst_extents();
691 de->set_start_block(6);
692 de->set_num_blocks(5);
693
694 // There is something extra in dest. Cannot skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800695 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("foo", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000696
697 se = iop.add_src_extents();
698 se->set_start_block(6);
699 se->set_num_blocks(5);
700
701 // Source and dest are identical again. Skip.
Yifan Hong6eec9952019-12-04 13:12:01 -0800702 EXPECT_TRUE(dynamicControl().ShouldSkipOperation("foo", iop));
703
704 // Don't skip for static partitions.
705 EXPECT_FALSE(dynamicControl().ShouldSkipOperation("bar", iop));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000706}
707
Yifan Hongc049f932019-07-23 15:06:05 -0700708} // namespace chromeos_update_engine