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/dynamic_partition_control_android.h" 18 19 #include <set> 20 #include <vector> 21 22 #include <base/logging.h> 23 #include <base/strings/string_util.h> 24 #include <gmock/gmock.h> 25 #include <gtest/gtest.h> 26 #include <libavb/libavb.h> 27 28 #include "update_engine/common/mock_prefs.h" 29 #include "update_engine/common/test_utils.h" 30 #include "update_engine/dynamic_partition_test_utils.h" 31 #include "update_engine/mock_dynamic_partition_control.h" 32 33 using android::dm::DmDeviceState; 34 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder; 35 using chromeos_update_engine::test_utils::ScopedTempFile; 36 using std::string; 37 using testing::_; 38 using testing::AnyNumber; 39 using testing::AnyOf; 40 using testing::Invoke; 41 using testing::NiceMock; 42 using testing::Not; 43 using testing::Optional; 44 using testing::Return; 45 46 namespace chromeos_update_engine { 47 48 class DynamicPartitionControlAndroidTest : public ::testing::Test { 49 public: 50 void SetUp() override { 51 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>(); 52 53 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag()) 54 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH))); 55 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag()) 56 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE))); 57 58 ON_CALL(dynamicControl(), GetDeviceDir(_)) 59 .WillByDefault(Invoke([](auto path) { 60 *path = kFakeDevicePath; 61 return true; 62 })); 63 64 ON_CALL(dynamicControl(), GetSuperPartitionName(_)) 65 .WillByDefault(Return(kFakeSuper)); 66 67 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _)) 68 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) { 69 *device = GetDmDevice(partition_name_suffix); 70 return true; 71 })); 72 73 ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _)) 74 .WillByDefault(Return(true)); 75 } 76 77 // Return the mocked DynamicPartitionControlInterface. 78 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() { 79 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_); 80 } 81 82 std::string GetSuperDevice(uint32_t slot) { 83 return GetDevice(dynamicControl().GetSuperPartitionName(slot)); 84 } 85 86 uint32_t source() { return slots_.source; } 87 uint32_t target() { return slots_.target; } 88 89 // Return partition names with suffix of source(). 90 std::string S(const std::string& name) { 91 return name + kSlotSuffixes[source()]; 92 } 93 94 // Return partition names with suffix of target(). 95 std::string T(const std::string& name) { 96 return name + kSlotSuffixes[target()]; 97 } 98 99 // Set the fake metadata to return when LoadMetadataBuilder is called on 100 // |slot|. 101 void SetMetadata(uint32_t slot, 102 const PartitionSuffixSizes& sizes, 103 uint32_t partition_attr = 0) { 104 EXPECT_CALL(dynamicControl(), 105 LoadMetadataBuilder(GetSuperDevice(slot), slot, _)) 106 .Times(AnyNumber()) 107 .WillRepeatedly(Invoke([sizes, partition_attr](auto, auto, auto) { 108 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes), 109 partition_attr); 110 })); 111 } 112 113 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) { 114 EXPECT_CALL(dynamicControl(), 115 StoreMetadata(GetSuperDevice(target()), 116 MetadataMatches(partition_sizes), 117 target())) 118 .WillOnce(Return(true)); 119 } 120 121 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata 122 // slot with each partition in |partitions|. 123 void ExpectUnmap(const std::set<std::string>& partitions) { 124 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments. 125 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_)) 126 .WillByDefault(Return(false)); 127 128 for (const auto& partition : partitions) { 129 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition)) 130 .WillOnce(Return(true)); 131 } 132 } 133 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) { 134 return dynamicControl().PreparePartitionsForUpdate( 135 source(), 136 target(), 137 PartitionSizesToManifest(partition_sizes), 138 true, 139 nullptr); 140 } 141 void SetSlots(const TestParam& slots) { slots_ = slots; } 142 143 void SetSnapshotEnabled(bool enabled) { 144 dynamicControl().target_supports_snapshot_ = enabled; 145 } 146 147 struct Listener : public ::testing::MatchResultListener { 148 explicit Listener(std::ostream* os) : MatchResultListener(os) {} 149 }; 150 151 testing::AssertionResult UpdatePartitionMetadata( 152 const PartitionSuffixSizes& source_metadata, 153 const PartitionSizes& update_metadata, 154 const PartitionSuffixSizes& expected) { 155 return UpdatePartitionMetadata( 156 PartitionSuffixSizesToManifest(source_metadata), 157 PartitionSizesToManifest(update_metadata), 158 PartitionSuffixSizesToManifest(expected)); 159 } 160 testing::AssertionResult UpdatePartitionMetadata( 161 const DeltaArchiveManifest& source_manifest, 162 const DeltaArchiveManifest& update_manifest, 163 const DeltaArchiveManifest& expected) { 164 return UpdatePartitionMetadata( 165 source_manifest, update_manifest, MetadataMatches(expected)); 166 } 167 testing::AssertionResult UpdatePartitionMetadata( 168 const DeltaArchiveManifest& source_manifest, 169 const DeltaArchiveManifest& update_manifest, 170 const Matcher<MetadataBuilder*>& matcher) { 171 auto super_metadata = NewFakeMetadata(source_manifest); 172 if (!module_->UpdatePartitionMetadata( 173 super_metadata.get(), target(), update_manifest)) { 174 return testing::AssertionFailure() 175 << "UpdatePartitionMetadataInternal failed"; 176 } 177 std::stringstream ss; 178 Listener listener(&ss); 179 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) { 180 return testing::AssertionSuccess() << ss.str(); 181 } else { 182 return testing::AssertionFailure() << ss.str(); 183 } 184 } 185 186 std::unique_ptr<DynamicPartitionControlAndroid> module_; 187 TestParam slots_; 188 }; 189 190 class DynamicPartitionControlAndroidTestP 191 : public DynamicPartitionControlAndroidTest, 192 public ::testing::WithParamInterface<TestParam> { 193 public: 194 void SetUp() override { 195 DynamicPartitionControlAndroidTest::SetUp(); 196 SetSlots(GetParam()); 197 } 198 }; 199 200 // Test resize case. Grow if target metadata contains a partition with a size 201 // less than expected. 202 TEST_P(DynamicPartitionControlAndroidTestP, 203 NeedGrowIfSizeNotMatchWhenResizing) { 204 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB}, 205 {S("vendor"), 1_GiB}, 206 {T("system"), 2_GiB}, 207 {T("vendor"), 1_GiB}}; 208 PartitionSuffixSizes expected{{S("system"), 2_GiB}, 209 {S("vendor"), 1_GiB}, 210 {T("system"), 3_GiB}, 211 {T("vendor"), 1_GiB}}; 212 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}}; 213 EXPECT_TRUE( 214 UpdatePartitionMetadata(source_metadata, update_metadata, expected)); 215 } 216 217 // Test resize case. Shrink if target metadata contains a partition with a size 218 // greater than expected. 219 TEST_P(DynamicPartitionControlAndroidTestP, 220 NeedShrinkIfSizeNotMatchWhenResizing) { 221 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB}, 222 {S("vendor"), 1_GiB}, 223 {T("system"), 2_GiB}, 224 {T("vendor"), 1_GiB}}; 225 PartitionSuffixSizes expected{{S("system"), 2_GiB}, 226 {S("vendor"), 1_GiB}, 227 {T("system"), 2_GiB}, 228 {T("vendor"), 150_MiB}}; 229 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}}; 230 EXPECT_TRUE( 231 UpdatePartitionMetadata(source_metadata, update_metadata, expected)); 232 } 233 234 // Test adding partitions on the first run. 235 TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) { 236 PartitionSuffixSizes source_metadata{}; 237 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}}; 238 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}}; 239 EXPECT_TRUE( 240 UpdatePartitionMetadata(source_metadata, update_metadata, expected)); 241 } 242 243 // Test subsequent add case. 244 TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) { 245 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB}, 246 {T("system"), 2_GiB}}; 247 PartitionSuffixSizes expected{ 248 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}}; 249 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}}; 250 EXPECT_TRUE( 251 UpdatePartitionMetadata(source_metadata, update_metadata, expected)); 252 } 253 254 // Test delete one partition. 255 TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) { 256 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB}, 257 {S("vendor"), 1_GiB}, 258 {T("system"), 2_GiB}, 259 {T("vendor"), 1_GiB}}; 260 // No T("vendor") 261 PartitionSuffixSizes expected{ 262 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}}; 263 PartitionSizes update_metadata{{"system", 2_GiB}}; 264 EXPECT_TRUE( 265 UpdatePartitionMetadata(source_metadata, update_metadata, expected)); 266 } 267 268 // Test delete all partitions. 269 TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) { 270 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB}, 271 {S("vendor"), 1_GiB}, 272 {T("system"), 2_GiB}, 273 {T("vendor"), 1_GiB}}; 274 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}; 275 PartitionSizes update_metadata{}; 276 EXPECT_TRUE( 277 UpdatePartitionMetadata(source_metadata, update_metadata, expected)); 278 } 279 280 // Test corrupt source metadata case. 281 TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) { 282 EXPECT_CALL(dynamicControl(), 283 LoadMetadataBuilder(GetSuperDevice(source()), source(), _)) 284 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; })); 285 ExpectUnmap({T("system")}); 286 287 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}})) 288 << "Should not be able to continue with corrupt source metadata"; 289 } 290 291 // Test that UpdatePartitionMetadata fails if there is not enough space on the 292 // device. 293 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) { 294 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB}, 295 {S("vendor"), 2_GiB}, 296 {T("system"), 0}, 297 {T("vendor"), 0}}; 298 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}}; 299 300 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {})) 301 << "Should not be able to fit 11GiB data into 10GiB space"; 302 } 303 304 TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) { 305 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB}, 306 {S("vendor"), 1_GiB}, 307 {T("system"), 0}, 308 {T("vendor"), 0}}; 309 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}}; 310 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {})) 311 << "Should not be able to grow over size of super / 2"; 312 } 313 314 TEST_P(DynamicPartitionControlAndroidTestP, 315 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) { 316 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag()) 317 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT))); 318 // Static partition {system,bar}_{a,b} exists. 319 EXPECT_CALL(dynamicControl(), 320 DeviceExists(AnyOf(GetDevice(S("bar")), 321 GetDevice(T("bar")), 322 GetDevice(S("system")), 323 GetDevice(T("system"))))) 324 .WillRepeatedly(Return(true)); 325 326 SetMetadata(source(), 327 {{S("system"), 2_GiB}, 328 {S("vendor"), 1_GiB}, 329 {T("system"), 2_GiB}, 330 {T("vendor"), 1_GiB}}); 331 332 // Not calling through 333 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we 334 // don't want any default group in the PartitionMetadata. 335 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate( 336 source(), target(), {}, true, nullptr)); 337 338 // Should use dynamic source partitions. 339 EXPECT_CALL(dynamicControl(), GetState(S("system"))) 340 .Times(1) 341 .WillOnce(Return(DmDeviceState::ACTIVE)); 342 string system_device; 343 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 344 "system", source(), source(), &system_device)); 345 EXPECT_EQ(GetDmDevice(S("system")), system_device); 346 347 // Should use static target partitions without querying dynamic control. 348 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0); 349 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 350 "system", target(), source(), &system_device)); 351 EXPECT_EQ(GetDevice(T("system")), system_device); 352 353 // Static partition "bar". 354 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0); 355 std::string bar_device; 356 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 357 "bar", source(), source(), &bar_device)); 358 EXPECT_EQ(GetDevice(S("bar")), bar_device); 359 360 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0); 361 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 362 "bar", target(), source(), &bar_device)); 363 EXPECT_EQ(GetDevice(T("bar")), bar_device); 364 } 365 366 TEST_P(DynamicPartitionControlAndroidTestP, 367 GetPartitionDeviceWhenResumingUpdate) { 368 // Static partition bar_{a,b} exists. 369 EXPECT_CALL(dynamicControl(), 370 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar"))))) 371 .WillRepeatedly(Return(true)); 372 373 // Both of the two slots contain valid partition metadata, since this is 374 // resuming an update. 375 SetMetadata(source(), 376 {{S("system"), 2_GiB}, 377 {S("vendor"), 1_GiB}, 378 {T("system"), 2_GiB}, 379 {T("vendor"), 1_GiB}}); 380 SetMetadata(target(), 381 {{S("system"), 2_GiB}, 382 {S("vendor"), 1_GiB}, 383 {T("system"), 2_GiB}, 384 {T("vendor"), 1_GiB}}); 385 386 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate( 387 source(), 388 target(), 389 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}), 390 false, 391 nullptr)); 392 393 // Dynamic partition "system". 394 EXPECT_CALL(dynamicControl(), GetState(S("system"))) 395 .Times(1) 396 .WillOnce(Return(DmDeviceState::ACTIVE)); 397 string system_device; 398 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 399 "system", source(), source(), &system_device)); 400 EXPECT_EQ(GetDmDevice(S("system")), system_device); 401 402 EXPECT_CALL(dynamicControl(), GetState(T("system"))) 403 .Times(AnyNumber()) 404 .WillOnce(Return(DmDeviceState::ACTIVE)); 405 EXPECT_CALL(dynamicControl(), 406 MapPartitionOnDeviceMapper( 407 GetSuperDevice(target()), T("system"), target(), _, _)) 408 .Times(AnyNumber()) 409 .WillRepeatedly( 410 Invoke([](const auto&, const auto& name, auto, auto, auto* device) { 411 *device = "/fake/remapped/" + name; 412 return true; 413 })); 414 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 415 "system", target(), source(), &system_device)); 416 EXPECT_EQ("/fake/remapped/" + T("system"), system_device); 417 418 // Static partition "bar". 419 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0); 420 std::string bar_device; 421 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 422 "bar", source(), source(), &bar_device)); 423 EXPECT_EQ(GetDevice(S("bar")), bar_device); 424 425 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0); 426 EXPECT_TRUE(dynamicControl().GetPartitionDevice( 427 "bar", target(), source(), &bar_device)); 428 EXPECT_EQ(GetDevice(T("bar")), bar_device); 429 } 430 431 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest, 432 DynamicPartitionControlAndroidTestP, 433 testing::Values(TestParam{0, 1}, TestParam{1, 0})); 434 435 class DynamicPartitionControlAndroidGroupTestP 436 : public DynamicPartitionControlAndroidTestP { 437 public: 438 DeltaArchiveManifest source_manifest; 439 void SetUp() override { 440 DynamicPartitionControlAndroidTestP::SetUp(); 441 AddGroupAndPartition( 442 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB); 443 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB); 444 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0); 445 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0); 446 } 447 448 void AddGroupAndPartition(DeltaArchiveManifest* manifest, 449 const string& group, 450 uint64_t group_size, 451 const string& partition, 452 uint64_t partition_size) { 453 auto* g = AddGroup(manifest, group, group_size); 454 AddPartition(manifest, g, partition, partition_size); 455 } 456 }; 457 458 // Allow to resize within group. 459 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) { 460 DeltaArchiveManifest expected; 461 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB); 462 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB); 463 464 DeltaArchiveManifest update_manifest; 465 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB); 466 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB); 467 468 EXPECT_TRUE( 469 UpdatePartitionMetadata(source_manifest, update_manifest, expected)); 470 } 471 472 TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) { 473 DeltaArchiveManifest update_manifest; 474 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB), 475 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB); 476 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {})) 477 << "Should not be able to grow over maximum size of group"; 478 } 479 480 TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) { 481 DeltaArchiveManifest update_manifest; 482 AddGroup(&update_manifest, "android", 3_GiB); 483 AddGroup(&update_manifest, "oem", 3_GiB); 484 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {})) 485 << "Should not be able to grow over size of super / 2"; 486 } 487 488 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) { 489 DeltaArchiveManifest expected; 490 auto* g = AddGroup(&expected, T("android"), 3_GiB); 491 AddPartition(&expected, g, T("system"), 2_GiB); 492 AddPartition(&expected, g, T("system_ext"), 1_GiB); 493 494 DeltaArchiveManifest update_manifest; 495 g = AddGroup(&update_manifest, "android", 3_GiB); 496 AddPartition(&update_manifest, g, "system", 2_GiB); 497 AddPartition(&update_manifest, g, "system_ext", 1_GiB); 498 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB); 499 500 EXPECT_TRUE( 501 UpdatePartitionMetadata(source_manifest, update_manifest, expected)); 502 } 503 504 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) { 505 DeltaArchiveManifest expected; 506 AddGroup(&expected, T("android"), 3_GiB); 507 508 DeltaArchiveManifest update_manifest; 509 AddGroup(&update_manifest, "android", 3_GiB); 510 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB); 511 512 EXPECT_TRUE( 513 UpdatePartitionMetadata(source_manifest, update_manifest, expected)); 514 } 515 516 TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) { 517 DeltaArchiveManifest expected; 518 AddGroupAndPartition( 519 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB); 520 521 DeltaArchiveManifest update_manifest; 522 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB); 523 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB); 524 AddGroupAndPartition( 525 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB); 526 EXPECT_TRUE( 527 UpdatePartitionMetadata(source_manifest, update_manifest, expected)); 528 } 529 530 TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) { 531 DeltaArchiveManifest update_manifest; 532 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB); 533 534 EXPECT_TRUE(UpdatePartitionMetadata( 535 source_manifest, update_manifest, Not(HasGroup(T("oem"))))); 536 } 537 538 TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) { 539 DeltaArchiveManifest expected; 540 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB); 541 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB); 542 DeltaArchiveManifest update_manifest; 543 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB), 544 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB); 545 EXPECT_TRUE( 546 UpdatePartitionMetadata(source_manifest, update_manifest, expected)); 547 } 548 549 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest, 550 DynamicPartitionControlAndroidGroupTestP, 551 testing::Values(TestParam{0, 1}, TestParam{1, 0})); 552 553 const PartitionSuffixSizes update_sizes_0() { 554 // Initial state is 0 for "other" slot. 555 return { 556 {"grown_a", 2_GiB}, 557 {"shrunk_a", 1_GiB}, 558 {"same_a", 100_MiB}, 559 {"deleted_a", 150_MiB}, 560 // no added_a 561 {"grown_b", 200_MiB}, 562 // simulate system_other 563 {"shrunk_b", 0}, 564 {"same_b", 0}, 565 {"deleted_b", 0}, 566 // no added_b 567 }; 568 } 569 570 const PartitionSuffixSizes update_sizes_1() { 571 return { 572 {"grown_a", 2_GiB}, 573 {"shrunk_a", 1_GiB}, 574 {"same_a", 100_MiB}, 575 {"deleted_a", 150_MiB}, 576 // no added_a 577 {"grown_b", 3_GiB}, 578 {"shrunk_b", 150_MiB}, 579 {"same_b", 100_MiB}, 580 {"added_b", 150_MiB}, 581 // no deleted_b 582 }; 583 } 584 585 const PartitionSuffixSizes update_sizes_2() { 586 return { 587 {"grown_a", 4_GiB}, 588 {"shrunk_a", 100_MiB}, 589 {"same_a", 100_MiB}, 590 {"deleted_a", 64_MiB}, 591 // no added_a 592 {"grown_b", 3_GiB}, 593 {"shrunk_b", 150_MiB}, 594 {"same_b", 100_MiB}, 595 {"added_b", 150_MiB}, 596 // no deleted_b 597 }; 598 } 599 600 // Test case for first update after the device is manufactured, in which 601 // case the "other" slot is likely of size "0" (except system, which is 602 // non-zero because of system_other partition) 603 TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) { 604 SetSlots({0, 1}); 605 606 SetMetadata(source(), update_sizes_0()); 607 SetMetadata(target(), update_sizes_0()); 608 ExpectStoreMetadata(update_sizes_1()); 609 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"}); 610 611 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB}, 612 {"shrunk", 150_MiB}, 613 {"same", 100_MiB}, 614 {"added", 150_MiB}})); 615 } 616 617 // After first update, test for the second update. In the second update, the 618 // "added" partition is deleted and "deleted" partition is re-added. 619 TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) { 620 SetSlots({1, 0}); 621 622 SetMetadata(source(), update_sizes_1()); 623 SetMetadata(target(), update_sizes_0()); 624 625 ExpectStoreMetadata(update_sizes_2()); 626 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"}); 627 628 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB}, 629 {"shrunk", 100_MiB}, 630 {"same", 100_MiB}, 631 {"deleted", 64_MiB}})); 632 } 633 634 TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) { 635 SetSlots({1, 1}); 636 EXPECT_FALSE(PreparePartitionsForUpdate({})) 637 << "Should not be able to apply to current slot."; 638 } 639 640 TEST_P(DynamicPartitionControlAndroidTestP, OptimizeOperationTest) { 641 ASSERT_TRUE(dynamicControl().PreparePartitionsForUpdate( 642 source(), 643 target(), 644 PartitionSizesToManifest({{"foo", 4_MiB}}), 645 false, 646 nullptr)); 647 dynamicControl().set_fake_mapped_devices({T("foo")}); 648 649 InstallOperation iop; 650 InstallOperation optimized; 651 Extent *se, *de; 652 653 // Not a SOURCE_COPY operation, cannot skip. 654 iop.set_type(InstallOperation::REPLACE); 655 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 656 657 iop.set_type(InstallOperation::SOURCE_COPY); 658 659 // By default GetVirtualAbFeatureFlag is disabled. Cannot skip operation. 660 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 661 662 // Enable GetVirtualAbFeatureFlag in the mock interface. 663 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag()) 664 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH))); 665 666 // By default target_supports_snapshot_ is set to false. Cannot skip 667 // operation. 668 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 669 670 SetSnapshotEnabled(true); 671 672 // Empty source and destination. Skip. 673 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 674 EXPECT_TRUE(optimized.src_extents().empty()); 675 EXPECT_TRUE(optimized.dst_extents().empty()); 676 677 se = iop.add_src_extents(); 678 se->set_start_block(0); 679 se->set_num_blocks(1); 680 681 // There is something in sources, but destinations are empty. Cannot skip. 682 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 683 684 InstallOperation iop2; 685 686 de = iop2.add_dst_extents(); 687 de->set_start_block(0); 688 de->set_num_blocks(1); 689 690 // There is something in destinations, but sources are empty. Cannot skip. 691 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop2, &optimized)); 692 693 de = iop.add_dst_extents(); 694 de->set_start_block(0); 695 de->set_num_blocks(1); 696 697 // Sources and destinations are identical. Skip. 698 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 699 EXPECT_TRUE(optimized.src_extents().empty()); 700 EXPECT_TRUE(optimized.dst_extents().empty()); 701 702 se = iop.add_src_extents(); 703 se->set_start_block(1); 704 se->set_num_blocks(5); 705 706 // There is something in source, but not in destination. Cannot skip. 707 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 708 709 de = iop.add_dst_extents(); 710 de->set_start_block(1); 711 de->set_num_blocks(5); 712 713 // There is source and destination are equal. Skip. 714 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 715 EXPECT_TRUE(optimized.src_extents().empty()); 716 EXPECT_TRUE(optimized.dst_extents().empty()); 717 718 de = iop.add_dst_extents(); 719 de->set_start_block(6); 720 de->set_num_blocks(5); 721 722 // There is something extra in dest. Cannot skip. 723 EXPECT_FALSE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 724 725 se = iop.add_src_extents(); 726 se->set_start_block(6); 727 se->set_num_blocks(5); 728 729 // Source and dest are identical again. Skip. 730 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 731 EXPECT_TRUE(optimized.src_extents().empty()); 732 EXPECT_TRUE(optimized.dst_extents().empty()); 733 734 iop.Clear(); 735 iop.set_type(InstallOperation::SOURCE_COPY); 736 se = iop.add_src_extents(); 737 se->set_start_block(1); 738 se->set_num_blocks(1); 739 se = iop.add_src_extents(); 740 se->set_start_block(3); 741 se->set_num_blocks(2); 742 se = iop.add_src_extents(); 743 se->set_start_block(7); 744 se->set_num_blocks(2); 745 de = iop.add_dst_extents(); 746 de->set_start_block(2); 747 de->set_num_blocks(5); 748 749 // [1, 3, 4, 7, 8] -> [2, 3, 4, 5, 6] should return [1, 7, 8] -> [2, 5, 6] 750 EXPECT_TRUE(dynamicControl().OptimizeOperation("foo", iop, &optimized)); 751 ASSERT_EQ(2, optimized.src_extents_size()); 752 ASSERT_EQ(2, optimized.dst_extents_size()); 753 EXPECT_EQ(1u, optimized.src_extents(0).start_block()); 754 EXPECT_EQ(1u, optimized.src_extents(0).num_blocks()); 755 EXPECT_EQ(2u, optimized.dst_extents(0).start_block()); 756 EXPECT_EQ(1u, optimized.dst_extents(0).num_blocks()); 757 EXPECT_EQ(7u, optimized.src_extents(1).start_block()); 758 EXPECT_EQ(2u, optimized.src_extents(1).num_blocks()); 759 EXPECT_EQ(5u, optimized.dst_extents(1).start_block()); 760 EXPECT_EQ(2u, optimized.dst_extents(1).num_blocks()); 761 762 // Don't skip for static partitions. 763 EXPECT_FALSE(dynamicControl().OptimizeOperation("bar", iop, &optimized)); 764 } 765 766 TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) { 767 MockPrefs prefs; 768 ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs)); 769 } 770 771 TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) { 772 // clang-format off 773 std::string fstab_content = 774 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical\n" // NOLINT(whitespace/line_length) 775 "/dev/block/by-name/system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other\n"; // NOLINT(whitespace/line_length) 776 // clang-format on 777 ScopedTempFile fstab; 778 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content)); 779 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()), 780 Optional(false)); 781 } 782 783 TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) { 784 // clang-format off 785 std::string fstab_content = 786 "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical,avb_keys=/foo\n"; // NOLINT(whitespace/line_length) 787 // clang-format on 788 ScopedTempFile fstab; 789 ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content)); 790 ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()), 791 Optional(true)); 792 } 793 794 TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) { 795 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _)) 796 .WillByDefault(Invoke([&](auto source_slot, 797 auto target_slot, 798 const auto& name, 799 auto path, 800 auto should_unmap) { 801 return dynamicControl().RealGetSystemOtherPath( 802 source_slot, target_slot, name, path, should_unmap); 803 })); 804 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther()) 805 .WillByDefault(Return(false)); 806 EXPECT_TRUE( 807 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target())); 808 } 809 810 TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) { 811 SetMetadata(source(), {{S("system"), 100_MiB}}); 812 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther()) 813 .WillByDefault(Return(true)); 814 std::string path; 815 bool should_unmap; 816 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath( 817 source(), target(), T("system"), &path, &should_unmap)); 818 ASSERT_TRUE(path.empty()) << path; 819 ASSERT_FALSE(should_unmap); 820 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _)) 821 .WillByDefault(Invoke([&](auto source_slot, 822 auto target_slot, 823 const auto& name, 824 auto path, 825 auto should_unmap) { 826 return dynamicControl().RealGetSystemOtherPath( 827 source_slot, target_slot, name, path, should_unmap); 828 })); 829 EXPECT_TRUE( 830 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target())); 831 } 832 833 TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) { 834 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}}; 835 SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED); 836 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther()) 837 .WillByDefault(Return(true)); 838 std::string path; 839 bool should_unmap; 840 ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath( 841 source(), target(), T("system"), &path, &should_unmap)); 842 ASSERT_TRUE(path.empty()) << path; 843 ASSERT_FALSE(should_unmap); 844 ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _)) 845 .WillByDefault(Invoke([&](auto source_slot, 846 auto target_slot, 847 const auto& name, 848 auto path, 849 auto should_unmap) { 850 return dynamicControl().RealGetSystemOtherPath( 851 source_slot, target_slot, name, path, should_unmap); 852 })); 853 EXPECT_TRUE( 854 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target())); 855 } 856 857 TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) { 858 constexpr uint64_t file_size = 1_MiB; 859 static_assert(file_size > AVB_FOOTER_SIZE); 860 ScopedTempFile system_other; 861 brillo::Blob original(file_size, 'X'); 862 ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original)); 863 std::string mnt_path; 864 ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path); 865 ASSERT_TRUE(dev.is_bound()); 866 867 brillo::Blob device_content; 868 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content)); 869 ASSERT_EQ(original, device_content); 870 871 PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}}; 872 SetMetadata(source(), sizes); 873 ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther()) 874 .WillByDefault(Return(true)); 875 EXPECT_CALL(dynamicControl(), 876 GetSystemOtherPath(source(), target(), T("system"), _, _)) 877 .WillRepeatedly( 878 Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) { 879 *path = mnt_path; 880 *should_unmap = false; 881 return true; 882 })); 883 ASSERT_TRUE( 884 dynamicControl().RealEraseSystemOtherAvbFooter(source(), target())); 885 886 device_content.clear(); 887 ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content)); 888 brillo::Blob new_expected(original); 889 // Clear the last AVB_FOOTER_SIZE bytes. 890 new_expected.resize(file_size - AVB_FOOTER_SIZE); 891 new_expected.resize(file_size, '\0'); 892 ASSERT_EQ(new_expected, device_content); 893 } 894 895 } // namespace chromeos_update_engine 896