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 <set>
20
21 #include <base/logging.h>
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24 #include <libavb/libavb.h>
25 #include <libsnapshot/mock_snapshot.h>
26
27 #include "update_engine/aosp/boot_control_android.h"
28 #include "update_engine/aosp/dynamic_partition_test_utils.h"
29 #include "update_engine/aosp/mock_dynamic_partition_control_android.h"
30 #include "update_engine/common/mock_prefs.h"
31 #include "update_engine/common/test_utils.h"
32
33 using android::dm::DmDeviceState;
34 using android::snapshot::MockSnapshotManager;
35 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
36 using std::string;
37 using testing::_;
38 using testing::AnyNumber;
39 using testing::AnyOf;
40 using testing::AtLeast;
41 using testing::Invoke;
42 using testing::NiceMock;
43 using testing::Not;
44 using testing::Optional;
45 using testing::Return;
46
47 namespace chromeos_update_engine {
48
49 class DynamicPartitionControlAndroidTest : public ::testing::Test {
50 public:
SetUp()51 void SetUp() override {
52 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
53
54 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
55 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
56 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
57 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
58 ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
59 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
60 ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
61 .WillByDefault(Return(false));
62 ON_CALL(dynamicControl(), GetDeviceDir(_))
63 .WillByDefault(Invoke([](auto path) {
64 *path = kFakeDevicePath;
65 return true;
66 }));
67
68 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
69 .WillByDefault(Return(kFakeSuper));
70
71 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
72 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
73 *device = GetDmDevice(partition_name_suffix);
74 return true;
75 }));
76
77 ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
78 .WillByDefault(Return(true));
79
80 ON_CALL(dynamicControl(), IsRecovery()).WillByDefault(Return(false));
81
82 ON_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
83 .WillByDefault(Invoke([&](uint32_t source_slot,
84 uint32_t target_slot,
85 const DeltaArchiveManifest& manifest,
86 bool delete_source) {
87 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
88 source_slot, target_slot, manifest, delete_source);
89 }));
90 }
91
92 // Return the mocked DynamicPartitionControlInterface.
dynamicControl()93 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
94 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
95 }
96
GetSuperDevice(uint32_t slot)97 std::string GetSuperDevice(uint32_t slot) {
98 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
99 }
100
source()101 uint32_t source() { return slots_.source; }
target()102 uint32_t target() { return slots_.target; }
103
104 // Return partition names with suffix of source().
S(const std::string & name)105 std::string S(const std::string& name) {
106 return name + kSlotSuffixes[source()];
107 }
108
109 // Return partition names with suffix of target().
T(const std::string & name)110 std::string T(const std::string& name) {
111 return name + kSlotSuffixes[target()];
112 }
113
114 // Set the fake metadata to return when LoadMetadataBuilder is called on
115 // |slot|.
SetMetadata(uint32_t slot,const PartitionSuffixSizes & sizes,uint32_t partition_attr=0,uint64_t super_size=kDefaultSuperSize)116 void SetMetadata(uint32_t slot,
117 const PartitionSuffixSizes& sizes,
118 uint32_t partition_attr = 0,
119 uint64_t super_size = kDefaultSuperSize) {
120 EXPECT_CALL(dynamicControl(),
121 LoadMetadataBuilder(GetSuperDevice(slot), slot))
122 .Times(AnyNumber())
123 .WillRepeatedly(Invoke([=](auto, auto) {
124 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
125 partition_attr,
126 super_size);
127 }));
128
129 EXPECT_CALL(dynamicControl(),
130 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
131 .Times(AnyNumber())
132 .WillRepeatedly(Invoke([=](auto, auto, auto) {
133 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
134 partition_attr,
135 super_size);
136 }));
137 }
138
ExpectStoreMetadata(const PartitionSuffixSizes & partition_sizes)139 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
140 EXPECT_CALL(dynamicControl(),
141 StoreMetadata(GetSuperDevice(target()),
142 MetadataMatches(partition_sizes),
143 target()))
144 .WillOnce(Return(true));
145 }
146
147 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
148 // slot with each partition in |partitions|.
ExpectUnmap(const std::set<std::string> & partitions)149 void ExpectUnmap(const std::set<std::string>& partitions) {
150 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
151 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
152 .WillByDefault(Return(false));
153
154 for (const auto& partition : partitions) {
155 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
156 .WillOnce(Return(true));
157 }
158 }
PreparePartitionsForUpdate(const PartitionSizes & partition_sizes)159 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
160 return dynamicControl().PreparePartitionsForUpdate(
161 source(),
162 target(),
163 PartitionSizesToManifest(partition_sizes),
164 true,
165 nullptr,
166 nullptr);
167 }
SetSlots(const TestParam & slots)168 void SetSlots(const TestParam& slots) { slots_ = slots; }
169
SetSnapshotEnabled(bool enabled)170 void SetSnapshotEnabled(bool enabled) {
171 dynamicControl().target_supports_snapshot_ = enabled;
172 }
173
174 struct Listener : public ::testing::MatchResultListener {
Listenerchromeos_update_engine::DynamicPartitionControlAndroidTest::Listener175 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
176 };
177
UpdatePartitionMetadata(const PartitionSuffixSizes & source_metadata,const PartitionSizes & update_metadata,const PartitionSuffixSizes & expected)178 testing::AssertionResult UpdatePartitionMetadata(
179 const PartitionSuffixSizes& source_metadata,
180 const PartitionSizes& update_metadata,
181 const PartitionSuffixSizes& expected) {
182 return UpdatePartitionMetadata(
183 PartitionSuffixSizesToManifest(source_metadata),
184 PartitionSizesToManifest(update_metadata),
185 PartitionSuffixSizesToManifest(expected));
186 }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const DeltaArchiveManifest & expected)187 testing::AssertionResult UpdatePartitionMetadata(
188 const DeltaArchiveManifest& source_manifest,
189 const DeltaArchiveManifest& update_manifest,
190 const DeltaArchiveManifest& expected) {
191 return UpdatePartitionMetadata(
192 source_manifest, update_manifest, MetadataMatches(expected));
193 }
UpdatePartitionMetadata(const DeltaArchiveManifest & source_manifest,const DeltaArchiveManifest & update_manifest,const Matcher<MetadataBuilder * > & matcher)194 testing::AssertionResult UpdatePartitionMetadata(
195 const DeltaArchiveManifest& source_manifest,
196 const DeltaArchiveManifest& update_manifest,
197 const Matcher<MetadataBuilder*>& matcher) {
198 auto super_metadata = NewFakeMetadata(source_manifest);
199 if (!module_->UpdatePartitionMetadata(
200 super_metadata.get(), target(), update_manifest)) {
201 return testing::AssertionFailure()
202 << "UpdatePartitionMetadataInternal failed";
203 }
204 std::stringstream ss;
205 Listener listener(&ss);
206 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
207 return testing::AssertionSuccess() << ss.str();
208 } else {
209 return testing::AssertionFailure() << ss.str();
210 }
211 }
212
213 std::unique_ptr<DynamicPartitionControlAndroid> module_;
214 TestParam slots_{};
215 };
216
217 class DynamicPartitionControlAndroidTestP
218 : public DynamicPartitionControlAndroidTest,
219 public ::testing::WithParamInterface<TestParam> {
220 public:
SetUp()221 void SetUp() override {
222 DynamicPartitionControlAndroidTest::SetUp();
223 SetSlots(GetParam());
224 dynamicControl().SetSourceSlot(source());
225 dynamicControl().SetTargetSlot(target());
226 }
227 };
228
229 // Test resize case. Grow if target metadata contains a partition with a size
230 // less than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedGrowIfSizeNotMatchWhenResizing)231 TEST_P(DynamicPartitionControlAndroidTestP,
232 NeedGrowIfSizeNotMatchWhenResizing) {
233 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
234 {S("vendor"), 1_GiB},
235 {T("system"), 2_GiB},
236 {T("vendor"), 1_GiB}};
237 PartitionSuffixSizes expected{{S("system"), 2_GiB},
238 {S("vendor"), 1_GiB},
239 {T("system"), 3_GiB},
240 {T("vendor"), 1_GiB}};
241 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
242 ASSERT_TRUE(
243 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
244 }
245
246 // Test resize case. Shrink if target metadata contains a partition with a size
247 // greater than expected.
TEST_P(DynamicPartitionControlAndroidTestP,NeedShrinkIfSizeNotMatchWhenResizing)248 TEST_P(DynamicPartitionControlAndroidTestP,
249 NeedShrinkIfSizeNotMatchWhenResizing) {
250 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
251 {S("vendor"), 1_GiB},
252 {T("system"), 2_GiB},
253 {T("vendor"), 1_GiB}};
254 PartitionSuffixSizes expected{{S("system"), 2_GiB},
255 {S("vendor"), 1_GiB},
256 {T("system"), 2_GiB},
257 {T("vendor"), 150_MiB}};
258 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
259 ASSERT_TRUE(
260 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
261 }
262
263 // Test adding partitions on the first run.
TEST_P(DynamicPartitionControlAndroidTestP,AddPartitionToEmptyMetadata)264 TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
265 PartitionSuffixSizes source_metadata{};
266 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
267 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
268 ASSERT_TRUE(
269 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
270 }
271
272 // Test subsequent add case.
TEST_P(DynamicPartitionControlAndroidTestP,AddAdditionalPartition)273 TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
274 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
275 {T("system"), 2_GiB}};
276 PartitionSuffixSizes expected{
277 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
278 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
279 ASSERT_TRUE(
280 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
281 }
282
283 // Test delete one partition.
TEST_P(DynamicPartitionControlAndroidTestP,DeletePartition)284 TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
285 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
286 {S("vendor"), 1_GiB},
287 {T("system"), 2_GiB},
288 {T("vendor"), 1_GiB}};
289 // No T("vendor")
290 PartitionSuffixSizes expected{
291 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
292 PartitionSizes update_metadata{{"system", 2_GiB}};
293 ASSERT_TRUE(
294 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
295 }
296
297 // Test delete all partitions.
TEST_P(DynamicPartitionControlAndroidTestP,DeleteAll)298 TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
299 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
300 {S("vendor"), 1_GiB},
301 {T("system"), 2_GiB},
302 {T("vendor"), 1_GiB}};
303 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
304 PartitionSizes update_metadata{};
305 ASSERT_TRUE(
306 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
307 }
308
309 // Test corrupt source metadata case.
TEST_P(DynamicPartitionControlAndroidTestP,CorruptedSourceMetadata)310 TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
311 EXPECT_CALL(dynamicControl(),
312 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
313 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
314 ExpectUnmap({T("system")});
315
316 ASSERT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
317 << "Should not be able to continue with corrupt source metadata";
318 }
319
320 // Test that UpdatePartitionMetadata fails if there is not enough space on the
321 // device.
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpace)322 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
323 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
324 {S("vendor"), 2_GiB},
325 {T("system"), 0},
326 {T("vendor"), 0}};
327 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
328
329 ASSERT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
330 << "Should not be able to fit 11GiB data into 10GiB space";
331 }
332
TEST_P(DynamicPartitionControlAndroidTestP,NotEnoughSpaceForSlot)333 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
334 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
335 {S("vendor"), 1_GiB},
336 {T("system"), 0},
337 {T("vendor"), 0}};
338 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
339 ASSERT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
340 << "Should not be able to grow over size of super / 2";
341 }
342
TEST_P(DynamicPartitionControlAndroidTestP,ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild)343 TEST_P(DynamicPartitionControlAndroidTestP,
344 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
345 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
346 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
347 // Static partition {system,bar}_{a,b} exists.
348 EXPECT_CALL(dynamicControl(),
349 DeviceExists(AnyOf(GetDevice(S("bar")),
350 GetDevice(T("bar")),
351 GetDevice(S("system")),
352 GetDevice(T("system")))))
353 .WillRepeatedly(Return(true));
354
355 SetMetadata(source(),
356 {{S("system"), 2_GiB},
357 {S("vendor"), 1_GiB},
358 {T("system"), 2_GiB},
359 {T("vendor"), 1_GiB}});
360
361 // Not calling through
362 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
363 // don't want any default group in the PartitionMetadata.
364 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
365 source(), target(), {}, true, nullptr, nullptr));
366
367 // Should use dynamic source partitions.
368 EXPECT_CALL(dynamicControl(), GetState(S("system") + "_ota"))
369 .Times(1)
370 .WillOnce(Return(DmDeviceState::ACTIVE));
371 string system_device;
372 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
373 "system", source(), source(), &system_device));
374 ASSERT_EQ(GetDmDevice(S("system") + "_ota"), system_device);
375
376 // Should use static target partitions without querying dynamic control.
377 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
378 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
379 "system", target(), source(), &system_device));
380 ASSERT_EQ(GetDevice(T("system")), system_device);
381
382 // Static partition "bar".
383 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
384 std::string bar_device;
385 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
386 "bar", source(), source(), &bar_device));
387 ASSERT_EQ(GetDevice(S("bar")), bar_device);
388
389 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
390 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
391 "bar", target(), source(), &bar_device));
392 ASSERT_EQ(GetDevice(T("bar")), bar_device);
393 }
394
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePath)395 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePath) {
396 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
397 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
398 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
399 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
400 ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
401 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
402 ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
403 .WillByDefault(Return(false));
404 ON_CALL(dynamicControl(), IsDynamicPartition(_, _))
405 .WillByDefault(Return(true));
406
407 EXPECT_CALL(dynamicControl(),
408 DeviceExists(AnyOf(GetDevice(S("vendor")),
409 GetDevice(T("vendor")),
410 GetDevice(S("system")),
411 GetDevice(T("system")))))
412 .WillRepeatedly(Return(true));
413 EXPECT_CALL(dynamicControl(),
414 GetState(AnyOf(
415 S("vendor"), T("vendor"), S("system") + "_ota", T("system"))))
416 .WillRepeatedly(Return(DmDeviceState::ACTIVE));
417
418 SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
419 SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
420 std::string device;
421 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
422 "system", source(), source(), &device));
423 ASSERT_EQ(GetDmDevice(S("system") + "_ota"), device);
424
425 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
426 "system", target(), source(), &device));
427 ASSERT_EQ(GetDevice(T("system")), device);
428
429 // If VABC is disabled, mountable device path should be same as device path.
430 auto device_info =
431 dynamicControl().GetPartitionDevice("system", target(), source(), false);
432 ASSERT_TRUE(device_info.has_value());
433 ASSERT_EQ(device_info->readonly_device_path, device);
434 }
435
TEST_P(DynamicPartitionControlAndroidTestP,GetMountableDevicePathVABC)436 TEST_P(DynamicPartitionControlAndroidTestP, GetMountableDevicePathVABC) {
437 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
438 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
439 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
440 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
441 ON_CALL(dynamicControl(), GetVirtualAbCompressionFeatureFlag())
442 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
443 ON_CALL(dynamicControl(), UpdateUsesSnapshotCompression())
444 .WillByDefault(Return(true));
445 EXPECT_CALL(dynamicControl(), IsDynamicPartition(_, _))
446 .Times(AtLeast(1))
447 .WillRepeatedly(Return(true));
448
449 EXPECT_CALL(dynamicControl(),
450 DeviceExists(AnyOf(GetDevice(S("vendor")),
451 GetDevice(T("vendor")),
452 GetDevice(S("system")),
453 GetDevice(T("system")))))
454 .WillRepeatedly(Return(true));
455 EXPECT_CALL(dynamicControl(),
456 GetState(AnyOf(
457 S("vendor"), T("vendor"), S("system") + "_ota", T("system"))))
458 .WillRepeatedly(Return(DmDeviceState::ACTIVE));
459
460 SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
461 SetMetadata(target(), {{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
462
463 std::string device;
464 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
465 "system", source(), source(), &device));
466 ASSERT_EQ(GetDmDevice(S("system") + "_ota"), device);
467
468 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
469 "system", target(), source(), &device));
470 ASSERT_EQ("", device);
471
472 auto device_info =
473 dynamicControl().GetPartitionDevice("system", target(), source(), false);
474 ASSERT_TRUE(device_info.has_value());
475 base::FilePath vabc_device_dir{
476 std::string{DynamicPartitionControlAndroid::VABC_DEVICE_DIR}};
477 ASSERT_EQ(device_info->readonly_device_path,
478 vabc_device_dir.Append(T("system")).value());
479 }
480
TEST_P(DynamicPartitionControlAndroidTestP,GetPartitionDeviceWhenResumingUpdate)481 TEST_P(DynamicPartitionControlAndroidTestP,
482 GetPartitionDeviceWhenResumingUpdate) {
483 // Static partition bar_{a,b} exists.
484 EXPECT_CALL(dynamicControl(),
485 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
486 .WillRepeatedly(Return(true));
487
488 // Both of the two slots contain valid partition metadata, since this is
489 // resuming an update.
490 SetMetadata(source(),
491 {{S("system"), 2_GiB},
492 {S("vendor"), 1_GiB},
493 {T("system"), 2_GiB},
494 {T("vendor"), 1_GiB}});
495 SetMetadata(target(),
496 {{S("system"), 2_GiB},
497 {S("vendor"), 1_GiB},
498 {T("system"), 2_GiB},
499 {T("vendor"), 1_GiB}});
500
501 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate(
502 source(),
503 target(),
504 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
505 false,
506 nullptr,
507 nullptr));
508
509 // Dynamic partition "system".
510 EXPECT_CALL(dynamicControl(), GetState(S("system") + "_ota"))
511 .Times(1)
512 .WillOnce(Return(DmDeviceState::ACTIVE));
513 string system_device;
514 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
515 "system", source(), source(), &system_device));
516 ASSERT_EQ(GetDmDevice(S("system") + "_ota"), 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 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
531 "system", target(), source(), &system_device));
532 ASSERT_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 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
538 "bar", source(), source(), &bar_device));
539 ASSERT_EQ(GetDevice(S("bar")), bar_device);
540
541 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
542 ASSERT_TRUE(dynamicControl().GetPartitionDevice(
543 "bar", target(), source(), &bar_device));
544 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 ASSERT_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 nullptr));
764 dynamicControl().set_fake_mapped_devices({T("foo")});
765
766 InstallOperation iop;
767 InstallOperation optimized;
768 Extent *se{}, *de{};
769
770 // Not a SOURCE_COPY operation, cannot skip.
771 iop.set_type(InstallOperation::REPLACE);
772 ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
773
774 iop.set_type(InstallOperation::SOURCE_COPY);
775
776 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation.
777 ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
778
779 // Enable GetVirtualAbFeatureFlag in the mock interface.
780 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
781 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
782
783 // By default target_supports_snapshot_ is set to false. Cannot skip
784 // operation.
785 ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
786
787 SetSnapshotEnabled(true);
788
789 // Empty source and destination. Skip.
790 ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
791 ASSERT_TRUE(optimized.src_extents().empty());
792 ASSERT_TRUE(optimized.dst_extents().empty());
793
794 se = iop.add_src_extents();
795 se->set_start_block(0);
796 se->set_num_blocks(1);
797
798 // There is something in sources, but destinations are empty. Cannot skip.
799 ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
800
801 InstallOperation iop2;
802
803 de = iop2.add_dst_extents();
804 de->set_start_block(0);
805 de->set_num_blocks(1);
806
807 // There is something in destinations, but sources are empty. Cannot skip.
808 ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized));
809
810 de = iop.add_dst_extents();
811 de->set_start_block(0);
812 de->set_num_blocks(1);
813
814 // Sources and destinations are identical. Skip.
815 ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
816 ASSERT_TRUE(optimized.src_extents().empty());
817 ASSERT_TRUE(optimized.dst_extents().empty());
818
819 se = iop.add_src_extents();
820 se->set_start_block(1);
821 se->set_num_blocks(5);
822
823 // There is something in source, but not in destination. Cannot skip.
824 ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
825
826 de = iop.add_dst_extents();
827 de->set_start_block(1);
828 de->set_num_blocks(5);
829
830 // There is source and destination are equal. Skip.
831 ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
832 ASSERT_TRUE(optimized.src_extents().empty());
833 ASSERT_TRUE(optimized.dst_extents().empty());
834
835 de = iop.add_dst_extents();
836 de->set_start_block(6);
837 de->set_num_blocks(5);
838
839 // There is something extra in dest. Cannot skip.
840 ASSERT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
841
842 se = iop.add_src_extents();
843 se->set_start_block(6);
844 se->set_num_blocks(5);
845
846 // Source and dest are identical again. Skip.
847 ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
848 ASSERT_TRUE(optimized.src_extents().empty());
849 ASSERT_TRUE(optimized.dst_extents().empty());
850
851 iop.Clear();
852 iop.set_type(InstallOperation::SOURCE_COPY);
853 se = iop.add_src_extents();
854 se->set_start_block(1);
855 se->set_num_blocks(1);
856 se = iop.add_src_extents();
857 se->set_start_block(3);
858 se->set_num_blocks(2);
859 se = iop.add_src_extents();
860 se->set_start_block(7);
861 se->set_num_blocks(2);
862 de = iop.add_dst_extents();
863 de->set_start_block(2);
864 de->set_num_blocks(5);
865
866 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6]
867 ASSERT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized));
868 ASSERT_EQ(2, optimized.src_extents_size());
869 ASSERT_EQ(2, optimized.dst_extents_size());
870 ASSERT_EQ(1u, optimized.src_extents(0).start_block());
871 ASSERT_EQ(1u, optimized.src_extents(0).num_blocks());
872 ASSERT_EQ(2u, optimized.dst_extents(0).start_block());
873 ASSERT_EQ(1u, optimized.dst_extents(0).num_blocks());
874 ASSERT_EQ(7u, optimized.src_extents(1).start_block());
875 ASSERT_EQ(2u, optimized.src_extents(1).num_blocks());
876 ASSERT_EQ(5u, optimized.dst_extents(1).start_block());
877 ASSERT_EQ(2u, optimized.dst_extents(1).num_blocks());
878
879 // Don't skip for static partitions.
880 ASSERT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized));
881 }
882
TEST_F(DynamicPartitionControlAndroidTest,ResetUpdate)883 TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
884 MockPrefs prefs;
885 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
886 }
887
TEST_F(DynamicPartitionControlAndroidTest,IsAvbNotEnabledInFstab)888 TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
889 std::string fstab_content =
890 "system /postinstall ext4 ro,nosuid,nodev,noexec "
891 "slotselect_other,logical\n"
892 "/dev/block/by-name/system /postinstall ext4 "
893 "ro,nosuid,nodev,noexec slotselect_other\n";
894 ScopedTempFile fstab;
895 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
896 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
897 Optional(false));
898 }
899
TEST_F(DynamicPartitionControlAndroidTest,IsAvbEnabledInFstab)900 TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
901 std::string fstab_content =
902 "system /postinstall ext4 ro,nosuid,nodev,noexec "
903 "slotselect_other,logical,avb_keys=/foo\n";
904 ScopedTempFile fstab;
905 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
906 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
907 Optional(true));
908 }
909
TEST_P(DynamicPartitionControlAndroidTestP,AvbNotEnabledOnSystemOther)910 TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
911 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
912 .WillByDefault(Invoke([&](auto source_slot,
913 auto target_slot,
914 const auto& name,
915 auto path,
916 auto should_unmap) {
917 return dynamicControl().RealGetSystemOtherPath(
918 source_slot, target_slot, name, path, should_unmap);
919 }));
920 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
921 .WillByDefault(Return(false));
922 ASSERT_TRUE(
923 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
924 }
925
TEST_P(DynamicPartitionControlAndroidTestP,NoSystemOtherToErase)926 TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
927 SetMetadata(source(), {{S("system"), 100_MiB}});
928 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
929 .WillByDefault(Return(true));
930 std::string path;
931 bool should_unmap{};
932 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
933 source(), target(), T("system"), &path, &should_unmap));
934 ASSERT_TRUE(path.empty()) << path;
935 ASSERT_FALSE(should_unmap);
936 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
937 .WillByDefault(Invoke([&](auto source_slot,
938 auto target_slot,
939 const auto& name,
940 auto path,
941 auto should_unmap) {
942 return dynamicControl().RealGetSystemOtherPath(
943 source_slot, target_slot, name, path, should_unmap);
944 }));
945 ASSERT_TRUE(
946 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
947 }
948
TEST_P(DynamicPartitionControlAndroidTestP,SkipEraseUpdatedSystemOther)949 TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
950 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
951 SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
952 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
953 .WillByDefault(Return(true));
954 std::string path;
955 bool should_unmap{};
956 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
957 source(), target(), T("system"), &path, &should_unmap));
958 ASSERT_TRUE(path.empty()) << path;
959 ASSERT_FALSE(should_unmap);
960 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
961 .WillByDefault(Invoke([&](auto source_slot,
962 auto target_slot,
963 const auto& name,
964 auto path,
965 auto should_unmap) {
966 return dynamicControl().RealGetSystemOtherPath(
967 source_slot, target_slot, name, path, should_unmap);
968 }));
969 ASSERT_TRUE(
970 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
971 }
972
TEST_P(DynamicPartitionControlAndroidTestP,EraseSystemOtherAvbFooter)973 TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
974 constexpr uint64_t file_size = 1_MiB;
975 static_assert(file_size > AVB_FOOTER_SIZE);
976 ScopedTempFile system_other;
977 brillo::Blob original(file_size, 'X');
978 ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
979 std::string mnt_path;
980 ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
981 ASSERT_TRUE(dev.is_bound());
982
983 brillo::Blob device_content;
984 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
985 ASSERT_EQ(original, device_content);
986
987 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
988 SetMetadata(source(), sizes);
989 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
990 .WillByDefault(Return(true));
991 EXPECT_CALL(dynamicControl(),
992 GetSystemOtherPath(source(), target(), T("system"), _, _))
993 .WillRepeatedly(
994 Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
995 *path = mnt_path;
996 *should_unmap = false;
997 return true;
998 }));
999 ASSERT_TRUE(
1000 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
1001
1002 device_content.clear();
1003 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
1004 brillo::Blob new_expected(original);
1005 // Clear the last AVB_FOOTER_SIZE bytes.
1006 new_expected.resize(file_size - AVB_FOOTER_SIZE);
1007 new_expected.resize(file_size, '\0');
1008 ASSERT_EQ(new_expected, device_content);
1009 }
1010
1011 class FakeAutoDevice : public android::snapshot::AutoDevice {
1012 public:
FakeAutoDevice()1013 FakeAutoDevice() : AutoDevice("") {}
1014 };
1015
1016 class SnapshotPartitionTestP : public DynamicPartitionControlAndroidTestP {
1017 public:
SetUp()1018 void SetUp() override {
1019 DynamicPartitionControlAndroidTestP::SetUp();
1020 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
1021 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
1022
1023 snapshot_ = new NiceMock<MockSnapshotManager>();
1024 dynamicControl().snapshot_.reset(snapshot_); // takes ownership
1025 EXPECT_CALL(*snapshot_, BeginUpdate()).WillOnce(Return(true));
1026 EXPECT_CALL(*snapshot_, EnsureMetadataMounted())
1027 .WillRepeatedly(
1028 Invoke([]() { return std::make_unique<FakeAutoDevice>(); }));
1029
1030 manifest_ =
1031 PartitionSizesToManifest({{"system", 3_GiB}, {"vendor", 1_GiB}});
1032 }
ExpectCreateUpdateSnapshots(android::snapshot::Return val)1033 void ExpectCreateUpdateSnapshots(android::snapshot::Return val) {
1034 manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
1035 EXPECT_CALL(*snapshot_, CreateUpdateSnapshots(_))
1036 .WillRepeatedly(Invoke([&, val](const auto& manifest) {
1037 // Deep comparison requires full protobuf library. Comparing the
1038 // pointers are sufficient.
1039 EXPECT_EQ(&manifest_, &manifest);
1040 LOG(WARNING) << "CreateUpdateSnapshots returning " << val.string();
1041 return val;
1042 }));
1043 }
PreparePartitionsForUpdate(uint64_t * required_size)1044 bool PreparePartitionsForUpdate(uint64_t* required_size) {
1045 return dynamicControl().PreparePartitionsForUpdate(source(),
1046 target(),
1047 manifest_,
1048 true /* update */,
1049 required_size,
1050 nullptr);
1051 }
1052 MockSnapshotManager* snapshot_ = nullptr;
1053 DeltaArchiveManifest manifest_;
1054 };
1055
1056 // Test happy path of PreparePartitionsForUpdate on a Virtual A/B device.
TEST_P(SnapshotPartitionTestP,PreparePartitions)1057 TEST_P(SnapshotPartitionTestP, PreparePartitions) {
1058 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1059 SetMetadata(source(), {});
1060 uint64_t required_size = 0;
1061 ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
1062 ASSERT_EQ(0u, required_size);
1063 }
1064
1065 // Test that if not enough space, required size returned by SnapshotManager is
1066 // passed up.
TEST_P(SnapshotPartitionTestP,PreparePartitionsNoSpace)1067 TEST_P(SnapshotPartitionTestP, PreparePartitionsNoSpace) {
1068 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1069 uint64_t required_size = 0;
1070
1071 SetMetadata(source(), {});
1072 ASSERT_FALSE(PreparePartitionsForUpdate(&required_size));
1073 ASSERT_EQ(1_GiB, required_size);
1074 }
1075
1076 // Test that in recovery, use empty space in super partition for a snapshot
1077 // update first.
TEST_P(SnapshotPartitionTestP,RecoveryUseSuperEmpty)1078 TEST_P(SnapshotPartitionTestP, RecoveryUseSuperEmpty) {
1079 ExpectCreateUpdateSnapshots(android::snapshot::Return::Ok());
1080 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1081
1082 // Metadata is needed to perform super partition size check.
1083 SetMetadata(source(), {});
1084
1085 // Must not call PrepareDynamicPartitionsForUpdate if
1086 // PrepareSnapshotPartitionsForUpdate succeeds.
1087 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1088 .Times(0);
1089 uint64_t required_size = 0;
1090 ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
1091 ASSERT_EQ(0u, required_size);
1092 }
1093
1094 // Test that in recovery, if CreateUpdateSnapshots throws an error, try
1095 // the flashing path for full updates.
TEST_P(SnapshotPartitionTestP,RecoveryErrorShouldDeleteSource)1096 TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) {
1097 // Expectation on PreparePartitionsForUpdate
1098 ExpectCreateUpdateSnapshots(android::snapshot::Return::NoSpace(1_GiB));
1099 EXPECT_CALL(dynamicControl(), IsRecovery()).WillRepeatedly(Return(true));
1100 EXPECT_CALL(*snapshot_, CancelUpdate()).WillOnce(Return(true));
1101 EXPECT_CALL(dynamicControl(), PrepareDynamicPartitionsForUpdate(_, _, _, _))
1102 .WillRepeatedly(Invoke([&](auto source_slot,
1103 auto target_slot,
1104 const auto& manifest,
1105 auto delete_source) {
1106 EXPECT_EQ(source(), source_slot);
1107 EXPECT_EQ(target(), target_slot);
1108 // Deep comparison requires full protobuf library. Comparing the
1109 // pointers are sufficient.
1110 EXPECT_EQ(&manifest_, &manifest);
1111 EXPECT_TRUE(delete_source);
1112 return dynamicControl().RealPrepareDynamicPartitionsForUpdate(
1113 source_slot, target_slot, manifest, delete_source);
1114 }));
1115 // Only one slot of space in super
1116 uint64_t super_size = kDefaultGroupSize + 1_MiB;
1117 // Expectation on PrepareDynamicPartitionsForUpdate
1118 SetMetadata(
1119 source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size);
1120 ExpectUnmap({T("system"), T("vendor")});
1121 // Expect that the source partitions aren't present in target super
1122 // metadata.
1123 ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}});
1124
1125 uint64_t required_size = 0;
1126 ASSERT_TRUE(PreparePartitionsForUpdate(&required_size));
1127 ASSERT_EQ(0u, required_size);
1128 }
1129
1130 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
1131 SnapshotPartitionTestP,
1132 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
1133
TEST(SourcePartitionTest,MapSourceWritable)1134 TEST(SourcePartitionTest, MapSourceWritable) {
1135 BootControlAndroid boot_control;
1136 ASSERT_TRUE(boot_control.Init());
1137 auto source_slot = boot_control.GetCurrentSlot();
1138 DynamicPartitionControlAndroid dynamic_control(source_slot);
1139 std::string device;
1140 ASSERT_TRUE(dynamic_control.GetPartitionDevice(
1141 "system", source_slot, source_slot, &device));
1142 android::base::unique_fd fd(open(device.c_str(), O_RDWR | O_CLOEXEC));
1143 ASSERT_TRUE(utils::SetBlockDeviceReadOnly(device, false));
1144 ASSERT_GE(fd, 0) << android::base::ErrnoNumberAsString(errno);
1145 std::array<char, 512> block{};
1146 ASSERT_EQ(pread(fd.get(), block.data(), block.size(), 0),
1147 (ssize_t)block.size())
1148 << android::base::ErrnoNumberAsString(errno);
1149 ASSERT_EQ(pwrite(fd.get(), block.data(), block.size(), 0),
1150 (ssize_t)block.size())
1151 << android::base::ErrnoNumberAsString(errno);
1152 }
1153
1154 } // namespace chromeos_update_engine
1155