1 //
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/aosp/dynamic_partition_control_android.h"
18
19 #include <algorithm>
20 #include <set>
21 #include <vector>
22
23 #include <base/logging.h>
24 #include <base/strings/string_util.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 #include <libavb/libavb.h>
28 #include <libsnapshot/mock_snapshot.h>
29
30 #include "update_engine/aosp/dynamic_partition_test_utils.h"
31 #include "update_engine/aosp/mock_dynamic_partition_control_android.h"
32 #include "update_engine/common/mock_prefs.h"
33 #include "update_engine/common/test_utils.h"
34
35 using android::dm::DmDeviceState;
36 using android::snapshot::MockSnapshotManager;
37 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
38 using std::string;
39 using testing::_;
40 using testing::AnyNumber;
41 using testing::AnyOf;
42 using testing::AtLeast;
43 using testing::Invoke;
44 using testing::NiceMock;
45 using testing::Not;
46 using testing::Optional;
47 using testing::Return;
48
49 namespace chromeos_update_engine {
50
51 class DynamicPartitionControlAndroidTest : public ::testing::Test {
52 public:
SetUp()53 void SetUp() override {
54 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
55
56 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
57 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
58 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
59 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
60 ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
61 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
62 ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
63 .WillByDefault(Return(false));
64 ON_CALL(dynamicControl(), GetDeviceDir(_))
65 .WillByDefault(Invoke([](auto path) {
66 *path = kFakeDevicePath;
67 return true;
68 }));
69
70 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
71 .WillByDefault(Return(kFakeSuper));
72
73 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
74 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
75 *device = GetDmDevice(partition_name_suffix);
76 return true;
77 }));
78
79 ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
80 .WillByDefault(Return(true));
81
82 ON_CALL(dynamicControl(), IsRecovery()).WillByDefault(Return(false));
83
84 ON_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
85 .WillByDefault(Invoke([&](uint32_t source_slot,
86 uint32_t target_slot,
87 const DeltaArchiveManifest& manifest,
88 bool delete_source) {
89 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
90 source_slot, target_slot, manifest, delete_source);
91 }));
92 }
93
94 // Return the mocked DynamicPartitionControlInterface.
dynamicControl()95 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
96 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
97 }
98
GetSuperDevice(uint32_t slot)99 std::string GetSuperDevice(uint32_t slot) {
100 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
101 }
102
source()103 uint32_t source() { return slots_.source; }
target()104 uint32_t target() { return slots_.target; }
105
106 // Return partition names with suffix of source().
S(const std::string & name)107 std::string S(const std::string& name) {
108 return name + kSlotSuffixes[source()];
109 }
110
111 // Return partition names with suffix of target().
T(const std::string & name)112 std::string T(const std::string& name) {
113 return name + kSlotSuffixes[target()];
114 }
115
116 // Set the fake metadata to return when LoadMetadataBuilder is called on
117 // |slot|.
SetMetadata(uint32_t slot,const PartitionSuffixSizes & sizes,uint32_t partition_attr=0,uint64_t super_size=kDefaultSuperSize)118 void SetMetadata(uint32_t slot,
119 const PartitionSuffixSizes& sizes,
120 uint32_t partition_attr = 0,
121 uint64_t super_size = kDefaultSuperSize) {
122 EXPECT_CALL(dynamicControl(),
123 LoadMetadataBuilder(GetSuperDevice(slot), slot))
124 .Times(AnyNumber())
125 .WillRepeatedly(Invoke([=](auto, auto) {
126 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
127 partition_attr,
128 super_size);
129 }));
130
131 EXPECT_CALL(dynamicControl(),
132 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
133 .Times(AnyNumber())
134 .WillRepeatedly(Invoke([=](auto, auto, auto) {
135 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
136 partition_attr,
137 super_size);
138 }));
139 }
140
ExpectStoreMetadata(const PartitionSuffixSizes & partition_sizes)141 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
142 EXPECT_CALL(dynamicControl(),
143 StoreMetadata(GetSuperDevice(target()),
144 MetadataMatches(partition_sizes),
145 target()))
146 .WillOnce(Return(true));
147 }
148
149 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
150 // slot with each partition in |partitions|.
ExpectUnmap(const std::set<std::string> & partitions)151 void ExpectUnmap(const std::set<std::string>& partitions) {
152 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
153 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
154 .WillByDefault(Return(false));
155
156 for (const auto& partition : partitions) {
157 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
158 .WillOnce(Return(true));
159 }
160 }
PreparePartitionsForUpdate(const PartitionSizes & partition_sizes)161 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
162 return dynamicControl().PreparePartitionsForUpdate(
163 source(),
164 target(),
165 PartitionSizesToManifest(partition_sizes),
166 true,
167 nullptr);
168 }
SetSlots(const TestParam & slots)169 void SetSlots(const TestParam& slots) { slots_ = slots; }
170
SetSnapshotEnabled(bool enabled)171 void SetSnapshotEnabled(bool enabled) {
172 dynamicControl().target_supports_snapshot_ = enabled;
173 }
174
175 struct Listener : public ::testing::MatchResultListener {
Listenerchromeos_update_engine::DynamicPartitionControlAndroidTest::Listener176 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
177 };
178
UpdatePartitionMetadata(const PartitionSuffixSizes & source_metadata,const PartitionSizes & update_metadata,const PartitionSuffixSizes & expected)179 testing::AssertionResult UpdatePartitionMetadata(
180 const PartitionSuffixSizes& source_metadata,
181 const PartitionSizes& update_metadata,
182 const PartitionSuffixSizes& expected) {
183 return UpdatePartitionMetadata(
184 PartitionSuffixSizesToManifest(source_metadata),
185 PartitionSizesToManifest(update_metadata),
186 PartitionSuffixSizesToManifest(expected));
187 }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const DeltaArchiveManifest & expected)188 testing::AssertionResult UpdatePartitionMetadata(
189 const DeltaArchiveManifest& source_manifest,
190 const DeltaArchiveManifest& update_manifest,
191 const DeltaArchiveManifest& expected) {
192 return UpdatePartitionMetadata(
193 source_manifest, update_manifest, MetadataMatches(expected));
194 }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const Matcher<MetadataBuilder * > & matcher)195 testing::AssertionResult UpdatePartitionMetadata(
196 const DeltaArchiveManifest& source_manifest,
197 const DeltaArchiveManifest& update_manifest,
198 const Matcher<MetadataBuilder*>& matcher) {
199 auto super_metadata = NewFakeMetadata(source_manifest);
200 if (!module_->UpdatePartitionMetadata(
201 super_metadata.get(), target(), update_manifest)) {
202 return testing::AssertionFailure()
203 << "UpdatePartitionMetadataInternal failed";
204 }
205 std::stringstream ss;
206 Listener listener(&ss);
207 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
208 return testing::AssertionSuccess() << ss.str();
209 } else {
210 return testing::AssertionFailure() << ss.str();
211 }
212 }
213
214 std::unique_ptr<DynamicPartitionControlAndroid> module_;
215 TestParam slots_;
216 };
217
218 class DynamicPartitionControlAndroidTestP
219 : public DynamicPartitionControlAndroidTest,
220 public ::testing::WithParamInterface<TestParam> {
221 public:
SetUp()222 void SetUp() override {
223 DynamicPartitionControlAndroidTest::SetUp();
224 SetSlots(GetParam());
225 dynamicControl().SetSourceSlot(source());
226 dynamicControl().SetTargetSlot(target());
227 }
228 };
229
230 // Test resize case. Grow if target metadata contains a partition with a size
231 // less than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedGrowIfSizeNotMatchWhenResizing)232 TEST_P(DynamicPartitionControlAndroidTestP,
233 NeedGrowIfSizeNotMatchWhenResizing) {
234 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
235 {S("vendor"), 1_GiB},
236 {T("system"), 2_GiB},
237 {T("vendor"), 1_GiB}};
238 PartitionSuffixSizes expected{{S("system"), 2_GiB},
239 {S("vendor"), 1_GiB},
240 {T("system"), 3_GiB},
241 {T("vendor"), 1_GiB}};
242 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
243 EXPECT_TRUE(
244 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
245 }
246
247 // Test resize case. Shrink if target metadata contains a partition with a size
248 // greater than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedShrinkIfSizeNotMatchWhenResizing)249 TEST_P(DynamicPartitionControlAndroidTestP,
250 NeedShrinkIfSizeNotMatchWhenResizing) {
251 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
252 {S("vendor"), 1_GiB},
253 {T("system"), 2_GiB},
254 {T("vendor"), 1_GiB}};
255 PartitionSuffixSizes expected{{S("system"), 2_GiB},
256 {S("vendor"), 1_GiB},
257 {T("system"), 2_GiB},
258 {T("vendor"), 150_MiB}};
259 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
260 EXPECT_TRUE(
261 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
262 }
263
264 // Test adding partitions on the first run.
TEST_P(DynamicPartitionControlAndroidTestP,AddPartitionToEmptyMetadata)265 TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
266 PartitionSuffixSizes source_metadata{};
267 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
268 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
269 EXPECT_TRUE(
270 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
271 }
272
273 // Test subsequent add case.
TEST_P(DynamicPartitionControlAndroidTestP,AddAdditionalPartition)274 TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
275 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
276 {T("system"), 2_GiB}};
277 PartitionSuffixSizes expected{
278 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
279 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
280 EXPECT_TRUE(
281 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
282 }
283
284 // Test delete one partition.
TEST_P(DynamicPartitionControlAndroidTestP,DeletePartition)285 TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
286 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
287 {S("vendor"), 1_GiB},
288 {T("system"), 2_GiB},
289 {T("vendor"), 1_GiB}};
290 // No T("vendor")
291 PartitionSuffixSizes expected{
292 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
293 PartitionSizes update_metadata{{"system", 2_GiB}};
294 EXPECT_TRUE(
295 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
296 }
297
298 // Test delete all partitions.
TEST_P(DynamicPartitionControlAndroidTestP,DeleteAll)299 TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
300 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
301 {S("vendor"), 1_GiB},
302 {T("system"), 2_GiB},
303 {T("vendor"), 1_GiB}};
304 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
305 PartitionSizes update_metadata{};
306 EXPECT_TRUE(
307 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
308 }
309
310 // Test corrupt source metadata case.
TEST_P(DynamicPartitionControlAndroidTestP,CorruptedSourceMetadata)311 TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
312 EXPECT_CALL(dynamicControl(),
313 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
314 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
315 ExpectUnmap({T("system")});
316
317 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
318 << "Should not be able to continue with corrupt source metadata";
319 }
320
321 // Test that UpdatePartitionMetadata fails if there is not enough space on the
322 // device.
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpace)323 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
324 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
325 {S("vendor"), 2_GiB},
326 {T("system"), 0},
327 {T("vendor"), 0}};
328 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
329
330 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
331 << "Should not be able to fit 11GiB data into 10GiB space";
332 }
333
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpaceForSlot)334 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
335 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
336 {S("vendor"), 1_GiB},
337 {T("system"), 0},
338 {T("vendor"), 0}};
339 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
340 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
341 << "Should not be able to grow over size of super / 2";
342 }
343
TEST_P(DynamicPartitionControlAndroidTestP,ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild)344 TEST_P(DynamicPartitionControlAndroidTestP,
345 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
346 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
347 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
348 // Static partition {system,bar}_{a,b} exists.
349 EXPECT_CALL(dynamicControl(),
350 DeviceExists(AnyOf(GetDevice(S("bar")),
351 GetDevice(T("bar")),
352 GetDevice(S("system")),
353 GetDevice(T("system")))))
354 .WillRepeatedly(Return(true));
355
356 SetMetadata(source(),
357 {{S("system"), 2_GiB},
358 {S("vendor"), 1_GiB},
359 {T("system"), 2_GiB},
360 {T("vendor"), 1_GiB}});
361
362 // Not calling through
363 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
364 // don't want any default group in the PartitionMetadata.
365 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
366 source(), target(), {}, true, nullptr));
367
368 // Should use dynamic source partitions.
369 EXPECT_CALL(dynamicControl(), GetState(S("system")))
370 .Times(1)
371 .WillOnce(Return(DmDeviceState::ACTIVE));
372 string system_device;
373 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
374 "system", source(), source(), &system_device));
375 EXPECT_EQ(GetDmDevice(S("system")), system_device);
376
377 // Should use static target partitions without querying dynamic control.
378 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
379 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
380 "system", target(), source(), &system_device));
381 EXPECT_EQ(GetDevice(T("system")), system_device);
382
383 // Static partition "bar".
384 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
385 std::string bar_device;
386 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
387 "bar", source(), source(), &bar_device));
388 EXPECT_EQ(GetDevice(S("bar")), bar_device);
389
390 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
391 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
392 "bar", target(), source(), &bar_device));
393 EXPECT_EQ(GetDevice(T("bar")), bar_device);
394 }
395
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePath)396 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePath) {
397 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
398 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
399 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
400 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
401 ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
402 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
403 ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
404 .WillByDefault(Return(false));
405 ON_CALL(dynamicControl(), IsDynamicPartition(_, _))
406 .WillByDefault(Return(true));
407
408 EXPECT_CALL(dynamicControl(),
409 DeviceExists(AnyOf(GetDevice(S("vendor")),
410 GetDevice(T("vendor")),
411 GetDevice(S("system")),
412 GetDevice(T("system")))))
413 .WillRepeatedly(Return(true));
414 EXPECT_CALL(
415 dynamicControl(),
416 GetState(AnyOf(S("vendor"), T("vendor"), S("system"), T("system"))))
417 .WillRepeatedly(Return(DmDeviceState::ACTIVE));
418
419 SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
420 SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
421 std::string device;
422 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
423 "system", source(), source(), &device));
424 ASSERT_EQ(GetDmDevice(S("system")), device);
425
426 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
427 "system", target(), source(), &device));
428 ASSERT_EQ(GetDevice(T("system")), device);
429
430 // If VABC is disabled, mountable device path should be same as device path.
431 auto device_info =
432 dynamicControl().GetPartitionDevice("system", target(), source(), false);
433 ASSERT_TRUE(device_info.has_value());
434 ASSERT_EQ(device_info->readonly_device_path, device);
435 }
436
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePathVABC)437 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePathVABC) {
438 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
439 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
440 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
441 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
442 ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
443 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
444 ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
445 .WillByDefault(Return(true));
446 EXPECT_CALL(dynamicControl(), IsDynamicPartition(_, _))
447 .Times(AtLeast(1))
448 .WillRepeatedly(Return(true));
449
450 EXPECT_CALL(dynamicControl(),
451 DeviceExists(AnyOf(GetDevice(S("vendor")),
452 GetDevice(T("vendor")),
453 GetDevice(S("system")),
454 GetDevice(T("system")))))
455 .WillRepeatedly(Return(true));
456 EXPECT_CALL(
457 dynamicControl(),
458 GetState(AnyOf(S("vendor"), T("vendor"), S("system"), T("system"))))
459 .WillRepeatedly(Return(DmDeviceState::ACTIVE));
460
461 SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
462 SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
463
464 std::string device;
465 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
466 "system", source(), source(), &device));
467 ASSERT_EQ(GetDmDevice(S("system")), device);
468
469 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
470 "system", target(), source(), &device));
471 ASSERT_EQ("", device);
472
473 auto device_info =
474 dynamicControl().GetPartitionDevice("system", target(), source(), false);
475 ASSERT_TRUE(device_info.has_value());
476 base::FilePath vabc_device_dir{
477 std::string{DynamicPartitionControlAndroid::VABC_DEVICE_DIR}};
478 ASSERT_EQ(device_info->readonly_device_path,
479 vabc_device_dir.Append(T("system")).value());
480 }
481
TEST_P(DynamicPartitionControlAndroidTestP,GetPartitionDeviceWhenResumingUpdate)482 TEST_P(DynamicPartitionControlAndroidTestP,
483 GetPartitionDeviceWhenResumingUpdate) {
484 // Static partition bar_{a,b} exists.
485 EXPECT_CALL(dynamicControl(),
486 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
487 .WillRepeatedly(Return(true));
488
489 // Both of the two slots contain valid partition metadata, since this is
490 // resuming an update.
491 SetMetadata(source(),
492 {{S("system"), 2_GiB},
493 {S("vendor"), 1_GiB},
494 {T("system"), 2_GiB},
495 {T("vendor"), 1_GiB}});
496 SetMetadata(target(),
497 {{S("system"), 2_GiB},
498 {S("vendor"), 1_GiB},
499 {T("system"), 2_GiB},
500 {T("vendor"), 1_GiB}});
501
502 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
503 source(),
504 target(),
505 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
506 false,
507 nullptr));
508
509 // Dynamic partition "system".
510 EXPECT_CALL(dynamicControl(), GetState(S("system")))
511 .Times(1)
512 .WillOnce(Return(DmDeviceState::ACTIVE));
513 string system_device;
514 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
515 "system", source(), source(), &system_device));
516 EXPECT_EQ(GetDmDevice(S("system")), system_device);
517
518 EXPECT_CALL(dynamicControl(), GetState(T("system")))
519 .Times(AnyNumber())
520 .WillOnce(Return(DmDeviceState::ACTIVE));
521 EXPECT_CALL(dynamicControl(),
522 MapPartitionOnDeviceMapper(
523 GetSuperDevice(target()), T("system"), target(), _, _))
524 .Times(AnyNumber())
525 .WillRepeatedly(
526 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
527 *device = "/fake/remapped/" + name;
528 return true;
529 }));
530 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
531 "system", target(), source(), &system_device));
532 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
533
534 // Static partition "bar".
535 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
536 std::string bar_device;
537 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
538 "bar", source(), source(), &bar_device));
539 EXPECT_EQ(GetDevice(S("bar")), bar_device);
540
541 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
542 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
543 "bar", target(), source(), &bar_device));
544 EXPECT_EQ(GetDevice(T("bar")), bar_device);
545 }
546
547 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
548 DynamicPartitionControlAndroidTestP,
549 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
550
551 class DynamicPartitionControlAndroidGroupTestP
552 : public DynamicPartitionControlAndroidTestP {
553 public:
554 DeltaArchiveManifest source_manifest;
SetUp()555 void SetUp() override {
556 DynamicPartitionControlAndroidTestP::SetUp();
557 AddGroupAndPartition(
558 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
559 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
560 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
561 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
562 }
563
AddGroupAndPartition(DeltaArchiveManifest * manifest,const string & group,uint64_t group_size,const string & partition,uint64_t partition_size)564 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
565 const string& group,
566 uint64_t group_size,
567 const string& partition,
568 uint64_t partition_size) {
569 auto* g = AddGroup(manifest, group, group_size);
570 AddPartition(manifest, g, partition, partition_size);
571 }
572 };
573
574 // Allow to resize within group.
TEST_P(DynamicPartitionControlAndroidGroupTestP,ResizeWithinGroup)575 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
576 DeltaArchiveManifest expected;
577 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
578 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
579
580 DeltaArchiveManifest update_manifest;
581 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
582 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
583
584 EXPECT_TRUE(
585 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
586 }
587
TEST_P(DynamicPartitionControlAndroidGroupTestP,NotEnoughSpaceForGroup)588 TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
589 DeltaArchiveManifest update_manifest;
590 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
591 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
592 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
593 << "Should not be able to grow over maximum size of group";
594 }
595
TEST_P(DynamicPartitionControlAndroidGroupTestP,GroupTooBig)596 TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
597 DeltaArchiveManifest update_manifest;
598 AddGroup(&update_manifest, "android", 3_GiB);
599 AddGroup(&update_manifest, "oem", 3_GiB);
600 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
601 << "Should not be able to grow over size of super / 2";
602 }
603
TEST_P(DynamicPartitionControlAndroidGroupTestP,AddPartitionToGroup)604 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
605 DeltaArchiveManifest expected;
606 auto* g = AddGroup(&expected, T("android"), 3_GiB);
607 AddPartition(&expected, g, T("system"), 2_GiB);
608 AddPartition(&expected, g, T("system_ext"), 1_GiB);
609
610 DeltaArchiveManifest update_manifest;
611 g = AddGroup(&update_manifest, "android", 3_GiB);
612 AddPartition(&update_manifest, g, "system", 2_GiB);
613 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
614 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
615
616 EXPECT_TRUE(
617 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
618 }
619
TEST_P(DynamicPartitionControlAndroidGroupTestP,RemovePartitionFromGroup)620 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
621 DeltaArchiveManifest expected;
622 AddGroup(&expected, T("android"), 3_GiB);
623
624 DeltaArchiveManifest update_manifest;
625 AddGroup(&update_manifest, "android", 3_GiB);
626 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
627
628 EXPECT_TRUE(
629 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
630 }
631
TEST_P(DynamicPartitionControlAndroidGroupTestP,AddGroup)632 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
633 DeltaArchiveManifest expected;
634 AddGroupAndPartition(
635 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
636
637 DeltaArchiveManifest update_manifest;
638 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
639 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
640 AddGroupAndPartition(
641 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
642 EXPECT_TRUE(
643 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
644 }
645
TEST_P(DynamicPartitionControlAndroidGroupTestP,RemoveGroup)646 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
647 DeltaArchiveManifest update_manifest;
648 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
649
650 EXPECT_TRUE(UpdatePartitionMetadata(
651 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
652 }
653
TEST_P(DynamicPartitionControlAndroidGroupTestP,ResizeGroup)654 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
655 DeltaArchiveManifest expected;
656 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
657 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
658 DeltaArchiveManifest update_manifest;
659 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
660 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
661 EXPECT_TRUE(
662 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
663 }
664
665 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
666 DynamicPartitionControlAndroidGroupTestP,
667 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
668
update_sizes_0()669 const PartitionSuffixSizes update_sizes_0() {
670 // Initial state is 0 for "other" slot.
671 return {
672 {"grown_a", 2_GiB},
673 {"shrunk_a", 1_GiB},
674 {"same_a", 100_MiB},
675 {"deleted_a", 150_MiB},
676 // no added_a
677 {"grown_b", 200_MiB},
678 // simulate system_other
679 {"shrunk_b", 0},
680 {"same_b", 0},
681 {"deleted_b", 0},
682 // no added_b
683 };
684 }
685
update_sizes_1()686 const PartitionSuffixSizes update_sizes_1() {
687 return {
688 {"grown_a", 2_GiB},
689 {"shrunk_a", 1_GiB},
690 {"same_a", 100_MiB},
691 {"deleted_a", 150_MiB},
692 // no added_a
693 {"grown_b", 3_GiB},
694 {"shrunk_b", 150_MiB},
695 {"same_b", 100_MiB},
696 {"added_b", 150_MiB},
697 // no deleted_b
698 };
699 }
700
update_sizes_2()701 const PartitionSuffixSizes update_sizes_2() {
702 return {
703 {"grown_a", 4_GiB},
704 {"shrunk_a", 100_MiB},
705 {"same_a", 100_MiB},
706 {"deleted_a", 64_MiB},
707 // no added_a
708 {"grown_b", 3_GiB},
709 {"shrunk_b", 150_MiB},
710 {"same_b", 100_MiB},
711 {"added_b", 150_MiB},
712 // no deleted_b
713 };
714 }
715
716 // Test case for first update after the device is manufactured, in which
717 // case the "other" slot is likely of size "0" (except system, which is
718 // non-zero because of system_other partition)
TEST_F(DynamicPartitionControlAndroidTest,SimulatedFirstUpdate)719 TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
720 SetSlots({0, 1});
721
722 SetMetadata(source(), update_sizes_0());
723 SetMetadata(target(), update_sizes_0());
724 ExpectStoreMetadata(update_sizes_1());
725 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
726
727 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
728 {"shrunk", 150_MiB},
729 {"same", 100_MiB},
730 {"added", 150_MiB}}));
731 }
732
733 // After first update, test for the second update. In the second update, the
734 // "added" partition is deleted and "deleted" partition is re-added.
TEST_F(DynamicPartitionControlAndroidTest,SimulatedSecondUpdate)735 TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
736 SetSlots({1, 0});
737
738 SetMetadata(source(), update_sizes_1());
739 SetMetadata(target(), update_sizes_0());
740
741 ExpectStoreMetadata(update_sizes_2());
742 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
743
744 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
745 {"shrunk", 100_MiB},
746 {"same", 100_MiB},
747 {"deleted", 64_MiB}}));
748 }
749
TEST_F(DynamicPartitionControlAndroidTest,ApplyingToCurrentSlot)750 TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
751 SetSlots({1, 1});
752 EXPECT_FALSE(PreparePartitionsForUpdate({}))
753 << "Should not be able to apply to current slot.";
754 }
755
TEST_P(DynamicPartitionControlAndroidTestP,OptimizeOperationTest)756 TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) {
757 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
758 source(),
759 target(),
760 PartitionSizesToManifest({{"foo", 4_MiB}}),
761 false,
762 nullptr));
763 dynamicControl().set_fake_mapped_devices({T("foo")});
764
765 InstallOperation iop;
766 InstallOperation optimized;
767 Extent *se, *de;
768
769 // Not a SOURCE_COPY operation, cannot skip.
770 iop.set_type(InstallOperation::REPLACE);
771 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
772
773 iop.set_type(InstallOperation::SOURCE_COPY);
774
775 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
776 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
777
778 // Enable GetVirtualAbFeatureFlag in the mock interface.
779 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
780 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
781
782 // By default target_supports_snapshot_ is set to false. Cannot skip
783 // operation.
784 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
785
786 SetSnapshotEnabled(true);
787
788 // Empty source and destination. Skip.
789 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
790 EXPECT_TRUE(optimized.src_extents().empty());
791 EXPECT_TRUE(optimized.dst_extents().empty());
792
793 se = iop.add_src_extents();
794 se->set_start_block(0);
795 se->set_num_blocks(1);
796
797 // There is something in sources, but destinations are empty. Cannot skip.
798 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
799
800 InstallOperation iop2;
801
802 de = iop2.add_dst_extents();
803 de->set_start_block(0);
804 de->set_num_blocks(1);
805
806 // There is something in destinations, but sources are empty. Cannot skip.
807 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
808
809 de = iop.add_dst_extents();
810 de->set_start_block(0);
811 de->set_num_blocks(1);
812
813 // Sources and destinations are identical. Skip.
814 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
815 EXPECT_TRUE(optimized.src_extents().empty());
816 EXPECT_TRUE(optimized.dst_extents().empty());
817
818 se = iop.add_src_extents();
819 se->set_start_block(1);
820 se->set_num_blocks(5);
821
822 // There is something in source, but not in destination. Cannot skip.
823 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
824
825 de = iop.add_dst_extents();
826 de->set_start_block(1);
827 de->set_num_blocks(5);
828
829 // There is source and destination are equal. Skip.
830 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
831 EXPECT_TRUE(optimized.src_extents().empty());
832 EXPECT_TRUE(optimized.dst_extents().empty());
833
834 de = iop.add_dst_extents();
835 de->set_start_block(6);
836 de->set_num_blocks(5);
837
838 // There is something extra in dest. Cannot skip.
839 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
840
841 se = iop.add_src_extents();
842 se->set_start_block(6);
843 se->set_num_blocks(5);
844
845 // Source and dest are identical again. Skip.
846 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
847 EXPECT_TRUE(optimized.src_extents().empty());
848 EXPECT_TRUE(optimized.dst_extents().empty());
849
850 iop.Clear();
851 iop.set_type(InstallOperation::SOURCE_COPY);
852 se = iop.add_src_extents();
853 se->set_start_block(1);
854 se->set_num_blocks(1);
855 se = iop.add_src_extents();
856 se->set_start_block(3);
857 se->set_num_blocks(2);
858 se = iop.add_src_extents();
859 se->set_start_block(7);
860 se->set_num_blocks(2);
861 de = iop.add_dst_extents();
862 de->set_start_block(2);
863 de->set_num_blocks(5);
864
865 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
866 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
867 ASSERT_EQ(2, optimized.src_extents_size());
868 ASSERT_EQ(2, optimized.dst_extents_size());
869 EXPECT_EQ(1u, optimized.src_extents(0).start_block());
870 EXPECT_EQ(1u, optimized.src_extents(0).num_blocks());
871 EXPECT_EQ(2u, optimized.dst_extents(0).start_block());
872 EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks());
873 EXPECT_EQ(7u, optimized.src_extents(1).start_block());
874 EXPECT_EQ(2u, optimized.src_extents(1).num_blocks());
875 EXPECT_EQ(5u, optimized.dst_extents(1).start_block());
876 EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks());
877
878 // Don't skip for static partitions.
879 EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
880 }
881
TEST_F(DynamicPartitionControlAndroidTest,ResetUpdate)882 TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
883 MockPrefs prefs;
884 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
885 }
886
TEST_F(DynamicPartitionControlAndroidTest,IsAvbNotEnabledInFstab)887 TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
888 std::string fstab_content =
889 "system /postinstall ext4 ro,nosuid,nodev,noexec "
890 "slotselect_other,logical\n"
891 "/dev/block/by-name/system /postinstall ext4 "
892 "ro,nosuid,nodev,noexec slotselect_other\n";
893 ScopedTempFile fstab;
894 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
895 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
896 Optional(false));
897 }
898
TEST_F(DynamicPartitionControlAndroidTest,IsAvbEnabledInFstab)899 TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
900 std::string fstab_content =
901 "system /postinstall ext4 ro,nosuid,nodev,noexec "
902 "slotselect_other,logical,avb_keys=/foo\n";
903 ScopedTempFile fstab;
904 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
905 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
906 Optional(true));
907 }
908
TEST_P(DynamicPartitionControlAndroidTestP,AvbNotEnabledOnSystemOther)909 TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
910 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
911 .WillByDefault(Invoke([&](auto source_slot,
912 auto target_slot,
913 const auto& name,
914 auto path,
915 auto should_unmap) {
916 return dynamicControl().RealGetSystemOtherPath(
917 source_slot, target_slot, name, path, should_unmap);
918 }));
919 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
920 .WillByDefault(Return(false));
921 EXPECT_TRUE(
922 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
923 }
924
TEST_P(DynamicPartitionControlAndroidTestP,NoSystemOtherToErase)925 TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
926 SetMetadata(source(), {{S("system"), 100_MiB}});
927 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
928 .WillByDefault(Return(true));
929 std::string path;
930 bool should_unmap;
931 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
932 source(), target(), T("system"), &path, &should_unmap));
933 ASSERT_TRUE(path.empty()) << path;
934 ASSERT_FALSE(should_unmap);
935 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
936 .WillByDefault(Invoke([&](auto source_slot,
937 auto target_slot,
938 const auto& name,
939 auto path,
940 auto should_unmap) {
941 return dynamicControl().RealGetSystemOtherPath(
942 source_slot, target_slot, name, path, should_unmap);
943 }));
944 EXPECT_TRUE(
945 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
946 }
947
TEST_P(DynamicPartitionControlAndroidTestP,SkipEraseUpdatedSystemOther)948 TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
949 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
950 SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
951 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
952 .WillByDefault(Return(true));
953 std::string path;
954 bool should_unmap;
955 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
956 source(), target(), T("system"), &path, &should_unmap));
957 ASSERT_TRUE(path.empty()) << path;
958 ASSERT_FALSE(should_unmap);
959 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
960 .WillByDefault(Invoke([&](auto source_slot,
961 auto target_slot,
962 const auto& name,
963 auto path,
964 auto should_unmap) {
965 return dynamicControl().RealGetSystemOtherPath(
966 source_slot, target_slot, name, path, should_unmap);
967 }));
968 EXPECT_TRUE(
969 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
970 }
971
TEST_P(DynamicPartitionControlAndroidTestP,EraseSystemOtherAvbFooter)972 TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
973 constexpr uint64_t file_size = 1_MiB;
974 static_assert(file_size > AVB_FOOTER_SIZE);
975 ScopedTempFile system_other;
976 brillo::Blob original(file_size, 'X');
977 ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
978 std::string mnt_path;
979 ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
980 ASSERT_TRUE(dev.is_bound());
981
982 brillo::Blob device_content;
983 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
984 ASSERT_EQ(original, device_content);
985
986 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
987 SetMetadata(source(), sizes);
988 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
989 .WillByDefault(Return(true));
990 EXPECT_CALL(dynamicControl(),
991 GetSystemOtherPath(source(), target(), T("system"), _, _))
992 .WillRepeatedly(
993 Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
994 *path = mnt_path;
995 *should_unmap = false;
996 return true;
997 }));
998 ASSERT_TRUE(
999 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
1000
1001 device_content.clear();
1002 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
1003 brillo::Blob new_expected(original);
1004 // Clear the last AVB_FOOTER_SIZE bytes.
1005 new_expected.resize(file_size - AVB_FOOTER_SIZE);
1006 new_expected.resize(file_size, '\0');
1007 ASSERT_EQ(new_expected, device_content);
1008 }
1009
1010 class FakeAutoDevice : public android::snapshot::AutoDevice {
1011 public:
FakeAutoDevice()1012 FakeAutoDevice() : AutoDevice("") {}
1013 };
1014
1015 class SnapshotPartitionTestP : public DynamicPartitionControlAndroidTestP {
1016 public:
SetUp()1017 void SetUp() override {
1018 DynamicPartitionControlAndroidTestP::SetUp();
1019 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
1020 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
1021
1022 snapshot_ = new NiceMock<MockSnapshotManager>();
1023 dynamicControl().snapshot_.reset(snapshot_); // takes ownership
1024 EXPECT_CALL(*snapshot_, BeginUpdate()).WillOnce(Return(true));
1025 EXPECT_CALL(*snapshot_, EnsureMetadataMounted())
1026 .WillRepeatedly(
1027 Invoke([]() { return std::make_unique<FakeAutoDevice>(); }));
1028
1029 manifest_ =
1030 PartitionSizesToManifest({{"system", 3_GiB}, {"vendor", 1_GiB}});
1031 }
ExpectCreateUpdateSnapshots(android::snapshot::Return val)1032 void ExpectCreateUpdateSnapshots(android::snapshot::Return val) {
1033 manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
1034 EXPECT_CALL(*snapshot_, CreateUpdateSnapshots(_))
1035 .WillRepeatedly(Invoke([&, val](const auto& manifest) {
1036 // Deep comparison requires full protobuf library. Comparing the
1037 // pointers are sufficient.
1038 EXPECT_EQ(&manifest_, &manifest);
1039 LOG(WARNING) << "CreateUpdateSnapshots returning " << val.string();
1040 return val;
1041 }));
1042 }
PreparePartitionsForUpdate(uint64_t * required_size)1043 bool PreparePartitionsForUpdate(uint64_t* required_size) {
1044 return dynamicControl().PreparePartitionsForUpdate(
1045 source(), target(), manifest_, true /* update */, required_size);
1046 }
1047 MockSnapshotManager* snapshot_ = nullptr;
1048 DeltaArchiveManifest manifest_;
1049 };
1050
1051 // Test happy path of PreparePartitionsForUpdate on a Virtual A/B device.
TEST_P(SnapshotPartitionTestP,PreparePartitions)1052 TEST_P(SnapshotPartitionTestP, PreparePartitions) {
1053 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1054 SetMetadata(source(), {});
1055 uint64_t required_size = 0;
1056 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1057 EXPECT_EQ(0u, required_size);
1058 }
1059
1060 // Test that if not enough space, required size returned by SnapshotManager is
1061 // passed up.
TEST_P(SnapshotPartitionTestP,PreparePartitionsNoSpace)1062 TEST_P(SnapshotPartitionTestP, PreparePartitionsNoSpace) {
1063 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1064 uint64_t required_size = 0;
1065
1066 SetMetadata(source(), {});
1067 EXPECT_FALSE(PreparePartitionsForUpdate(&required_size));
1068 EXPECT_EQ(1_GiB, required_size);
1069 }
1070
1071 // Test that in recovery, use empty space in super partition for a snapshot
1072 // update first.
TEST_P(SnapshotPartitionTestP,RecoveryUseSuperEmpty)1073 TEST_P(SnapshotPartitionTestP, RecoveryUseSuperEmpty) {
1074 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1075 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1076
1077 // Metadata is needed to perform super partition size check.
1078 SetMetadata(source(), {});
1079
1080 // Must not call PrepareDynamicPartitionsForUpdate if
1081 // PrepareSnapshotPartitionsForUpdate succeeds.
1082 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1083 .Times(0);
1084 uint64_t required_size = 0;
1085 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1086 EXPECT_EQ(0u, required_size);
1087 }
1088
1089 // Test that in recovery, if CreateUpdateSnapshots throws an error, try
1090 // the flashing path for full updates.
TEST_P(SnapshotPartitionTestP,RecoveryErrorShouldDeleteSource)1091 TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
1092 // Expectation on PreparePartitionsForUpdate
1093 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1094 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1095 EXPECT_CALL(*snapshot_, CancelUpdate()).WillOnce(Return(true));
1096 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1097 .WillRepeatedly(Invoke([&](auto source_slot,
1098 auto target_slot,
1099 const auto& manifest,
1100 auto delete_source) {
1101 EXPECT_EQ(source(), source_slot);
1102 EXPECT_EQ(target(), target_slot);
1103 // Deep comparison requires full protobuf library. Comparing the
1104 // pointers are sufficient.
1105 EXPECT_EQ(&manifest_, &manifest);
1106 EXPECT_TRUE(delete_source);
1107 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
1108 source_slot, target_slot, manifest, delete_source);
1109 }));
1110 // Only one slot of space in super
1111 uint64_t super_size = kDefaultGroupSize + 1_MiB;
1112 // Expectation on PrepareDynamicPartitionsForUpdate
1113 SetMetadata(
1114 source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size);
1115 ExpectUnmap({T("system"), T("vendor")});
1116 // Expect that the source partitions aren't present in target super
1117 // metadata.
1118 ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
1119
1120 uint64_t required_size = 0;
1121 EXPECT_TRUE(PreparePartitionsForUpdate(&required_size));
1122 EXPECT_EQ(0u, required_size);
1123 }
1124
1125 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
1126 SnapshotPartitionTestP,
1127 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
1128
1129 } // namespace chromeos_update_engine
1130