blob: 20819182da832665caa5ee614ce094b28f2e27a9 [file] [log] [blame]
Yifan Hongc049f932019-07-23 15:06:05 -07001//
2// Copyright (C) 2019 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/dynamic_partition_control_android.h"
18
19#include <set>
20#include <vector>
21
22#include <base/logging.h>
23#include <base/strings/string_util.h>
24#include <gmock/gmock.h>
25#include <gtest/gtest.h>
Yifan Hong29692902020-03-26 12:47:05 -070026#include <libavb/libavb.h>
Yifan Hongc049f932019-07-23 15:06:05 -070027
Yifan Hong6a6d0f12020-03-11 13:20:52 -070028#include "update_engine/common/mock_prefs.h"
Yifan Hong29692902020-03-26 12:47:05 -070029#include "update_engine/common/test_utils.h"
Yifan Hongc049f932019-07-23 15:06:05 -070030#include "update_engine/dynamic_partition_test_utils.h"
31#include "update_engine/mock_dynamic_partition_control.h"
32
Yifan Hong3a1a5612019-11-05 16:34:32 -080033using android::dm::DmDeviceState;
Yifan Hong29692902020-03-26 12:47:05 -070034using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
35using chromeos_update_engine::test_utils::ScopedTempFile;
Yifan Hongc049f932019-07-23 15:06:05 -070036using std::string;
37using testing::_;
38using testing::AnyNumber;
Yifan Hong3a1a5612019-11-05 16:34:32 -080039using testing::AnyOf;
Yifan Hongc049f932019-07-23 15:06:05 -070040using testing::Invoke;
41using testing::NiceMock;
42using testing::Not;
Yifan Hong29692902020-03-26 12:47:05 -070043using testing::Optional;
Yifan Hongc049f932019-07-23 15:06:05 -070044using testing::Return;
45
46namespace chromeos_update_engine {
47
48class DynamicPartitionControlAndroidTest : public ::testing::Test {
49 public:
50 void SetUp() override {
51 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
52
53 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
54 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
Yifan Hong413d5722019-07-23 14:21:09 -070055 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
56 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
Yifan Hongc049f932019-07-23 15:06:05 -070057
58 ON_CALL(dynamicControl(), GetDeviceDir(_))
59 .WillByDefault(Invoke([](auto path) {
60 *path = kFakeDevicePath;
61 return true;
62 }));
Yifan Hong700d7c12019-07-23 20:49:16 -070063
64 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
65 .WillByDefault(Return(kFakeSuper));
Yifan Hong3a1a5612019-11-05 16:34:32 -080066
67 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
68 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
69 *device = GetDmDevice(partition_name_suffix);
70 return true;
71 }));
Yifan Hong29692902020-03-26 12:47:05 -070072
73 ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
74 .WillByDefault(Return(true));
Yifan Hongc049f932019-07-23 15:06:05 -070075 }
76
77 // Return the mocked DynamicPartitionControlInterface.
78 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
79 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
80 }
81
Yifan Hong700d7c12019-07-23 20:49:16 -070082 std::string GetSuperDevice(uint32_t slot) {
83 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
84 }
85
Yifan Hongc049f932019-07-23 15:06:05 -070086 uint32_t source() { return slots_.source; }
87 uint32_t target() { return slots_.target; }
88
89 // Return partition names with suffix of source().
90 std::string S(const std::string& name) {
91 return name + kSlotSuffixes[source()];
92 }
93
94 // Return partition names with suffix of target().
95 std::string T(const std::string& name) {
96 return name + kSlotSuffixes[target()];
97 }
98
99 // Set the fake metadata to return when LoadMetadataBuilder is called on
100 // |slot|.
Yifan Hong29692902020-03-26 12:47:05 -0700101 void SetMetadata(uint32_t slot,
102 const PartitionSuffixSizes& sizes,
103 uint32_t partition_attr = 0) {
Yifan Hongc049f932019-07-23 15:06:05 -0700104 EXPECT_CALL(dynamicControl(),
105 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
106 .Times(AnyNumber())
Yifan Hong29692902020-03-26 12:47:05 -0700107 .WillRepeatedly(Invoke([sizes, partition_attr](auto, auto, auto) {
108 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
109 partition_attr);
Yifan Hongc049f932019-07-23 15:06:05 -0700110 }));
111 }
112
113 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
114 EXPECT_CALL(dynamicControl(),
115 StoreMetadata(GetSuperDevice(target()),
116 MetadataMatches(partition_sizes),
117 target()))
118 .WillOnce(Return(true));
119 }
120
121 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
122 // slot with each partition in |partitions|.
123 void ExpectUnmap(const std::set<std::string>& partitions) {
124 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
125 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
126 .WillByDefault(Return(false));
127
128 for (const auto& partition : partitions) {
129 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
130 .WillOnce(Return(true));
131 }
132 }
133 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
134 return dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800135 source(),
136 target(),
137 PartitionSizesToManifest(partition_sizes),
138 true,
139 nullptr);
Yifan Hongc049f932019-07-23 15:06:05 -0700140 }
141 void SetSlots(const TestParam& slots) { slots_ = slots; }
142
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000143 void SetSnapshotEnabled(bool enabled) {
144 dynamicControl().target_supports_snapshot_ = enabled;
145 }
146
Yifan Hongc049f932019-07-23 15:06:05 -0700147 struct Listener : public ::testing::MatchResultListener {
148 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
149 };
150
151 testing::AssertionResult UpdatePartitionMetadata(
152 const PartitionSuffixSizes& source_metadata,
153 const PartitionSizes& update_metadata,
154 const PartitionSuffixSizes& expected) {
155 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700156 PartitionSuffixSizesToManifest(source_metadata),
157 PartitionSizesToManifest(update_metadata),
158 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700159 }
160 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700161 const DeltaArchiveManifest& source_manifest,
162 const DeltaArchiveManifest& update_manifest,
163 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700164 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700165 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700166 }
167 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700168 const DeltaArchiveManifest& source_manifest,
169 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700170 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700171 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700172 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700173 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700174 return testing::AssertionFailure()
175 << "UpdatePartitionMetadataInternal failed";
176 }
177 std::stringstream ss;
178 Listener listener(&ss);
179 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
180 return testing::AssertionSuccess() << ss.str();
181 } else {
182 return testing::AssertionFailure() << ss.str();
183 }
184 }
185
186 std::unique_ptr<DynamicPartitionControlAndroid> module_;
187 TestParam slots_;
188};
189
190class DynamicPartitionControlAndroidTestP
191 : public DynamicPartitionControlAndroidTest,
192 public ::testing::WithParamInterface<TestParam> {
193 public:
194 void SetUp() override {
195 DynamicPartitionControlAndroidTest::SetUp();
196 SetSlots(GetParam());
197 }
198};
199
200// Test resize case. Grow if target metadata contains a partition with a size
201// less than expected.
202TEST_P(DynamicPartitionControlAndroidTestP,
203 NeedGrowIfSizeNotMatchWhenResizing) {
204 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
205 {S("vendor"), 1_GiB},
206 {T("system"), 2_GiB},
207 {T("vendor"), 1_GiB}};
208 PartitionSuffixSizes expected{{S("system"), 2_GiB},
209 {S("vendor"), 1_GiB},
210 {T("system"), 3_GiB},
211 {T("vendor"), 1_GiB}};
212 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
213 EXPECT_TRUE(
214 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
215}
216
217// Test resize case. Shrink if target metadata contains a partition with a size
218// greater than expected.
219TEST_P(DynamicPartitionControlAndroidTestP,
220 NeedShrinkIfSizeNotMatchWhenResizing) {
221 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
222 {S("vendor"), 1_GiB},
223 {T("system"), 2_GiB},
224 {T("vendor"), 1_GiB}};
225 PartitionSuffixSizes expected{{S("system"), 2_GiB},
226 {S("vendor"), 1_GiB},
227 {T("system"), 2_GiB},
228 {T("vendor"), 150_MiB}};
229 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
230 EXPECT_TRUE(
231 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
232}
233
234// Test adding partitions on the first run.
235TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
236 PartitionSuffixSizes source_metadata{};
237 PartitionSuffixSizes expected{{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 subsequent add case.
244TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
245 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
246 {T("system"), 2_GiB}};
247 PartitionSuffixSizes expected{
248 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
249 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
250 EXPECT_TRUE(
251 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
252}
253
254// Test delete one partition.
255TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
256 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
257 {S("vendor"), 1_GiB},
258 {T("system"), 2_GiB},
259 {T("vendor"), 1_GiB}};
260 // No T("vendor")
261 PartitionSuffixSizes expected{
262 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
263 PartitionSizes update_metadata{{"system", 2_GiB}};
264 EXPECT_TRUE(
265 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
266}
267
268// Test delete all partitions.
269TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
270 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
271 {S("vendor"), 1_GiB},
272 {T("system"), 2_GiB},
273 {T("vendor"), 1_GiB}};
274 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
275 PartitionSizes update_metadata{};
276 EXPECT_TRUE(
277 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
278}
279
280// Test corrupt source metadata case.
281TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
282 EXPECT_CALL(dynamicControl(),
283 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
284 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
285 ExpectUnmap({T("system")});
286
287 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
288 << "Should not be able to continue with corrupt source metadata";
289}
290
291// Test that UpdatePartitionMetadata fails if there is not enough space on the
292// device.
293TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
294 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
295 {S("vendor"), 2_GiB},
296 {T("system"), 0},
297 {T("vendor"), 0}};
298 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
299
300 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
301 << "Should not be able to fit 11GiB data into 10GiB space";
302}
303
304TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
305 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
306 {S("vendor"), 1_GiB},
307 {T("system"), 0},
308 {T("vendor"), 0}};
309 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
310 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
311 << "Should not be able to grow over size of super / 2";
312}
313
Yifan Hong3a1a5612019-11-05 16:34:32 -0800314TEST_P(DynamicPartitionControlAndroidTestP,
315 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
316 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
317 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
318 // Static partition {system,bar}_{a,b} exists.
319 EXPECT_CALL(dynamicControl(),
320 DeviceExists(AnyOf(GetDevice(S("bar")),
321 GetDevice(T("bar")),
322 GetDevice(S("system")),
323 GetDevice(T("system")))))
324 .WillRepeatedly(Return(true));
325
326 SetMetadata(source(),
327 {{S("system"), 2_GiB},
328 {S("vendor"), 1_GiB},
329 {T("system"), 2_GiB},
330 {T("vendor"), 1_GiB}});
331
332 // Not calling through
333 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
334 // don't want any default group in the PartitionMetadata.
335 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800336 source(), target(), {}, true, nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800337
338 // Should use dynamic source partitions.
339 EXPECT_CALL(dynamicControl(), GetState(S("system")))
340 .Times(1)
341 .WillOnce(Return(DmDeviceState::ACTIVE));
342 string system_device;
343 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
344 "system", source(), source(), &system_device));
345 EXPECT_EQ(GetDmDevice(S("system")), system_device);
346
347 // Should use static target partitions without querying dynamic control.
348 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
349 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
350 "system", target(), source(), &system_device));
351 EXPECT_EQ(GetDevice(T("system")), system_device);
352
353 // Static partition "bar".
354 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
355 std::string bar_device;
356 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
357 "bar", source(), source(), &bar_device));
358 EXPECT_EQ(GetDevice(S("bar")), bar_device);
359
360 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
361 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
362 "bar", target(), source(), &bar_device));
363 EXPECT_EQ(GetDevice(T("bar")), bar_device);
364}
365
366TEST_P(DynamicPartitionControlAndroidTestP,
367 GetPartitionDeviceWhenResumingUpdate) {
368 // Static partition bar_{a,b} exists.
369 EXPECT_CALL(dynamicControl(),
370 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
371 .WillRepeatedly(Return(true));
372
373 // Both of the two slots contain valid partition metadata, since this is
374 // resuming an update.
375 SetMetadata(source(),
376 {{S("system"), 2_GiB},
377 {S("vendor"), 1_GiB},
378 {T("system"), 2_GiB},
379 {T("vendor"), 1_GiB}});
380 SetMetadata(target(),
381 {{S("system"), 2_GiB},
382 {S("vendor"), 1_GiB},
383 {T("system"), 2_GiB},
384 {T("vendor"), 1_GiB}});
385
386 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
387 source(),
388 target(),
389 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
Yifan Hongf033ecb2020-01-07 18:13:56 -0800390 false,
391 nullptr));
Yifan Hong3a1a5612019-11-05 16:34:32 -0800392
393 // Dynamic partition "system".
394 EXPECT_CALL(dynamicControl(), GetState(S("system")))
395 .Times(1)
396 .WillOnce(Return(DmDeviceState::ACTIVE));
397 string system_device;
398 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
399 "system", source(), source(), &system_device));
400 EXPECT_EQ(GetDmDevice(S("system")), system_device);
401
402 EXPECT_CALL(dynamicControl(), GetState(T("system")))
403 .Times(AnyNumber())
404 .WillOnce(Return(DmDeviceState::ACTIVE));
405 EXPECT_CALL(dynamicControl(),
406 MapPartitionOnDeviceMapper(
407 GetSuperDevice(target()), T("system"), target(), _, _))
408 .Times(AnyNumber())
409 .WillRepeatedly(
410 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
411 *device = "/fake/remapped/" + name;
412 return true;
413 }));
414 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
415 "system", target(), source(), &system_device));
416 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
417
418 // Static partition "bar".
419 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
420 std::string bar_device;
421 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
422 "bar", source(), source(), &bar_device));
423 EXPECT_EQ(GetDevice(S("bar")), bar_device);
424
425 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
426 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
427 "bar", target(), source(), &bar_device));
428 EXPECT_EQ(GetDevice(T("bar")), bar_device);
429}
430
Yifan Hongc049f932019-07-23 15:06:05 -0700431INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
432 DynamicPartitionControlAndroidTestP,
433 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
434
435class DynamicPartitionControlAndroidGroupTestP
436 : public DynamicPartitionControlAndroidTestP {
437 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700438 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700439 void SetUp() override {
440 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700441 AddGroupAndPartition(
442 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
443 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
444 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
445 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700446 }
447
Yifan Hong13d41cb2019-09-16 13:18:22 -0700448 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
449 const string& group,
450 uint64_t group_size,
451 const string& partition,
452 uint64_t partition_size) {
453 auto* g = AddGroup(manifest, group, group_size);
454 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700455 }
456};
457
458// Allow to resize within group.
459TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700460 DeltaArchiveManifest expected;
461 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
462 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700463
Yifan Hong13d41cb2019-09-16 13:18:22 -0700464 DeltaArchiveManifest update_manifest;
465 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
466 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700467
468 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700469 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700470}
471
472TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700473 DeltaArchiveManifest update_manifest;
474 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
475 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
476 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700477 << "Should not be able to grow over maximum size of group";
478}
479
480TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700481 DeltaArchiveManifest update_manifest;
482 AddGroup(&update_manifest, "android", 3_GiB);
483 AddGroup(&update_manifest, "oem", 3_GiB);
484 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700485 << "Should not be able to grow over size of super / 2";
486}
487
488TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700489 DeltaArchiveManifest expected;
490 auto* g = AddGroup(&expected, T("android"), 3_GiB);
491 AddPartition(&expected, g, T("system"), 2_GiB);
492 AddPartition(&expected, g, T("system_ext"), 1_GiB);
493
494 DeltaArchiveManifest update_manifest;
495 g = AddGroup(&update_manifest, "android", 3_GiB);
496 AddPartition(&update_manifest, g, "system", 2_GiB);
497 AddPartition(&update_manifest, g, "system_ext", 1_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, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700505 DeltaArchiveManifest expected;
506 AddGroup(&expected, T("android"), 3_GiB);
507
508 DeltaArchiveManifest update_manifest;
509 AddGroup(&update_manifest, "android", 3_GiB);
510 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
511
Yifan Hongc049f932019-07-23 15:06:05 -0700512 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700513 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700514}
515
516TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700517 DeltaArchiveManifest expected;
518 AddGroupAndPartition(
519 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
520
521 DeltaArchiveManifest update_manifest;
522 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
523 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
524 AddGroupAndPartition(
525 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700526 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700527 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700528}
529
530TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700531 DeltaArchiveManifest update_manifest;
532 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700533
534 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700535 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700536}
537
538TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700539 DeltaArchiveManifest expected;
540 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
541 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
542 DeltaArchiveManifest update_manifest;
543 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
544 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700545 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700546 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700547}
548
549INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
550 DynamicPartitionControlAndroidGroupTestP,
551 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
552
553const PartitionSuffixSizes update_sizes_0() {
554 // Initial state is 0 for "other" slot.
555 return {
556 {"grown_a", 2_GiB},
557 {"shrunk_a", 1_GiB},
558 {"same_a", 100_MiB},
559 {"deleted_a", 150_MiB},
560 // no added_a
561 {"grown_b", 200_MiB},
562 // simulate system_other
563 {"shrunk_b", 0},
564 {"same_b", 0},
565 {"deleted_b", 0},
566 // no added_b
567 };
568}
569
570const PartitionSuffixSizes update_sizes_1() {
571 return {
572 {"grown_a", 2_GiB},
573 {"shrunk_a", 1_GiB},
574 {"same_a", 100_MiB},
575 {"deleted_a", 150_MiB},
576 // no added_a
577 {"grown_b", 3_GiB},
578 {"shrunk_b", 150_MiB},
579 {"same_b", 100_MiB},
580 {"added_b", 150_MiB},
581 // no deleted_b
582 };
583}
584
585const PartitionSuffixSizes update_sizes_2() {
586 return {
587 {"grown_a", 4_GiB},
588 {"shrunk_a", 100_MiB},
589 {"same_a", 100_MiB},
590 {"deleted_a", 64_MiB},
591 // no added_a
592 {"grown_b", 3_GiB},
593 {"shrunk_b", 150_MiB},
594 {"same_b", 100_MiB},
595 {"added_b", 150_MiB},
596 // no deleted_b
597 };
598}
599
600// Test case for first update after the device is manufactured, in which
601// case the "other" slot is likely of size "0" (except system, which is
602// non-zero because of system_other partition)
603TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
604 SetSlots({0, 1});
605
606 SetMetadata(source(), update_sizes_0());
607 SetMetadata(target(), update_sizes_0());
608 ExpectStoreMetadata(update_sizes_1());
609 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
610
611 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
612 {"shrunk", 150_MiB},
613 {"same", 100_MiB},
614 {"added", 150_MiB}}));
615}
616
617// After first update, test for the second update. In the second update, the
618// "added" partition is deleted and "deleted" partition is re-added.
619TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
620 SetSlots({1, 0});
621
622 SetMetadata(source(), update_sizes_1());
623 SetMetadata(target(), update_sizes_0());
624
625 ExpectStoreMetadata(update_sizes_2());
626 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
627
628 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
629 {"shrunk", 100_MiB},
630 {"same", 100_MiB},
631 {"deleted", 64_MiB}}));
632}
633
Yifan Hong3a1a5612019-11-05 16:34:32 -0800634TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
635 SetSlots({1, 1});
636 EXPECT_FALSE(PreparePartitionsForUpdate({}))
637 << "Should not be able to apply to current slot.";
638}
639
Yifan Hongf5261562020-03-10 10:28:10 -0700640TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
Yifan Hong6eec9952019-12-04 13:12:01 -0800641 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf033ecb2020-01-07 18:13:56 -0800642 source(),
643 target(),
644 PartitionSizesToManifest({{"foo", 4_MiB}}),
645 false,
646 nullptr));
Yifan Hong6eec9952019-12-04 13:12:01 -0800647 dynamicControl().set_fake_mapped_devices({T("foo")});
648
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000649 InstallOperation iop;
Yifan Hongf5261562020-03-10 10:28:10 -0700650 InstallOperation optimized;
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000651 Extent *se, *de;
652
653 // Not a SOURCE_COPY operation, cannot skip.
654 iop.set_type(InstallOperation::REPLACE);
Yifan Hongf5261562020-03-10 10:28:10 -0700655 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000656
657 iop.set_type(InstallOperation::SOURCE_COPY);
658
659 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700660 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000661
662 // Enable GetVirtualAbFeatureFlag in the mock interface.
663 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
664 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
665
666 // By default target_supports_snapshot_ is set to false. Cannot skip
667 // operation.
Yifan Hongf5261562020-03-10 10:28:10 -0700668 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000669
670 SetSnapshotEnabled(true);
671
672 // Empty source and destination. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700673 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
674 EXPECT_TRUE(optimized.src_extents().empty());
675 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000676
677 se = iop.add_src_extents();
678 se->set_start_block(0);
679 se->set_num_blocks(1);
680
681 // There is something in sources, but destinations are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700682 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000683
684 InstallOperation iop2;
685
686 de = iop2.add_dst_extents();
687 de->set_start_block(0);
688 de->set_num_blocks(1);
689
690 // There is something in destinations, but sources are empty. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700691 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000692
693 de = iop.add_dst_extents();
694 de->set_start_block(0);
695 de->set_num_blocks(1);
696
697 // Sources and destinations are identical. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700698 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
699 EXPECT_TRUE(optimized.src_extents().empty());
700 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000701
702 se = iop.add_src_extents();
703 se->set_start_block(1);
704 se->set_num_blocks(5);
705
706 // There is something in source, but not in destination. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700707 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000708
709 de = iop.add_dst_extents();
710 de->set_start_block(1);
711 de->set_num_blocks(5);
712
713 // There is source and destination are equal. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700714 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
715 EXPECT_TRUE(optimized.src_extents().empty());
716 EXPECT_TRUE(optimized.dst_extents().empty());
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000717
718 de = iop.add_dst_extents();
719 de->set_start_block(6);
720 de->set_num_blocks(5);
721
722 // There is something extra in dest. Cannot skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700723 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000724
725 se = iop.add_src_extents();
726 se->set_start_block(6);
727 se->set_num_blocks(5);
728
729 // Source and dest are identical again. Skip.
Yifan Hongf5261562020-03-10 10:28:10 -0700730 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
731 EXPECT_TRUE(optimized.src_extents().empty());
732 EXPECT_TRUE(optimized.dst_extents().empty());
733
734 iop.Clear();
735 iop.set_type(InstallOperation::SOURCE_COPY);
736 se = iop.add_src_extents();
737 se->set_start_block(1);
738 se->set_num_blocks(1);
739 se = iop.add_src_extents();
740 se->set_start_block(3);
741 se->set_num_blocks(2);
742 se = iop.add_src_extents();
743 se->set_start_block(7);
744 se->set_num_blocks(2);
745 de = iop.add_dst_extents();
746 de->set_start_block(2);
747 de->set_num_blocks(5);
748
749 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
750 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
751 ASSERT_EQ(2, optimized.src_extents_size());
752 ASSERT_EQ(2, optimized.dst_extents_size());
753 EXPECT_EQ(1u, optimized.src_extents(0).start_block());
754 EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
755 EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
756 EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
757 EXPECT_EQ(7u, optimized.src_extents(1).start_block());
758 EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
759 EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
760 EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
Yifan Hong6eec9952019-12-04 13:12:01 -0800761
762 // Don't skip for static partitions.
Yifan Hongf5261562020-03-10 10:28:10 -0700763 EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
Alessio Balsini2a3b4a22019-11-25 16:46:51 +0000764}
765
Yifan Hong6a6d0f12020-03-11 13:20:52 -0700766TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
767 MockPrefs prefs;
768 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
769}
770
Yifan Hong29692902020-03-26 12:47:05 -0700771TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
772 // clang-format off
773 std::string fstab_content =
774 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical\n" // NOLINT(whitespace/line_length)
775 "/dev/block/by-name/system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other\n"; // NOLINT(whitespace/line_length)
776 // clang-format on
777 ScopedTempFile fstab;
778 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
779 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
780 Optional(false));
781}
782
783TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
784 // clang-format off
785 std::string fstab_content =
786 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical,avb_keys=/foo\n"; // NOLINT(whitespace/line_length)
787 // clang-format on
788 ScopedTempFile fstab;
789 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
790 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
791 Optional(true));
792}
793
794TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
795 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
796 .WillByDefault(Invoke([&](auto source_slot,
797 auto target_slot,
798 const auto& name,
799 auto path,
800 auto should_unmap) {
801 return dynamicControl().RealGetSystemOtherPath(
802 source_slot, target_slot, name, path, should_unmap);
803 }));
804 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
805 .WillByDefault(Return(false));
806 EXPECT_TRUE(
807 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
808}
809
810TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
811 SetMetadata(source(), {{S("system"), 100_MiB}});
812 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
813 .WillByDefault(Return(true));
814 std::string path;
815 bool should_unmap;
816 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
817 source(), target(), T("system"), &path, &should_unmap));
818 ASSERT_TRUE(path.empty()) << path;
819 ASSERT_FALSE(should_unmap);
820 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
821 .WillByDefault(Invoke([&](auto source_slot,
822 auto target_slot,
823 const auto& name,
824 auto path,
825 auto should_unmap) {
826 return dynamicControl().RealGetSystemOtherPath(
827 source_slot, target_slot, name, path, should_unmap);
828 }));
829 EXPECT_TRUE(
830 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
831}
832
833TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
834 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
835 SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
836 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
837 .WillByDefault(Return(true));
838 std::string path;
839 bool should_unmap;
840 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
841 source(), target(), T("system"), &path, &should_unmap));
842 ASSERT_TRUE(path.empty()) << path;
843 ASSERT_FALSE(should_unmap);
844 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
845 .WillByDefault(Invoke([&](auto source_slot,
846 auto target_slot,
847 const auto& name,
848 auto path,
849 auto should_unmap) {
850 return dynamicControl().RealGetSystemOtherPath(
851 source_slot, target_slot, name, path, should_unmap);
852 }));
853 EXPECT_TRUE(
854 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
855}
856
857TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
858 constexpr uint64_t file_size = 1_MiB;
859 static_assert(file_size > AVB_FOOTER_SIZE);
860 ScopedTempFile system_other;
861 brillo::Blob original(file_size, 'X');
862 ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
863 std::string mnt_path;
864 ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
865 ASSERT_TRUE(dev.is_bound());
866
867 brillo::Blob device_content;
868 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
869 ASSERT_EQ(original, device_content);
870
871 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
872 SetMetadata(source(), sizes);
873 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
874 .WillByDefault(Return(true));
875 EXPECT_CALL(dynamicControl(),
876 GetSystemOtherPath(source(), target(), T("system"), _, _))
877 .WillRepeatedly(
878 Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
879 *path = mnt_path;
880 *should_unmap = false;
881 return true;
882 }));
883 ASSERT_TRUE(
884 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
885
886 device_content.clear();
887 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
888 brillo::Blob new_expected(original);
889 // Clear the last AVB_FOOTER_SIZE bytes.
890 new_expected.resize(file_size - AVB_FOOTER_SIZE);
891 new_expected.resize(file_size, '\0');
892 ASSERT_EQ(new_expected, device_content);
893}
894
Yifan Hongc049f932019-07-23 15:06:05 -0700895} // namespace chromeos_update_engine