1 /* 2 * Copyright (C) 2018 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 <algorithm> 18 #include <filesystem> 19 #include <fstream> 20 #include <functional> 21 #include <memory> 22 #include <optional> 23 #include <string> 24 #include <unordered_set> 25 #include <vector> 26 27 #include <grp.h> 28 #include <linux/loop.h> 29 #include <stdio.h> 30 #include <sys/ioctl.h> 31 #include <sys/stat.h> 32 #include <sys/types.h> 33 34 #include <android-base/file.h> 35 #include <android-base/logging.h> 36 #include <android-base/macros.h> 37 #include <android-base/properties.h> 38 #include <android-base/scopeguard.h> 39 #include <android-base/stringprintf.h> 40 #include <android-base/strings.h> 41 #include <android/os/IVold.h> 42 #include <binder/IServiceManager.h> 43 #include <fs_mgr_overlayfs.h> 44 #include <fstab/fstab.h> 45 #include <gmock/gmock.h> 46 #include <gtest/gtest.h> 47 #include <libdm/dm.h> 48 #include <selinux/selinux.h> 49 50 #include <android/apex/ApexInfo.h> 51 #include <android/apex/IApexService.h> 52 53 #include "apex_constants.h" 54 #include "apex_database.h" 55 #include "apex_file.h" 56 #include "apex_manifest.h" 57 #include "apexd.h" 58 #include "apexd_private.h" 59 #include "apexd_session.h" 60 #include "apexd_test_utils.h" 61 #include "apexd_utils.h" 62 #include "session_state.pb.h" 63 #include "string_log.h" 64 65 using apex::proto::SessionState; 66 67 namespace android { 68 namespace apex { 69 70 using android::sp; 71 using android::String16; 72 using android::apex::testing::ApexInfoEq; 73 using android::apex::testing::CreateSessionInfo; 74 using android::apex::testing::IsOk; 75 using android::apex::testing::SessionInfoEq; 76 using android::base::EndsWith; 77 using android::base::ErrnoError; 78 using android::base::Join; 79 using android::base::ReadFully; 80 using android::base::StartsWith; 81 using android::base::StringPrintf; 82 using android::base::unique_fd; 83 using android::dm::DeviceMapper; 84 using android::fs_mgr::Fstab; 85 using android::fs_mgr::GetEntryForMountPoint; 86 using android::fs_mgr::ReadFstabFromFile; 87 using ::apex::proto::ApexManifest; 88 using ::testing::Contains; 89 using ::testing::EndsWith; 90 using ::testing::HasSubstr; 91 using ::testing::Not; 92 using ::testing::SizeIs; 93 using ::testing::UnorderedElementsAre; 94 using ::testing::UnorderedElementsAreArray; 95 96 using MountedApexData = MountedApexDatabase::MountedApexData; 97 98 namespace fs = std::filesystem; 99 100 class ApexServiceTest : public ::testing::Test { 101 public: 102 ApexServiceTest() { 103 using android::IBinder; 104 using android::IServiceManager; 105 106 sp<IServiceManager> sm = android::defaultServiceManager(); 107 sp<IBinder> binder = sm->waitForService(String16("apexservice")); 108 if (binder != nullptr) { 109 service_ = android::interface_cast<IApexService>(binder); 110 } 111 binder = sm->getService(String16("vold")); 112 if (binder != nullptr) { 113 vold_service_ = android::interface_cast<android::os::IVold>(binder); 114 } 115 } 116 117 protected: 118 void SetUp() override { 119 // TODO(b/136647373): Move this check to environment setup 120 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 121 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 122 } 123 ASSERT_NE(nullptr, service_.get()); 124 ASSERT_NE(nullptr, vold_service_.get()); 125 android::binder::Status status = 126 vold_service_->supportsCheckpoint(&supports_fs_checkpointing_); 127 ASSERT_TRUE(IsOk(status)); 128 CleanUp(); 129 service_->recollectPreinstalledData(kApexPackageBuiltinDirs); 130 } 131 132 void TearDown() override { CleanUp(); } 133 134 static std::string GetTestDataDir() { 135 return android::base::GetExecutableDirectory(); 136 } 137 static std::string GetTestFile(const std::string& name) { 138 return GetTestDataDir() + "/" + name; 139 } 140 141 static bool HaveSelinux() { return 1 == is_selinux_enabled(); } 142 143 static bool IsSelinuxEnforced() { return 0 != security_getenforce(); } 144 145 Result<bool> IsActive(const std::string& name) { 146 std::vector<ApexInfo> list; 147 android::binder::Status status = service_->getActivePackages(&list); 148 if (!status.isOk()) { 149 return Error() << "Failed to check if " << name 150 << " is active : " << status.exceptionMessage().c_str(); 151 } 152 for (const ApexInfo& apex : list) { 153 if (apex.moduleName == name) { 154 return true; 155 } 156 } 157 return false; 158 } 159 160 Result<bool> IsActive(const std::string& name, int64_t version, 161 const std::string& path) { 162 std::vector<ApexInfo> list; 163 android::binder::Status status = service_->getActivePackages(&list); 164 if (status.isOk()) { 165 for (const ApexInfo& p : list) { 166 if (p.moduleName == name && p.versionCode == version && 167 p.modulePath == path) { 168 return true; 169 } 170 } 171 return false; 172 } 173 return Error() << status.exceptionMessage().c_str(); 174 } 175 176 Result<std::vector<ApexInfo>> GetAllPackages() { 177 std::vector<ApexInfo> list; 178 android::binder::Status status = service_->getAllPackages(&list); 179 if (status.isOk()) { 180 return list; 181 } 182 183 return Error() << status.toString8().c_str(); 184 } 185 186 Result<std::vector<ApexInfo>> GetActivePackages() { 187 std::vector<ApexInfo> list; 188 android::binder::Status status = service_->getActivePackages(&list); 189 if (status.isOk()) { 190 return list; 191 } 192 193 return Error() << status.exceptionMessage().c_str(); 194 } 195 196 Result<std::vector<ApexInfo>> GetInactivePackages() { 197 std::vector<ApexInfo> list; 198 android::binder::Status status = service_->getAllPackages(&list); 199 list.erase(std::remove_if( 200 list.begin(), list.end(), 201 [](const ApexInfo& apexInfo) { return apexInfo.isActive; }), 202 list.end()); 203 if (status.isOk()) { 204 return list; 205 } 206 207 return Error() << status.toString8().c_str(); 208 } 209 210 Result<ApexInfo> GetActivePackage(const std::string& name) { 211 ApexInfo package; 212 android::binder::Status status = service_->getActivePackage(name, &package); 213 if (status.isOk()) { 214 return package; 215 } 216 217 return Error() << status.exceptionMessage().c_str(); 218 } 219 220 std::string GetPackageString(const ApexInfo& p) { 221 return p.moduleName + "@" + std::to_string(p.versionCode) + 222 " [path=" + p.moduleName + "]"; 223 } 224 225 std::vector<std::string> GetPackagesStrings( 226 const std::vector<ApexInfo>& list) { 227 std::vector<std::string> ret; 228 ret.reserve(list.size()); 229 for (const ApexInfo& p : list) { 230 ret.push_back(GetPackageString(p)); 231 } 232 return ret; 233 } 234 235 std::vector<std::string> GetActivePackagesStrings() { 236 std::vector<ApexInfo> list; 237 android::binder::Status status = service_->getActivePackages(&list); 238 if (status.isOk()) { 239 std::vector<std::string> ret(list.size()); 240 for (const ApexInfo& p : list) { 241 ret.push_back(GetPackageString(p)); 242 } 243 return ret; 244 } 245 246 std::vector<std::string> error; 247 error.push_back("ERROR"); 248 return error; 249 } 250 251 Result<std::vector<ApexInfo>> GetFactoryPackages() { 252 std::vector<ApexInfo> list; 253 android::binder::Status status = service_->getAllPackages(&list); 254 list.erase( 255 std::remove_if(list.begin(), list.end(), 256 [](ApexInfo& apexInfo) { return !apexInfo.isFactory; }), 257 list.end()); 258 if (status.isOk()) { 259 return list; 260 } 261 262 return Error() << status.toString8().c_str(); 263 } 264 265 static std::vector<std::string> ListDir(const std::string& path) { 266 std::vector<std::string> ret; 267 std::error_code ec; 268 if (!fs::is_directory(path, ec)) { 269 return ret; 270 } 271 auto status = WalkDir(path, [&](const fs::directory_entry& entry) { 272 std::string tmp; 273 switch (entry.symlink_status(ec).type()) { 274 case fs::file_type::directory: 275 tmp = "[dir]"; 276 break; 277 case fs::file_type::symlink: 278 tmp = "[lnk]"; 279 break; 280 case fs::file_type::regular: 281 tmp = "[reg]"; 282 break; 283 default: 284 tmp = "[other]"; 285 } 286 ret.push_back(tmp.append(entry.path().filename())); 287 }); 288 CHECK(status.has_value()) 289 << "Failed to list " << path << " : " << status.error(); 290 std::sort(ret.begin(), ret.end()); 291 return ret; 292 } 293 294 static std::string GetLogcat() { 295 // For simplicity, log to file and read it. 296 std::string file = GetTestFile("logcat.tmp.txt"); 297 std::vector<std::string> args{ 298 "/system/bin/logcat", 299 "-d", 300 "-f", 301 file, 302 }; 303 auto res = ForkAndRun(args); 304 CHECK(res.ok()) << res.error(); 305 306 std::string data; 307 CHECK(android::base::ReadFileToString(file, &data)); 308 309 unlink(file.c_str()); 310 311 return data; 312 } 313 314 static void DeleteIfExists(const std::string& path) { 315 if (fs::exists(path)) { 316 std::error_code ec; 317 fs::remove_all(path, ec); 318 ASSERT_FALSE(ec) << "Failed to delete dir " << path << " : " 319 << ec.message(); 320 } 321 } 322 323 struct PrepareTestApexForInstall { 324 static constexpr const char* kTestDir = "/data/app-staging/apexservice_tmp"; 325 326 // This is given to the constructor. 327 std::string test_input; // Original test file. 328 std::string selinux_label_input; // SELinux label to apply. 329 std::string test_dir_input; 330 331 // This is derived from the input. 332 std::string test_file; // Prepared path. Under test_dir_input. 333 std::string test_installed_file; // Where apexd will store it. 334 335 std::string package; // APEX package name. 336 uint64_t version; // APEX version 337 338 explicit PrepareTestApexForInstall( 339 const std::string& test, 340 const std::string& test_dir = std::string(kTestDir), 341 const std::string& selinux_label = "staging_data_file") { 342 test_input = test; 343 selinux_label_input = selinux_label; 344 test_dir_input = test_dir; 345 346 test_file = test_dir_input + "/" + android::base::Basename(test); 347 348 package = ""; // Explicitly mark as not initialized. 349 350 Result<ApexFile> apex_file = ApexFile::Open(test); 351 if (!apex_file.ok()) { 352 return; 353 } 354 355 const ApexManifest& manifest = apex_file->GetManifest(); 356 package = manifest.name(); 357 version = manifest.version(); 358 359 test_installed_file = std::string(kActiveApexPackagesDataDir) + "/" + 360 package + "@" + std::to_string(version) + ".apex"; 361 } 362 363 bool Prepare() { 364 if (package.empty()) { 365 // Failure in constructor. Redo work to get error message. 366 auto fail_fn = [&]() { 367 Result<ApexFile> apex_file = ApexFile::Open(test_input); 368 ASSERT_FALSE(IsOk(apex_file)); 369 ASSERT_TRUE(apex_file.ok()) 370 << test_input << " failed to load: " << apex_file.error(); 371 }; 372 fail_fn(); 373 return false; 374 } 375 376 auto prepare = [](const std::string& src, const std::string& trg, 377 const std::string& selinux_label) { 378 ASSERT_EQ(0, access(src.c_str(), F_OK)) 379 << src << ": " << strerror(errno); 380 const std::string trg_dir = android::base::Dirname(trg); 381 if (0 != mkdir(trg_dir.c_str(), 0777)) { 382 int saved_errno = errno; 383 ASSERT_EQ(saved_errno, EEXIST) << trg << ":" << strerror(saved_errno); 384 } 385 386 // Do not use a hardlink, even though it's the simplest solution. 387 // b/119569101. 388 { 389 std::ifstream src_stream(src, std::ios::binary); 390 ASSERT_TRUE(src_stream.good()); 391 std::ofstream trg_stream(trg, std::ios::binary); 392 ASSERT_TRUE(trg_stream.good()); 393 394 trg_stream << src_stream.rdbuf(); 395 } 396 397 ASSERT_EQ(0, chmod(trg.c_str(), 0666)) << strerror(errno); 398 struct group* g = getgrnam("system"); 399 ASSERT_NE(nullptr, g); 400 ASSERT_EQ(0, chown(trg.c_str(), /* root uid */ 0, g->gr_gid)) 401 << strerror(errno); 402 403 int rc = setfilecon( 404 trg_dir.c_str(), 405 std::string("u:object_r:" + selinux_label + ":s0").c_str()); 406 ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno); 407 rc = setfilecon( 408 trg.c_str(), 409 std::string("u:object_r:" + selinux_label + ":s0").c_str()); 410 ASSERT_TRUE(0 == rc || !HaveSelinux()) << strerror(errno); 411 }; 412 prepare(test_input, test_file, selinux_label_input); 413 return !HasFatalFailure(); 414 } 415 416 ~PrepareTestApexForInstall() { 417 LOG(INFO) << "Deleting file " << test_file; 418 if (unlink(test_file.c_str()) != 0) { 419 PLOG(ERROR) << "Unable to unlink " << test_file; 420 } 421 LOG(INFO) << "Deleting directory " << test_dir_input; 422 if (rmdir(test_dir_input.c_str()) != 0) { 423 PLOG(ERROR) << "Unable to rmdir " << test_dir_input; 424 } 425 } 426 }; 427 428 std::string GetDebugStr(PrepareTestApexForInstall* installer) { 429 StringLog log; 430 431 if (installer != nullptr) { 432 log << "test_input=" << installer->test_input << " "; 433 log << "test_file=" << installer->test_file << " "; 434 log << "test_installed_file=" << installer->test_installed_file << " "; 435 log << "package=" << installer->package << " "; 436 log << "version=" << installer->version << " "; 437 } 438 439 log << "active=[" << Join(GetActivePackagesStrings(), ',') << "] "; 440 log << kActiveApexPackagesDataDir << "=[" 441 << Join(ListDir(kActiveApexPackagesDataDir), ',') << "] "; 442 log << kApexRoot << "=[" << Join(ListDir(kApexRoot), ',') << "]"; 443 444 return log; 445 } 446 447 sp<IApexService> service_; 448 sp<android::os::IVold> vold_service_; 449 bool supports_fs_checkpointing_; 450 451 private: 452 void CleanUp() { 453 DeleteDirContent(kActiveApexPackagesDataDir); 454 DeleteDirContent(kApexBackupDir); 455 DeleteDirContent(kApexHashTreeDir); 456 DeleteDirContent(ApexSession::GetSessionsDir()); 457 458 DeleteIfExists("/data/misc_ce/0/apexdata/apex.apexd_test"); 459 DeleteIfExists("/data/misc_ce/0/apexrollback/123456"); 460 DeleteIfExists("/data/misc_ce/0/apexrollback/77777"); 461 DeleteIfExists("/data/misc_ce/0/apexrollback/98765"); 462 DeleteIfExists("/data/misc_de/0/apexrollback/123456"); 463 DeleteIfExists("/data/misc/apexrollback/123456"); 464 } 465 }; 466 467 namespace { 468 469 bool RegularFileExists(const std::string& path) { 470 struct stat buf; 471 if (0 != stat(path.c_str(), &buf)) { 472 return false; 473 } 474 return S_ISREG(buf.st_mode); 475 } 476 477 bool DirExists(const std::string& path) { 478 struct stat buf; 479 if (0 != stat(path.c_str(), &buf)) { 480 return false; 481 } 482 return S_ISDIR(buf.st_mode); 483 } 484 485 void CreateDir(const std::string& path) { 486 std::error_code ec; 487 fs::create_directory(path, ec); 488 ASSERT_FALSE(ec) << "Failed to create rollback dir " 489 << " : " << ec.message(); 490 } 491 492 void CreateFile(const std::string& path) { 493 std::ofstream ofs(path); 494 ASSERT_TRUE(ofs.good()); 495 ofs.close(); 496 } 497 498 Result<std::vector<std::string>> ReadEntireDir(const std::string& path) { 499 static const auto kAcceptAll = [](auto /*entry*/) { return true; }; 500 return ReadDir(path, kAcceptAll); 501 } 502 503 Result<std::string> GetBlockDeviceForApex(const std::string& package_id) { 504 std::string mount_point = std::string(kApexRoot) + "/" + package_id; 505 Fstab fstab; 506 if (!ReadFstabFromFile("/proc/mounts", &fstab)) { 507 return Error() << "Failed to read /proc/mounts"; 508 } 509 auto entry = GetEntryForMountPoint(&fstab, mount_point); 510 if (entry == nullptr) { 511 return Error() << "Can't find " << mount_point << " in /proc/mounts"; 512 } 513 return entry->blk_device; 514 } 515 516 Result<void> ReadDevice(const std::string& block_device) { 517 static constexpr int kBlockSize = 4096; 518 static constexpr size_t kBufSize = 1024 * kBlockSize; 519 std::vector<uint8_t> buffer(kBufSize); 520 521 unique_fd fd( 522 TEMP_FAILURE_RETRY(open(block_device.c_str(), O_RDONLY | O_CLOEXEC))); 523 if (fd.get() == -1) { 524 return ErrnoError() << "Can't open " << block_device; 525 } 526 527 while (true) { 528 int n = read(fd.get(), buffer.data(), kBufSize); 529 if (n < 0) { 530 return ErrnoError() << "Failed to read " << block_device; 531 } 532 if (n == 0) { 533 break; 534 } 535 } 536 return {}; 537 } 538 539 std::vector<std::string> ListSlavesOfDmDevice(const std::string& name) { 540 DeviceMapper& dm = DeviceMapper::Instance(); 541 std::string dm_path; 542 EXPECT_TRUE(dm.GetDmDevicePathByName(name, &dm_path)) 543 << "Failed to get path of dm device " << name; 544 // It's a little bit sad we can't use ConsumePrefix here :( 545 constexpr std::string_view kDevPrefix = "/dev/"; 546 EXPECT_TRUE(StartsWith(dm_path, kDevPrefix)) << "Illegal path " << dm_path; 547 dm_path = dm_path.substr(kDevPrefix.length()); 548 std::vector<std::string> slaves; 549 { 550 std::string slaves_dir = "/sys/" + dm_path + "/slaves"; 551 auto st = WalkDir(slaves_dir, [&](const auto& entry) { 552 std::error_code ec; 553 if (entry.is_symlink(ec)) { 554 slaves.push_back("/dev/block/" + entry.path().filename().string()); 555 } 556 if (ec) { 557 ADD_FAILURE() << "Failed to scan " << slaves_dir << " : " << ec; 558 } 559 }); 560 EXPECT_TRUE(IsOk(st)); 561 } 562 return slaves; 563 } 564 565 Result<void> CopyFile(const std::string& from, const std::string& to, 566 const fs::copy_options& options) { 567 std::error_code ec; 568 if (!fs::copy_file(from, to, options)) { 569 return Error() << "Failed to copy file " << from << " to " << to << " : " 570 << ec.message(); 571 } 572 return {}; 573 } 574 575 } // namespace 576 577 TEST_F(ApexServiceTest, HaveSelinux) { 578 // We want to test under selinux. 579 EXPECT_TRUE(HaveSelinux()); 580 } 581 582 // Skip for b/119032200. 583 TEST_F(ApexServiceTest, DISABLED_EnforceSelinux) { 584 // Crude cutout for virtual devices. 585 #if !defined(__i386__) && !defined(__x86_64__) 586 constexpr bool kIsX86 = false; 587 #else 588 constexpr bool kIsX86 = true; 589 #endif 590 EXPECT_TRUE(IsSelinuxEnforced() || kIsX86); 591 } 592 593 TEST_F(ApexServiceTest, StageFailAccess) { 594 if (!IsSelinuxEnforced()) { 595 LOG(WARNING) << "Skipping InstallFailAccess because of selinux"; 596 return; 597 } 598 599 // Use an extra copy, so that even if this test fails (incorrectly installs), 600 // we have the testdata file still around. 601 std::string orig_test_file = GetTestFile("apex.apexd_test.apex"); 602 std::string test_file = orig_test_file + ".2"; 603 ASSERT_EQ(0, link(orig_test_file.c_str(), test_file.c_str())) 604 << strerror(errno); 605 struct Deleter { 606 std::string to_delete; 607 explicit Deleter(std::string t) : to_delete(std::move(t)) {} 608 ~Deleter() { 609 if (unlink(to_delete.c_str()) != 0) { 610 PLOG(ERROR) << "Could not unlink " << to_delete; 611 } 612 } 613 }; 614 Deleter del(test_file); 615 616 android::binder::Status st = service_->stagePackages({test_file}); 617 ASSERT_FALSE(IsOk(st)); 618 std::string error = st.exceptionMessage().c_str(); 619 EXPECT_NE(std::string::npos, error.find("Failed to open package")) << error; 620 EXPECT_NE(std::string::npos, error.find("I/O error")) << error; 621 } 622 623 TEST_F(ApexServiceTest, StageFailKey) { 624 PrepareTestApexForInstall installer( 625 GetTestFile("apex.apexd_test_no_inst_key.apex")); 626 if (!installer.Prepare()) { 627 return; 628 } 629 ASSERT_EQ(std::string("com.android.apex.test_package.no_inst_key"), 630 installer.package); 631 632 android::binder::Status st = service_->stagePackages({installer.test_file}); 633 ASSERT_FALSE(IsOk(st)); 634 635 // May contain one of two errors. 636 std::string error = st.exceptionMessage().c_str(); 637 638 ASSERT_THAT(error, HasSubstr("No preinstalled apex found for package " 639 "com.android.apex.test_package.no_inst_key")); 640 } 641 642 TEST_F(ApexServiceTest, StageSuccess) { 643 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); 644 if (!installer.Prepare()) { 645 return; 646 } 647 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); 648 649 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 650 EXPECT_TRUE(RegularFileExists(installer.test_installed_file)); 651 } 652 653 TEST_F(ApexServiceTest, 654 SubmitStagegSessionSuccessDoesNotLeakTempVerityDevices) { 655 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 656 "/data/app-staging/session_1543", 657 "staging_data_file"); 658 if (!installer.Prepare()) { 659 return; 660 } 661 662 ApexInfoList list; 663 ApexSessionParams params; 664 params.sessionId = 1543; 665 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 666 667 std::vector<DeviceMapper::DmBlockDevice> devices; 668 DeviceMapper& dm = DeviceMapper::Instance(); 669 ASSERT_TRUE(dm.GetAvailableDevices(&devices)); 670 671 for (const auto& device : devices) { 672 ASSERT_THAT(device.name(), Not(EndsWith(".tmp"))); 673 } 674 } 675 676 TEST_F(ApexServiceTest, SubmitStagedSessionStoresBuildFingerprint) { 677 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 678 "/data/app-staging/session_1547", 679 "staging_data_file"); 680 if (!installer.Prepare()) { 681 return; 682 } 683 ApexInfoList list; 684 ApexSessionParams params; 685 params.sessionId = 1547; 686 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 687 688 auto session = ApexSession::GetSession(1547); 689 ASSERT_FALSE(session->GetBuildFingerprint().empty()); 690 } 691 692 TEST_F(ApexServiceTest, SubmitStagedSessionFailDoesNotLeakTempVerityDevices) { 693 PrepareTestApexForInstall installer( 694 GetTestFile("apex.apexd_test_manifest_mismatch.apex"), 695 "/data/app-staging/session_239", "staging_data_file"); 696 if (!installer.Prepare()) { 697 return; 698 } 699 700 ApexInfoList list; 701 ApexSessionParams params; 702 params.sessionId = 239; 703 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 704 705 std::vector<DeviceMapper::DmBlockDevice> devices; 706 DeviceMapper& dm = DeviceMapper::Instance(); 707 ASSERT_TRUE(dm.GetAvailableDevices(&devices)); 708 709 for (const auto& device : devices) { 710 ASSERT_THAT(device.name(), Not(EndsWith(".tmp"))); 711 } 712 } 713 714 TEST_F(ApexServiceTest, StageSuccessClearsPreviouslyActivePackage) { 715 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test_v2.apex")); 716 PrepareTestApexForInstall installer2( 717 GetTestFile("apex.apexd_test_different_app.apex")); 718 PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test.apex")); 719 auto install_fn = [&](PrepareTestApexForInstall& installer) { 720 if (!installer.Prepare()) { 721 return; 722 } 723 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 724 EXPECT_TRUE(RegularFileExists(installer.test_installed_file)); 725 }; 726 install_fn(installer1); 727 install_fn(installer2); 728 // Simulating a revert. After this call test_v2_apex_path should be removed. 729 install_fn(installer3); 730 731 EXPECT_FALSE(RegularFileExists(installer1.test_installed_file)); 732 EXPECT_TRUE(RegularFileExists(installer2.test_installed_file)); 733 EXPECT_TRUE(RegularFileExists(installer3.test_installed_file)); 734 } 735 736 TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccess) { 737 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); 738 if (!installer.Prepare()) { 739 return; 740 } 741 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); 742 743 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 744 ASSERT_TRUE(RegularFileExists(installer.test_installed_file)); 745 746 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 747 ASSERT_TRUE(RegularFileExists(installer.test_installed_file)); 748 } 749 750 TEST_F(ApexServiceTest, StageAlreadyStagedPackageSuccessNewWins) { 751 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); 752 PrepareTestApexForInstall installer2( 753 GetTestFile("apex.apexd_test_nocode.apex")); 754 if (!installer.Prepare() || !installer2.Prepare()) { 755 return; 756 } 757 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); 758 ASSERT_EQ(installer.test_installed_file, installer2.test_installed_file); 759 760 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 761 const auto& apex = ApexFile::Open(installer.test_installed_file); 762 ASSERT_TRUE(IsOk(apex)); 763 ASSERT_FALSE(apex->GetManifest().nocode()); 764 765 ASSERT_TRUE(IsOk(service_->stagePackages({installer2.test_file}))); 766 const auto& new_apex = ApexFile::Open(installer.test_installed_file); 767 ASSERT_TRUE(IsOk(new_apex)); 768 ASSERT_TRUE(new_apex->GetManifest().nocode()); 769 } 770 771 TEST_F(ApexServiceTest, MultiStageSuccess) { 772 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); 773 if (!installer.Prepare()) { 774 return; 775 } 776 ASSERT_EQ(std::string("com.android.apex.test_package"), installer.package); 777 778 PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex")); 779 if (!installer2.Prepare()) { 780 return; 781 } 782 ASSERT_EQ(std::string("com.android.apex.test_package"), installer2.package); 783 784 std::vector<std::string> packages; 785 packages.push_back(installer.test_file); 786 packages.push_back(installer2.test_file); 787 788 ASSERT_TRUE(IsOk(service_->stagePackages(packages))); 789 EXPECT_TRUE(RegularFileExists(installer.test_installed_file)); 790 EXPECT_TRUE(RegularFileExists(installer2.test_installed_file)); 791 } 792 793 TEST_F(ApexServiceTest, CannotBeRollbackAndHaveRollbackEnabled) { 794 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 795 "/data/app-staging/session_1543", 796 "staging_data_file"); 797 if (!installer.Prepare()) { 798 return; 799 } 800 801 ApexInfoList list; 802 ApexSessionParams params; 803 params.sessionId = 1543; 804 params.isRollback = true; 805 params.hasRollbackEnabled = true; 806 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 807 } 808 809 TEST_F(ApexServiceTest, SessionParamDefaults) { 810 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 811 "/data/app-staging/session_1547", 812 "staging_data_file"); 813 if (!installer.Prepare()) { 814 return; 815 } 816 ApexInfoList list; 817 ApexSessionParams params; 818 params.sessionId = 1547; 819 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 820 821 auto session = ApexSession::GetSession(1547); 822 ASSERT_TRUE(session->GetChildSessionIds().empty()); 823 ASSERT_FALSE(session->IsRollback()); 824 ASSERT_FALSE(session->HasRollbackEnabled()); 825 ASSERT_EQ(0, session->GetRollbackId()); 826 } 827 828 TEST_F(ApexServiceTest, SnapshotCeData) { 829 CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test"); 830 CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt"); 831 832 ASSERT_TRUE( 833 RegularFileExists("/data/misc_ce/0/apexdata/apex.apexd_test/hello.txt")); 834 835 service_->snapshotCeData(0, 123456, "apex.apexd_test"); 836 837 ASSERT_TRUE(RegularFileExists( 838 "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/hello.txt")); 839 } 840 841 TEST_F(ApexServiceTest, RestoreCeData) { 842 CreateDir("/data/misc_ce/0/apexdata/apex.apexd_test"); 843 CreateDir("/data/misc_ce/0/apexrollback/123456"); 844 CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"); 845 846 CreateFile("/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt"); 847 CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt"); 848 849 ASSERT_TRUE(RegularFileExists( 850 "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt")); 851 ASSERT_TRUE(RegularFileExists( 852 "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/oldfile.txt")); 853 854 service_->restoreCeData(0, 123456, "apex.apexd_test"); 855 856 ASSERT_TRUE(RegularFileExists( 857 "/data/misc_ce/0/apexdata/apex.apexd_test/oldfile.txt")); 858 ASSERT_FALSE(RegularFileExists( 859 "/data/misc_ce/0/apexdata/apex.apexd_test/newfile.txt")); 860 // The snapshot should be deleted after restoration. 861 ASSERT_FALSE( 862 DirExists("/data/misc_ce/0/apexrollback/123456/apex.apexd_test")); 863 } 864 865 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeSys) { 866 CreateDir("/data/misc/apexrollback/123456"); 867 CreateDir("/data/misc/apexrollback/123456/my.apex"); 868 CreateFile("/data/misc/apexrollback/123456/my.apex/hello.txt"); 869 870 ASSERT_TRUE( 871 RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt")); 872 873 service_->destroyDeSnapshots(8975); 874 ASSERT_TRUE( 875 RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt")); 876 877 service_->destroyDeSnapshots(123456); 878 ASSERT_FALSE( 879 RegularFileExists("/data/misc/apexrollback/123456/my.apex/hello.txt")); 880 ASSERT_FALSE(DirExists("/data/misc/apexrollback/123456")); 881 } 882 883 TEST_F(ApexServiceTest, DestroyDeSnapshotsDeUser) { 884 CreateDir("/data/misc_de/0/apexrollback/123456"); 885 CreateDir("/data/misc_de/0/apexrollback/123456/my.apex"); 886 CreateFile("/data/misc_de/0/apexrollback/123456/my.apex/hello.txt"); 887 888 ASSERT_TRUE(RegularFileExists( 889 "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt")); 890 891 service_->destroyDeSnapshots(8975); 892 ASSERT_TRUE(RegularFileExists( 893 "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt")); 894 895 service_->destroyDeSnapshots(123456); 896 ASSERT_FALSE(RegularFileExists( 897 "/data/misc_de/0/apexrollback/123456/my.apex/hello.txt")); 898 ASSERT_FALSE(DirExists("/data/misc_de/0/apexrollback/123456")); 899 } 900 901 TEST_F(ApexServiceTest, DestroyCeSnapshots) { 902 CreateDir("/data/misc_ce/0/apexrollback/123456"); 903 CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"); 904 CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"); 905 906 CreateDir("/data/misc_ce/0/apexrollback/77777"); 907 CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test"); 908 CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"); 909 910 ASSERT_TRUE(RegularFileExists( 911 "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt")); 912 ASSERT_TRUE(RegularFileExists( 913 "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt")); 914 915 android::binder::Status st = service_->destroyCeSnapshots(0, 123456); 916 ASSERT_TRUE(IsOk(st)); 917 // Should be OK if the directory doesn't exist. 918 st = service_->destroyCeSnapshots(1, 123456); 919 ASSERT_TRUE(IsOk(st)); 920 921 ASSERT_TRUE(RegularFileExists( 922 "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt")); 923 ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456")); 924 } 925 926 TEST_F(ApexServiceTest, DestroyCeSnapshotsNotSpecified) { 927 CreateDir("/data/misc_ce/0/apexrollback/123456"); 928 CreateDir("/data/misc_ce/0/apexrollback/123456/apex.apexd_test"); 929 CreateFile("/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt"); 930 931 CreateDir("/data/misc_ce/0/apexrollback/77777"); 932 CreateDir("/data/misc_ce/0/apexrollback/77777/apex.apexd_test"); 933 CreateFile("/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt"); 934 935 CreateDir("/data/misc_ce/0/apexrollback/98765"); 936 CreateDir("/data/misc_ce/0/apexrollback/98765/apex.apexd_test"); 937 CreateFile("/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt"); 938 939 ASSERT_TRUE(RegularFileExists( 940 "/data/misc_ce/0/apexrollback/123456/apex.apexd_test/file.txt")); 941 ASSERT_TRUE(RegularFileExists( 942 "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt")); 943 ASSERT_TRUE(RegularFileExists( 944 "/data/misc_ce/0/apexrollback/98765/apex.apexd_test/test.txt")); 945 946 std::vector<int> retain{123, 77777, 987654}; 947 android::binder::Status st = 948 service_->destroyCeSnapshotsNotSpecified(0, retain); 949 ASSERT_TRUE(IsOk(st)); 950 951 ASSERT_TRUE(RegularFileExists( 952 "/data/misc_ce/0/apexrollback/77777/apex.apexd_test/thing.txt")); 953 ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/123456")); 954 ASSERT_FALSE(DirExists("/data/misc_ce/0/apexrollback/98765")); 955 } 956 957 TEST_F(ApexServiceTest, SubmitStagedSessionCleanupsTempMountOnFailure) { 958 // Parent session id: 23 959 // Children session ids: 37 73 960 PrepareTestApexForInstall installer( 961 GetTestFile("apex.apexd_test_different_app.apex"), 962 "/data/app-staging/session_37", "staging_data_file"); 963 PrepareTestApexForInstall installer2( 964 GetTestFile("apex.apexd_test_manifest_mismatch.apex"), 965 "/data/app-staging/session_73", "staging_data_file"); 966 if (!installer.Prepare() || !installer2.Prepare()) { 967 FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2); 968 } 969 ApexInfoList list; 970 ApexSessionParams params; 971 params.sessionId = 23; 972 params.childSessionIds = {37, 73}; 973 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))) 974 << GetDebugStr(&installer); 975 976 // Check that temp mounts were cleanded up. 977 for (const auto& mount : GetApexMounts()) { 978 EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount; 979 } 980 } 981 982 template <typename NameProvider> 983 class ApexServiceActivationTest : public ApexServiceTest { 984 public: 985 ApexServiceActivationTest() : stage_package(true) {} 986 987 explicit ApexServiceActivationTest(bool stage_package) 988 : stage_package(stage_package) {} 989 990 void SetUp() override { 991 // TODO(b/136647373): Move this check to environment setup 992 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 993 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 994 } 995 ApexServiceTest::SetUp(); 996 ASSERT_NE(nullptr, service_.get()); 997 998 installer_ = std::make_unique<PrepareTestApexForInstall>( 999 GetTestFile(NameProvider::GetTestName())); 1000 if (!installer_->Prepare()) { 1001 return; 1002 } 1003 ASSERT_EQ(NameProvider::GetPackageName(), installer_->package); 1004 1005 { 1006 // Check package is not active. 1007 std::string path = stage_package ? installer_->test_installed_file 1008 : installer_->test_file; 1009 Result<bool> active = 1010 IsActive(installer_->package, installer_->version, path); 1011 ASSERT_TRUE(IsOk(active)); 1012 ASSERT_FALSE(*active); 1013 } 1014 1015 if (stage_package) { 1016 ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file}))); 1017 } 1018 } 1019 1020 void TearDown() override { 1021 // Attempt to deactivate. 1022 if (installer_ != nullptr) { 1023 if (stage_package) { 1024 service_->deactivatePackage(installer_->test_installed_file); 1025 } else { 1026 service_->deactivatePackage(installer_->test_file); 1027 } 1028 } 1029 1030 installer_.reset(); 1031 // ApexServiceTest::TearDown will wipe out everything under /data/apex. 1032 // Since some of that information is required for deactivatePackage binder 1033 // call, it's required to be called after deactivating package. 1034 ApexServiceTest::TearDown(); 1035 } 1036 1037 std::unique_ptr<PrepareTestApexForInstall> installer_; 1038 1039 private: 1040 bool stage_package; 1041 }; 1042 1043 struct SuccessNameProvider { 1044 static std::string GetTestName() { return "apex.apexd_test.apex"; } 1045 static std::string GetPackageName() { 1046 return "com.android.apex.test_package"; 1047 } 1048 }; 1049 1050 struct ManifestMismatchNameProvider { 1051 static std::string GetTestName() { 1052 return "apex.apexd_test_manifest_mismatch.apex"; 1053 } 1054 static std::string GetPackageName() { 1055 return "com.android.apex.test_package"; 1056 } 1057 }; 1058 1059 class ApexServiceActivationManifestMismatchFailure 1060 : public ApexServiceActivationTest<ManifestMismatchNameProvider> { 1061 public: 1062 ApexServiceActivationManifestMismatchFailure() 1063 : ApexServiceActivationTest(false) {} 1064 }; 1065 1066 TEST_F(ApexServiceActivationManifestMismatchFailure, 1067 ActivateFailsWithManifestMismatch) { 1068 android::binder::Status st = service_->activatePackage(installer_->test_file); 1069 ASSERT_FALSE(IsOk(st)); 1070 1071 std::string error = st.exceptionMessage().c_str(); 1072 ASSERT_THAT( 1073 error, 1074 HasSubstr( 1075 "Manifest inside filesystem does not match manifest outside it")); 1076 } 1077 1078 class ApexServiceActivationSuccessTest 1079 : public ApexServiceActivationTest<SuccessNameProvider> {}; 1080 1081 TEST_F(ApexServiceActivationSuccessTest, Activate) { 1082 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1083 << GetDebugStr(installer_.get()); 1084 1085 { 1086 // Check package is active. 1087 Result<bool> active = IsActive(installer_->package, installer_->version, 1088 installer_->test_installed_file); 1089 ASSERT_TRUE(IsOk(active)); 1090 ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ','); 1091 } 1092 1093 { 1094 // Check that the "latest" view exists. 1095 std::string latest_path = 1096 std::string(kApexRoot) + "/" + installer_->package; 1097 struct stat buf; 1098 ASSERT_EQ(0, stat(latest_path.c_str(), &buf)) << strerror(errno); 1099 // Check that it is a folder. 1100 EXPECT_TRUE(S_ISDIR(buf.st_mode)); 1101 1102 // Collect direct entries of a folder. 1103 auto collect_entries_fn = [&](const std::string& path) { 1104 std::vector<std::string> ret; 1105 auto status = WalkDir(path, [&](const fs::directory_entry& entry) { 1106 if (!entry.is_directory()) { 1107 return; 1108 } 1109 ret.emplace_back(entry.path().filename()); 1110 }); 1111 CHECK(status.has_value()) 1112 << "Failed to list " << path << " : " << status.error(); 1113 std::sort(ret.begin(), ret.end()); 1114 return ret; 1115 }; 1116 1117 std::string versioned_path = std::string(kApexRoot) + "/" + 1118 installer_->package + "@" + 1119 std::to_string(installer_->version); 1120 std::vector<std::string> versioned_folder_entries = 1121 collect_entries_fn(versioned_path); 1122 std::vector<std::string> latest_folder_entries = 1123 collect_entries_fn(latest_path); 1124 1125 EXPECT_TRUE(versioned_folder_entries == latest_folder_entries) 1126 << "Versioned: " << Join(versioned_folder_entries, ',') 1127 << " Latest: " << Join(latest_folder_entries, ','); 1128 } 1129 } 1130 1131 TEST_F(ApexServiceActivationSuccessTest, GetActivePackages) { 1132 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1133 << GetDebugStr(installer_.get()); 1134 1135 Result<std::vector<ApexInfo>> active = GetActivePackages(); 1136 ASSERT_TRUE(IsOk(active)); 1137 ApexInfo match; 1138 1139 for (const ApexInfo& info : *active) { 1140 if (info.moduleName == installer_->package) { 1141 match = info; 1142 break; 1143 } 1144 } 1145 1146 ASSERT_EQ(installer_->package, match.moduleName); 1147 ASSERT_EQ(installer_->version, static_cast<uint64_t>(match.versionCode)); 1148 ASSERT_EQ(installer_->test_installed_file, match.modulePath); 1149 } 1150 1151 TEST_F(ApexServiceActivationSuccessTest, GetActivePackage) { 1152 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1153 << GetDebugStr(installer_.get()); 1154 1155 Result<ApexInfo> active = GetActivePackage(installer_->package); 1156 ASSERT_TRUE(IsOk(active)); 1157 1158 ASSERT_EQ(installer_->package, active->moduleName); 1159 ASSERT_EQ(installer_->version, static_cast<uint64_t>(active->versionCode)); 1160 ASSERT_EQ(installer_->test_installed_file, active->modulePath); 1161 } 1162 1163 TEST_F(ApexServiceActivationSuccessTest, ShowsUpInMountedApexDatabase) { 1164 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1165 << GetDebugStr(installer_.get()); 1166 1167 MountedApexDatabase db; 1168 db.PopulateFromMounts(kActiveApexPackagesDataDir, kApexDecompressedDir, 1169 kApexHashTreeDir); 1170 1171 std::optional<MountedApexData> mounted_apex; 1172 db.ForallMountedApexes(installer_->package, 1173 [&](const MountedApexData& d, bool active) { 1174 if (active) { 1175 mounted_apex.emplace(d); 1176 } 1177 }); 1178 ASSERT_TRUE(mounted_apex) 1179 << "Haven't found " << installer_->test_installed_file 1180 << " in the database of mounted apexes"; 1181 1182 // Get all necessary data for assertions on mounted_apex. 1183 std::string package_id = 1184 installer_->package + "@" + std::to_string(installer_->version); 1185 DeviceMapper& dm = DeviceMapper::Instance(); 1186 std::string dm_path; 1187 ASSERT_TRUE(dm.GetDmDevicePathByName(package_id, &dm_path)) 1188 << "Failed to get path of dm device " << package_id; 1189 auto loop_device = dm.GetParentBlockDeviceByPath(dm_path); 1190 ASSERT_TRUE(loop_device) << "Failed to find parent block device of " 1191 << dm_path; 1192 1193 // Now we are ready to assert on mounted_apex. 1194 ASSERT_EQ(*loop_device, mounted_apex->loop_name); 1195 ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path); 1196 std::string expected_mount = std::string(kApexRoot) + "/" + package_id; 1197 ASSERT_EQ(expected_mount, mounted_apex->mount_point); 1198 ASSERT_EQ(package_id, mounted_apex->device_name); 1199 ASSERT_EQ("", mounted_apex->hashtree_loop_name); 1200 } 1201 1202 struct NoHashtreeApexNameProvider { 1203 static std::string GetTestName() { 1204 return "apex.apexd_test_no_hashtree.apex"; 1205 } 1206 static std::string GetPackageName() { 1207 return "com.android.apex.test_package"; 1208 } 1209 }; 1210 1211 class ApexServiceNoHashtreeApexActivationTest 1212 : public ApexServiceActivationTest<NoHashtreeApexNameProvider> {}; 1213 1214 TEST_F(ApexServiceNoHashtreeApexActivationTest, Activate) { 1215 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1216 << GetDebugStr(installer_.get()); 1217 { 1218 // Check package is active. 1219 Result<bool> active = IsActive(installer_->package, installer_->version, 1220 installer_->test_installed_file); 1221 ASSERT_TRUE(IsOk(active)); 1222 ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ','); 1223 } 1224 1225 std::string package_id = 1226 installer_->package + "@" + std::to_string(installer_->version); 1227 // Check that hashtree file was created. 1228 { 1229 std::string hashtree_path = 1230 std::string(kApexHashTreeDir) + "/" + package_id; 1231 auto exists = PathExists(hashtree_path); 1232 ASSERT_TRUE(IsOk(exists)); 1233 ASSERT_TRUE(*exists); 1234 } 1235 1236 // Check that block device can be read. 1237 auto block_device = GetBlockDeviceForApex(package_id); 1238 ASSERT_TRUE(IsOk(block_device)); 1239 ASSERT_TRUE(IsOk(ReadDevice(*block_device))); 1240 } 1241 1242 TEST_F(ApexServiceNoHashtreeApexActivationTest, 1243 NewSessionDoesNotImpactActivePackage) { 1244 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1245 << GetDebugStr(installer_.get()); 1246 { 1247 // Check package is active. 1248 Result<bool> active = IsActive(installer_->package, installer_->version, 1249 installer_->test_installed_file); 1250 ASSERT_TRUE(IsOk(active)); 1251 ASSERT_TRUE(*active) << Join(GetActivePackagesStrings(), ','); 1252 } 1253 1254 PrepareTestApexForInstall installer2( 1255 GetTestFile("apex.apexd_test_no_hashtree_2.apex"), 1256 "/data/app-staging/session_123", "staging_data_file"); 1257 if (!installer2.Prepare()) { 1258 FAIL(); 1259 } 1260 1261 ApexInfoList list; 1262 ApexSessionParams params; 1263 params.sessionId = 123; 1264 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 1265 1266 std::string package_id = 1267 installer_->package + "@" + std::to_string(installer_->version); 1268 // Check that new hashtree file was created. 1269 { 1270 std::string hashtree_path = 1271 std::string(kApexHashTreeDir) + "/" + package_id + ".new"; 1272 auto exists = PathExists(hashtree_path); 1273 ASSERT_TRUE(IsOk(exists)); 1274 ASSERT_TRUE(*exists) << hashtree_path << " does not exist"; 1275 } 1276 // Check that active hashtree is still there. 1277 { 1278 std::string hashtree_path = 1279 std::string(kApexHashTreeDir) + "/" + package_id; 1280 auto exists = PathExists(hashtree_path); 1281 ASSERT_TRUE(IsOk(exists)); 1282 ASSERT_TRUE(*exists) << hashtree_path << " does not exist"; 1283 } 1284 1285 // Check that block device of active APEX can still be read. 1286 auto block_device = GetBlockDeviceForApex(package_id); 1287 ASSERT_TRUE(IsOk(block_device)); 1288 } 1289 1290 TEST_F(ApexServiceNoHashtreeApexActivationTest, ShowsUpInMountedApexDatabase) { 1291 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1292 << GetDebugStr(installer_.get()); 1293 1294 MountedApexDatabase db; 1295 db.PopulateFromMounts(kActiveApexPackagesDataDir, kApexDecompressedDir, 1296 kApexHashTreeDir); 1297 1298 std::optional<MountedApexData> mounted_apex; 1299 db.ForallMountedApexes(installer_->package, 1300 [&](const MountedApexData& d, bool active) { 1301 if (active) { 1302 mounted_apex.emplace(d); 1303 } 1304 }); 1305 ASSERT_TRUE(mounted_apex) 1306 << "Haven't found " << installer_->test_installed_file 1307 << " in the database of mounted apexes"; 1308 1309 // Get all necessary data for assertions on mounted_apex. 1310 std::string package_id = 1311 installer_->package + "@" + std::to_string(installer_->version); 1312 std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id); 1313 ASSERT_EQ(2u, slaves.size()) 1314 << "Unexpected number of slaves: " << Join(slaves, ","); 1315 1316 // Now we are ready to assert on mounted_apex. 1317 ASSERT_EQ(installer_->test_installed_file, mounted_apex->full_path); 1318 std::string expected_mount = std::string(kApexRoot) + "/" + package_id; 1319 ASSERT_EQ(expected_mount, mounted_apex->mount_point); 1320 ASSERT_EQ(package_id, mounted_apex->device_name); 1321 // For loops we only check that both loop_name and hashtree_loop_name are 1322 // slaves of the top device mapper device. 1323 ASSERT_THAT(slaves, Contains(mounted_apex->loop_name)); 1324 ASSERT_THAT(slaves, Contains(mounted_apex->hashtree_loop_name)); 1325 ASSERT_NE(mounted_apex->loop_name, mounted_apex->hashtree_loop_name); 1326 } 1327 1328 TEST_F(ApexServiceNoHashtreeApexActivationTest, DeactivateFreesLoopDevices) { 1329 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1330 << GetDebugStr(installer_.get()); 1331 1332 std::string package_id = 1333 installer_->package + "@" + std::to_string(installer_->version); 1334 std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id); 1335 ASSERT_EQ(2u, slaves.size()) 1336 << "Unexpected number of slaves: " << Join(slaves, ","); 1337 1338 ASSERT_TRUE( 1339 IsOk(service_->deactivatePackage(installer_->test_installed_file))); 1340 1341 for (const auto& loop : slaves) { 1342 struct loop_info li; 1343 unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC))); 1344 ASSERT_NE(-1, fd.get()) 1345 << "Failed to open " << loop << " : " << strerror(errno); 1346 ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li)) 1347 << loop << " is still alive"; 1348 ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno); 1349 } 1350 1351 // Skip deactivatePackage on TearDown. 1352 installer_.reset(); 1353 } 1354 1355 TEST_F(ApexServiceTest, NoHashtreeApexStagePackagesMovesHashtree) { 1356 PrepareTestApexForInstall installer( 1357 GetTestFile("apex.apexd_test_no_hashtree.apex"), 1358 "/data/app-staging/session_239", "staging_data_file"); 1359 if (!installer.Prepare()) { 1360 FAIL(); 1361 } 1362 1363 auto read_fn = [](const std::string& path) -> std::vector<uint8_t> { 1364 static constexpr size_t kBufSize = 4096; 1365 std::vector<uint8_t> buffer(kBufSize); 1366 unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC))); 1367 if (fd.get() == -1) { 1368 PLOG(ERROR) << "Failed to open " << path; 1369 ADD_FAILURE(); 1370 return buffer; 1371 } 1372 if (!ReadFully(fd.get(), buffer.data(), kBufSize)) { 1373 PLOG(ERROR) << "Failed to read " << path; 1374 ADD_FAILURE(); 1375 } 1376 return buffer; 1377 }; 1378 1379 ApexInfoList list; 1380 ApexSessionParams params; 1381 params.sessionId = 239; 1382 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 1383 1384 std::string package_id = 1385 installer.package + "@" + std::to_string(installer.version); 1386 // Check that new hashtree file was created. 1387 std::vector<uint8_t> original_hashtree_data; 1388 { 1389 std::string hashtree_path = 1390 std::string(kApexHashTreeDir) + "/" + package_id + ".new"; 1391 auto exists = PathExists(hashtree_path); 1392 ASSERT_TRUE(IsOk(exists)); 1393 ASSERT_TRUE(*exists); 1394 original_hashtree_data = read_fn(hashtree_path); 1395 } 1396 1397 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 1398 // Check that hashtree file was moved. 1399 { 1400 std::string hashtree_path = 1401 std::string(kApexHashTreeDir) + "/" + package_id + ".new"; 1402 auto exists = PathExists(hashtree_path); 1403 ASSERT_TRUE(IsOk(exists)); 1404 ASSERT_FALSE(*exists); 1405 } 1406 { 1407 std::string hashtree_path = 1408 std::string(kApexHashTreeDir) + "/" + package_id; 1409 auto exists = PathExists(hashtree_path); 1410 ASSERT_TRUE(IsOk(exists)); 1411 ASSERT_TRUE(*exists); 1412 std::vector<uint8_t> moved_hashtree_data = read_fn(hashtree_path); 1413 ASSERT_EQ(moved_hashtree_data, original_hashtree_data); 1414 } 1415 } 1416 1417 TEST_F(ApexServiceTest, GetFactoryPackages) { 1418 Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages(); 1419 ASSERT_TRUE(IsOk(factory_packages)); 1420 ASSERT_TRUE(factory_packages->size() > 0); 1421 1422 std::vector<std::string> builtin_dirs; 1423 for (const auto& d : kApexPackageBuiltinDirs) { 1424 std::string realpath; 1425 if (android::base::Realpath(d, &realpath)) { 1426 builtin_dirs.push_back(realpath); 1427 } 1428 // realpath might fail in case when dir is a non-existing path. We can 1429 // ignore non-existing paths. 1430 } 1431 1432 // Decompressed APEX is also considred factory package 1433 builtin_dirs.push_back(kApexDecompressedDir); 1434 1435 for (const ApexInfo& package : *factory_packages) { 1436 bool is_builtin = false; 1437 for (const auto& dir : builtin_dirs) { 1438 if (StartsWith(package.modulePath, dir)) { 1439 is_builtin = true; 1440 } 1441 } 1442 ASSERT_TRUE(is_builtin); 1443 } 1444 } 1445 1446 TEST_F(ApexServiceTest, NoPackagesAreBothActiveAndInactive) { 1447 Result<std::vector<ApexInfo>> active_packages = GetActivePackages(); 1448 ASSERT_TRUE(IsOk(active_packages)); 1449 ASSERT_TRUE(active_packages->size() > 0); 1450 Result<std::vector<ApexInfo>> inactive_packages = GetInactivePackages(); 1451 ASSERT_TRUE(IsOk(inactive_packages)); 1452 std::vector<std::string> active_packages_strings = 1453 GetPackagesStrings(*active_packages); 1454 std::vector<std::string> inactive_packages_strings = 1455 GetPackagesStrings(*inactive_packages); 1456 std::sort(active_packages_strings.begin(), active_packages_strings.end()); 1457 std::sort(inactive_packages_strings.begin(), inactive_packages_strings.end()); 1458 std::vector<std::string> intersection; 1459 std::set_intersection( 1460 active_packages_strings.begin(), active_packages_strings.end(), 1461 inactive_packages_strings.begin(), inactive_packages_strings.end(), 1462 std::back_inserter(intersection)); 1463 ASSERT_THAT(intersection, SizeIs(0)); 1464 } 1465 1466 TEST_F(ApexServiceTest, GetAllPackages) { 1467 Result<std::vector<ApexInfo>> all_packages = GetAllPackages(); 1468 ASSERT_TRUE(IsOk(all_packages)); 1469 ASSERT_TRUE(all_packages->size() > 0); 1470 Result<std::vector<ApexInfo>> active_packages = GetActivePackages(); 1471 std::vector<std::string> active_strings = 1472 GetPackagesStrings(*active_packages); 1473 Result<std::vector<ApexInfo>> factory_packages = GetFactoryPackages(); 1474 std::vector<std::string> factory_strings = 1475 GetPackagesStrings(*factory_packages); 1476 for (ApexInfo& apexInfo : *all_packages) { 1477 std::string package_string = GetPackageString(apexInfo); 1478 bool should_be_active = 1479 std::find(active_strings.begin(), active_strings.end(), 1480 package_string) != active_strings.end(); 1481 bool should_be_factory = 1482 std::find(factory_strings.begin(), factory_strings.end(), 1483 package_string) != factory_strings.end(); 1484 ASSERT_EQ(should_be_active, apexInfo.isActive) 1485 << package_string << " should " << (should_be_active ? "" : "not ") 1486 << "be active"; 1487 ASSERT_EQ(should_be_factory, apexInfo.isFactory) 1488 << package_string << " should " << (should_be_factory ? "" : "not ") 1489 << "be factory"; 1490 } 1491 } 1492 1493 class ApexSameGradeOfPreInstalledVersionTest : public ApexServiceTest { 1494 public: 1495 void SetUp() override { 1496 // TODO(b/136647373): Move this check to environment setup 1497 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 1498 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 1499 } 1500 ApexServiceTest::SetUp(); 1501 ASSERT_NE(nullptr, service_.get()); 1502 1503 installer_ = std::make_unique<PrepareTestApexForInstall>( 1504 GetTestFile("com.android.apex.cts.shim.apex")); 1505 if (!installer_->Prepare()) { 1506 return; 1507 } 1508 ASSERT_EQ("com.android.apex.cts.shim", installer_->package); 1509 // First deactivate currently active shim, otherwise activatePackage will be 1510 // no-op. 1511 { 1512 ApexInfo system_shim; 1513 ASSERT_TRUE(IsOk(service_->getActivePackage("com.android.apex.cts.shim", 1514 &system_shim))); 1515 ASSERT_TRUE(IsOk(service_->deactivatePackage(system_shim.modulePath))); 1516 } 1517 ASSERT_TRUE(IsOk(service_->stagePackages({installer_->test_file}))); 1518 ASSERT_TRUE( 1519 IsOk(service_->activatePackage(installer_->test_installed_file))); 1520 } 1521 1522 void TearDown() override { 1523 // Attempt to deactivate. 1524 service_->deactivatePackage(installer_->test_installed_file); 1525 installer_.reset(); 1526 // ApexServiceTest::TearDown will wipe out everything under /data/apex. 1527 // Since some of that information is required for deactivatePackage binder 1528 // call, it's required to be called after deactivating package. 1529 ApexServiceTest::TearDown(); 1530 ASSERT_TRUE(IsOk(service_->activatePackage( 1531 "/system/apex/com.android.apex.cts.shim.apex"))); 1532 } 1533 1534 std::unique_ptr<PrepareTestApexForInstall> installer_; 1535 }; 1536 1537 TEST_F(ApexSameGradeOfPreInstalledVersionTest, VersionOnDataWins) { 1538 std::vector<ApexInfo> all; 1539 ASSERT_TRUE(IsOk(service_->getAllPackages(&all))); 1540 1541 ApexInfo on_data; 1542 on_data.moduleName = "com.android.apex.cts.shim"; 1543 on_data.modulePath = "/data/apex/active/com.android.apex.cts.shim@1.apex"; 1544 on_data.preinstalledModulePath = 1545 "/system/apex/com.android.apex.cts.shim.apex"; 1546 on_data.versionCode = 1; 1547 on_data.isFactory = false; 1548 on_data.isActive = true; 1549 1550 ApexInfo preinstalled; 1551 preinstalled.moduleName = "com.android.apex.cts.shim"; 1552 preinstalled.modulePath = "/system/apex/com.android.apex.cts.shim.apex"; 1553 preinstalled.preinstalledModulePath = 1554 "/system/apex/com.android.apex.cts.shim.apex"; 1555 preinstalled.versionCode = 1; 1556 preinstalled.isFactory = true; 1557 preinstalled.isActive = false; 1558 1559 ASSERT_THAT(all, Contains(ApexInfoEq(on_data))); 1560 ASSERT_THAT(all, Contains(ApexInfoEq(preinstalled))); 1561 } 1562 1563 class ApexServiceDeactivationTest : public ApexServiceActivationSuccessTest { 1564 public: 1565 void SetUp() override { 1566 ApexServiceActivationSuccessTest::SetUp(); 1567 1568 ASSERT_TRUE(installer_ != nullptr); 1569 } 1570 1571 void TearDown() override { 1572 installer_.reset(); 1573 ApexServiceActivationSuccessTest::TearDown(); 1574 } 1575 1576 std::unique_ptr<PrepareTestApexForInstall> installer_; 1577 }; 1578 1579 TEST_F(ApexServiceActivationSuccessTest, DmDeviceTearDown) { 1580 std::string package_id = 1581 installer_->package + "@" + std::to_string(installer_->version); 1582 1583 auto find_fn = [](const std::string& name) { 1584 auto& dm = DeviceMapper::Instance(); 1585 std::vector<DeviceMapper::DmBlockDevice> devices; 1586 if (!dm.GetAvailableDevices(&devices)) { 1587 return Result<bool>(Errorf("GetAvailableDevices failed")); 1588 } 1589 for (const auto& device : devices) { 1590 if (device.name() == name) { 1591 return Result<bool>(true); 1592 } 1593 } 1594 return Result<bool>(false); 1595 }; 1596 1597 #define ASSERT_FIND(type) \ 1598 { \ 1599 Result<bool> res = find_fn(package_id); \ 1600 ASSERT_RESULT_OK(res); \ 1601 ASSERT_##type(*res); \ 1602 } 1603 1604 ASSERT_FIND(FALSE); 1605 1606 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1607 << GetDebugStr(installer_.get()); 1608 1609 ASSERT_FIND(TRUE); 1610 1611 ASSERT_TRUE( 1612 IsOk(service_->deactivatePackage(installer_->test_installed_file))); 1613 1614 ASSERT_FIND(FALSE); 1615 1616 installer_.reset(); // Skip TearDown deactivatePackage. 1617 } 1618 1619 TEST_F(ApexServiceActivationSuccessTest, DeactivateFreesLoopDevices) { 1620 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 1621 << GetDebugStr(installer_.get()); 1622 1623 std::string package_id = 1624 installer_->package + "@" + std::to_string(installer_->version); 1625 std::vector<std::string> slaves = ListSlavesOfDmDevice(package_id); 1626 ASSERT_EQ(1u, slaves.size()) 1627 << "Unexpected number of slaves: " << Join(slaves, ","); 1628 const std::string& loop = slaves[0]; 1629 1630 ASSERT_TRUE( 1631 IsOk(service_->deactivatePackage(installer_->test_installed_file))); 1632 1633 struct loop_info li; 1634 unique_fd fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CLOEXEC))); 1635 ASSERT_NE(-1, fd.get()) << "Failed to open " << loop << " : " 1636 << strerror(errno); 1637 ASSERT_EQ(-1, ioctl(fd.get(), LOOP_GET_STATUS, &li)) 1638 << loop << " is still alive"; 1639 ASSERT_EQ(ENXIO, errno) << "Unexpected errno : " << strerror(errno); 1640 1641 installer_.reset(); // Skip TearDown deactivatePackage. 1642 } 1643 1644 class ApexServicePrePostInstallTest : public ApexServiceTest { 1645 public: 1646 template <typename Fn> 1647 void RunPrePost(Fn fn, const std::vector<std::string>& apex_names, 1648 const char* test_message, bool expect_success = true) { 1649 // Using unique_ptr is just the easiest here. 1650 using InstallerUPtr = std::unique_ptr<PrepareTestApexForInstall>; 1651 std::vector<InstallerUPtr> installers; 1652 std::vector<std::string> pkgs; 1653 1654 for (const std::string& apex_name : apex_names) { 1655 InstallerUPtr installer( 1656 new PrepareTestApexForInstall(GetTestFile(apex_name))); 1657 if (!installer->Prepare()) { 1658 return; 1659 } 1660 pkgs.push_back(installer->test_file); 1661 installers.emplace_back(std::move(installer)); 1662 } 1663 android::binder::Status st = (service_.get()->*fn)(pkgs); 1664 if (expect_success) { 1665 ASSERT_TRUE(IsOk(st)); 1666 } else { 1667 ASSERT_FALSE(IsOk(st)); 1668 } 1669 1670 if (test_message != nullptr) { 1671 std::string logcat = GetLogcat(); 1672 EXPECT_THAT(logcat, HasSubstr(test_message)); 1673 } 1674 1675 // Ensure that the package is neither active nor mounted. 1676 for (const InstallerUPtr& installer : installers) { 1677 Result<bool> active = IsActive(installer->package, installer->version, 1678 installer->test_file); 1679 ASSERT_TRUE(IsOk(active)); 1680 EXPECT_FALSE(*active); 1681 } 1682 for (const InstallerUPtr& installer : installers) { 1683 Result<ApexFile> apex = ApexFile::Open(installer->test_input); 1684 ASSERT_TRUE(IsOk(apex)); 1685 std::string path = 1686 apexd_private::GetPackageMountPoint(apex->GetManifest()); 1687 std::string entry = std::string("[dir]").append(path); 1688 std::vector<std::string> slash_apex = ListDir(kApexRoot); 1689 auto it = std::find(slash_apex.begin(), slash_apex.end(), entry); 1690 EXPECT_TRUE(it == slash_apex.end()) << Join(slash_apex, ','); 1691 } 1692 } 1693 }; 1694 1695 TEST_F(ApexServicePrePostInstallTest, Preinstall) { 1696 RunPrePost(&IApexService::preinstallPackages, 1697 {"apex.apexd_test_preinstall.apex"}, "sh : PreInstall Test"); 1698 } 1699 1700 TEST_F(ApexServicePrePostInstallTest, MultiPreinstall) { 1701 constexpr const char* kLogcatText = 1702 "sh : /apex/com.android.apex.test_package/etc/sample_prebuilt_file"; 1703 RunPrePost(&IApexService::preinstallPackages, 1704 {"apex.apexd_test_preinstall.apex", "apex.apexd_test.apex"}, 1705 kLogcatText); 1706 } 1707 1708 TEST_F(ApexServicePrePostInstallTest, PreinstallFail) { 1709 RunPrePost(&IApexService::preinstallPackages, 1710 {"apex.apexd_test_prepostinstall.fail.apex"}, 1711 /* test_message= */ nullptr, /* expect_success= */ false); 1712 } 1713 1714 TEST_F(ApexServicePrePostInstallTest, Postinstall) { 1715 RunPrePost(&IApexService::postinstallPackages, 1716 {"apex.apexd_test_postinstall.apex"}, 1717 "sh : PostInstall Test"); 1718 } 1719 1720 TEST_F(ApexServicePrePostInstallTest, MultiPostinstall) { 1721 constexpr const char* kLogcatText = 1722 "sh : /apex/com.android.apex.test_package/etc/sample_prebuilt_file"; 1723 RunPrePost(&IApexService::postinstallPackages, 1724 {"apex.apexd_test_postinstall.apex", "apex.apexd_test.apex"}, 1725 kLogcatText); 1726 } 1727 1728 TEST_F(ApexServicePrePostInstallTest, PostinstallFail) { 1729 RunPrePost(&IApexService::postinstallPackages, 1730 {"apex.apexd_test_prepostinstall.fail.apex"}, 1731 /* test_message= */ nullptr, /* expect_success= */ false); 1732 } 1733 1734 TEST_F(ApexServiceTest, SubmitSingleSessionTestSuccess) { 1735 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 1736 "/data/app-staging/session_123", 1737 "staging_data_file"); 1738 if (!installer.Prepare()) { 1739 FAIL() << GetDebugStr(&installer); 1740 } 1741 1742 ApexInfoList list; 1743 ApexSessionParams params; 1744 params.sessionId = 123; 1745 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))) 1746 << GetDebugStr(&installer); 1747 EXPECT_EQ(1u, list.apexInfos.size()); 1748 ApexInfo match; 1749 for (const ApexInfo& info : list.apexInfos) { 1750 if (info.moduleName == installer.package) { 1751 match = info; 1752 break; 1753 } 1754 } 1755 1756 ASSERT_EQ(installer.package, match.moduleName); 1757 ASSERT_EQ(installer.version, static_cast<uint64_t>(match.versionCode)); 1758 ASSERT_EQ(installer.test_file, match.modulePath); 1759 1760 ApexSessionInfo session; 1761 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session))) 1762 << GetDebugStr(&installer); 1763 ApexSessionInfo expected = CreateSessionInfo(123); 1764 expected.isVerified = true; 1765 EXPECT_THAT(session, SessionInfoEq(expected)); 1766 1767 ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123))); 1768 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session))) 1769 << GetDebugStr(&installer); 1770 expected.isVerified = false; 1771 expected.isStaged = true; 1772 EXPECT_THAT(session, SessionInfoEq(expected)); 1773 1774 // Call markStagedSessionReady again. Should be a no-op. 1775 ASSERT_TRUE(IsOk(service_->markStagedSessionReady(123))) 1776 << GetDebugStr(&installer); 1777 1778 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(123, &session))) 1779 << GetDebugStr(&installer); 1780 EXPECT_THAT(session, SessionInfoEq(expected)); 1781 1782 // See if the session is reported with getSessions() as well 1783 std::vector<ApexSessionInfo> sessions; 1784 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))) 1785 << GetDebugStr(&installer); 1786 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); 1787 } 1788 1789 TEST_F(ApexServiceTest, SubmitSingleStagedSessionKeepsPreviousSessions) { 1790 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 1791 "/data/app-staging/session_239", 1792 "staging_data_file"); 1793 if (!installer.Prepare()) { 1794 FAIL() << GetDebugStr(&installer); 1795 } 1796 1797 // First simulate existence of a bunch of sessions. 1798 auto session1 = ApexSession::CreateSession(37); 1799 ASSERT_TRUE(IsOk(session1)); 1800 auto session2 = ApexSession::CreateSession(57); 1801 ASSERT_TRUE(IsOk(session2)); 1802 auto session3 = ApexSession::CreateSession(73); 1803 ASSERT_TRUE(IsOk(session3)); 1804 ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED))); 1805 ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED))); 1806 ASSERT_TRUE(IsOk(session3->UpdateStateAndCommit(SessionState::SUCCESS))); 1807 1808 std::vector<ApexSessionInfo> sessions; 1809 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 1810 1811 ApexSessionInfo expected_session1 = CreateSessionInfo(37); 1812 expected_session1.isVerified = true; 1813 ApexSessionInfo expected_session2 = CreateSessionInfo(57); 1814 expected_session2.isStaged = true; 1815 ApexSessionInfo expected_session3 = CreateSessionInfo(73); 1816 expected_session3.isSuccess = true; 1817 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected_session1), 1818 SessionInfoEq(expected_session2), 1819 SessionInfoEq(expected_session3))); 1820 1821 ApexInfoList list; 1822 ApexSessionParams params; 1823 params.sessionId = 239; 1824 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 1825 1826 sessions.clear(); 1827 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 1828 1829 ApexSessionInfo new_session = CreateSessionInfo(239); 1830 new_session.isVerified = true; 1831 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(new_session), 1832 SessionInfoEq(expected_session1), 1833 SessionInfoEq(expected_session2), 1834 SessionInfoEq(expected_session3))); 1835 } 1836 1837 TEST_F(ApexServiceTest, SubmitSingleSessionTestFail) { 1838 PrepareTestApexForInstall installer( 1839 GetTestFile("apex.apexd_test_corrupt_apex.apex"), 1840 "/data/app-staging/session_456", "staging_data_file"); 1841 if (!installer.Prepare()) { 1842 FAIL() << GetDebugStr(&installer); 1843 } 1844 1845 ApexInfoList list; 1846 ApexSessionParams params; 1847 params.sessionId = 456; 1848 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))) 1849 << GetDebugStr(&installer); 1850 1851 ApexSessionInfo session; 1852 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(456, &session))) 1853 << GetDebugStr(&installer); 1854 ApexSessionInfo expected = CreateSessionInfo(-1); 1855 expected.isUnknown = true; 1856 EXPECT_THAT(session, SessionInfoEq(expected)); 1857 } 1858 1859 TEST_F(ApexServiceTest, SubmitMultiSessionTestSuccess) { 1860 // Parent session id: 10 1861 // Children session ids: 20 30 1862 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 1863 "/data/app-staging/session_20", 1864 "staging_data_file"); 1865 PrepareTestApexForInstall installer2( 1866 GetTestFile("apex.apexd_test_different_app.apex"), 1867 "/data/app-staging/session_30", "staging_data_file"); 1868 if (!installer.Prepare() || !installer2.Prepare()) { 1869 FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2); 1870 } 1871 1872 ApexInfoList list; 1873 ApexSessionParams params; 1874 params.sessionId = 10; 1875 params.childSessionIds = {20, 30}; 1876 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))) 1877 << GetDebugStr(&installer); 1878 EXPECT_EQ(2u, list.apexInfos.size()); 1879 ApexInfo match; 1880 bool package1_found = false; 1881 bool package2_found = false; 1882 for (const ApexInfo& info : list.apexInfos) { 1883 if (info.moduleName == installer.package) { 1884 ASSERT_EQ(installer.package, info.moduleName); 1885 ASSERT_EQ(installer.version, static_cast<uint64_t>(info.versionCode)); 1886 ASSERT_EQ(installer.test_file, info.modulePath); 1887 package1_found = true; 1888 } else if (info.moduleName == installer2.package) { 1889 ASSERT_EQ(installer2.package, info.moduleName); 1890 ASSERT_EQ(installer2.version, static_cast<uint64_t>(info.versionCode)); 1891 ASSERT_EQ(installer2.test_file, info.modulePath); 1892 package2_found = true; 1893 } else { 1894 FAIL() << "Unexpected package found " << info.moduleName 1895 << GetDebugStr(&installer) << GetDebugStr(&installer2); 1896 } 1897 } 1898 ASSERT_TRUE(package1_found); 1899 ASSERT_TRUE(package2_found); 1900 1901 ApexSessionInfo session; 1902 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session))) 1903 << GetDebugStr(&installer); 1904 ApexSessionInfo expected = CreateSessionInfo(10); 1905 expected.isVerified = true; 1906 ASSERT_THAT(session, SessionInfoEq(expected)); 1907 1908 ASSERT_TRUE(IsOk(service_->markStagedSessionReady(10))) 1909 << GetDebugStr(&installer); 1910 1911 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(10, &session))) 1912 << GetDebugStr(&installer); 1913 expected.isVerified = false; 1914 expected.isStaged = true; 1915 ASSERT_THAT(session, SessionInfoEq(expected)); 1916 1917 // Check that temp mounts were cleanded up. 1918 for (const auto& mount : GetApexMounts()) { 1919 EXPECT_FALSE(EndsWith(mount, ".tmp")) << "Found temp mount " << mount; 1920 } 1921 } 1922 1923 TEST_F(ApexServiceTest, SubmitMultiSessionTestFail) { 1924 // Parent session id: 11 1925 // Children session ids: 21 31 1926 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex"), 1927 "/data/app-staging/session_21", 1928 "staging_data_file"); 1929 PrepareTestApexForInstall installer2( 1930 GetTestFile("apex.apexd_test_corrupt_apex.apex"), 1931 "/data/app-staging/session_31", "staging_data_file"); 1932 if (!installer.Prepare() || !installer2.Prepare()) { 1933 FAIL() << GetDebugStr(&installer) << GetDebugStr(&installer2); 1934 } 1935 ApexInfoList list; 1936 ApexSessionParams params; 1937 params.sessionId = 11; 1938 params.childSessionIds = {21, 31}; 1939 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))) 1940 << GetDebugStr(&installer); 1941 } 1942 1943 TEST_F(ApexServiceTest, MarkStagedSessionReadyFail) { 1944 // We should fail if we ask information about a session we don't know. 1945 ASSERT_FALSE(IsOk(service_->markStagedSessionReady(666))); 1946 1947 ApexSessionInfo session; 1948 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(666, &session))); 1949 ApexSessionInfo expected = CreateSessionInfo(-1); 1950 expected.isUnknown = true; 1951 ASSERT_THAT(session, SessionInfoEq(expected)); 1952 } 1953 1954 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsNoSession) { 1955 ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(37))); 1956 1957 ApexSessionInfo session_info; 1958 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(37, &session_info))); 1959 ApexSessionInfo expected = CreateSessionInfo(-1); 1960 expected.isUnknown = true; 1961 ASSERT_THAT(session_info, SessionInfoEq(expected)); 1962 } 1963 1964 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulFailsSessionInWrongState) { 1965 auto session = ApexSession::CreateSession(73); 1966 ASSERT_TRUE(IsOk(session)); 1967 ASSERT_TRUE( 1968 IsOk(session->UpdateStateAndCommit(::apex::proto::SessionState::STAGED))); 1969 1970 ASSERT_FALSE(IsOk(service_->markStagedSessionSuccessful(73))); 1971 1972 ApexSessionInfo session_info; 1973 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(73, &session_info))); 1974 ApexSessionInfo expected = CreateSessionInfo(73); 1975 expected.isStaged = true; 1976 ASSERT_THAT(session_info, SessionInfoEq(expected)); 1977 } 1978 1979 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulActivatedSession) { 1980 auto session = ApexSession::CreateSession(239); 1981 ASSERT_TRUE(IsOk(session)); 1982 ASSERT_TRUE(IsOk( 1983 session->UpdateStateAndCommit(::apex::proto::SessionState::ACTIVATED))); 1984 1985 ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(239))); 1986 1987 ApexSessionInfo session_info; 1988 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(239, &session_info))); 1989 ApexSessionInfo expected = CreateSessionInfo(239); 1990 expected.isSuccess = true; 1991 ASSERT_THAT(session_info, SessionInfoEq(expected)); 1992 } 1993 1994 TEST_F(ApexServiceTest, MarkStagedSessionSuccessfulNoOp) { 1995 auto session = ApexSession::CreateSession(1543); 1996 ASSERT_TRUE(IsOk(session)); 1997 ASSERT_TRUE(IsOk( 1998 session->UpdateStateAndCommit(::apex::proto::SessionState::SUCCESS))); 1999 2000 ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(1543))); 2001 2002 ApexSessionInfo session_info; 2003 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(1543, &session_info))); 2004 ApexSessionInfo expected = CreateSessionInfo(1543); 2005 expected.isSuccess = true; 2006 ASSERT_THAT(session_info, SessionInfoEq(expected)); 2007 } 2008 2009 // Should be able to abort individual staged session 2010 TEST_F(ApexServiceTest, AbortStagedSession) { 2011 auto session1 = ApexSession::CreateSession(239); 2012 ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::VERIFIED))); 2013 auto session2 = ApexSession::CreateSession(240); 2014 ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED))); 2015 2016 std::vector<ApexSessionInfo> sessions; 2017 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 2018 ASSERT_EQ(2u, sessions.size()); 2019 2020 ASSERT_TRUE(IsOk(service_->abortStagedSession(239))); 2021 2022 sessions.clear(); 2023 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 2024 ApexSessionInfo expected = CreateSessionInfo(240); 2025 expected.isStaged = true; 2026 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); 2027 } 2028 2029 // abortStagedSession should not abort activated session 2030 TEST_F(ApexServiceTest, AbortStagedSessionActivatedFail) { 2031 auto session1 = ApexSession::CreateSession(239); 2032 ASSERT_TRUE(IsOk(session1->UpdateStateAndCommit(SessionState::ACTIVATED))); 2033 auto session2 = ApexSession::CreateSession(240); 2034 ASSERT_TRUE(IsOk(session2->UpdateStateAndCommit(SessionState::STAGED))); 2035 2036 std::vector<ApexSessionInfo> sessions; 2037 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 2038 ASSERT_EQ(2u, sessions.size()); 2039 2040 ASSERT_FALSE(IsOk(service_->abortStagedSession(239))); 2041 2042 sessions.clear(); 2043 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 2044 ApexSessionInfo expected1 = CreateSessionInfo(239); 2045 expected1.isActivated = true; 2046 ApexSessionInfo expected2 = CreateSessionInfo(240); 2047 expected2.isStaged = true; 2048 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected1), 2049 SessionInfoEq(expected2))); 2050 } 2051 2052 // Only finalized sessions should be deleted on DeleteFinalizedSessions() 2053 TEST_F(ApexServiceTest, DeleteFinalizedSessions) { 2054 // Fetch list of all session state 2055 std::vector<SessionState::State> states; 2056 for (int i = SessionState::State_MIN; i < SessionState::State_MAX; i++) { 2057 if (!SessionState::State_IsValid(i)) { 2058 continue; 2059 } 2060 states.push_back(SessionState::State(i)); 2061 } 2062 2063 // For every session state, create a new session. This is to verify we only 2064 // delete sessions in final state. 2065 auto nonFinalSessions = 0u; 2066 for (auto i = 0u; i < states.size(); i++) { 2067 auto session = ApexSession::CreateSession(230 + i); 2068 SessionState::State state = states[i]; 2069 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(state))); 2070 if (!session->IsFinalized()) { 2071 nonFinalSessions++; 2072 } 2073 } 2074 std::vector<ApexSession> sessions = ApexSession::GetSessions(); 2075 ASSERT_EQ(states.size(), sessions.size()); 2076 2077 // Now try cleaning up all finalized sessions 2078 ApexSession::DeleteFinalizedSessions(); 2079 sessions = ApexSession::GetSessions(); 2080 ASSERT_EQ(nonFinalSessions, sessions.size()); 2081 2082 // Verify only finalized sessions have been deleted 2083 for (auto& session : sessions) { 2084 ASSERT_FALSE(session.IsFinalized()); 2085 } 2086 } 2087 2088 TEST_F(ApexServiceTest, BackupActivePackages) { 2089 if (supports_fs_checkpointing_) { 2090 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2091 } 2092 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); 2093 PrepareTestApexForInstall installer2( 2094 GetTestFile("apex.apexd_test_different_app.apex")); 2095 PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"), 2096 "/data/app-staging/session_23", 2097 "staging_data_file"); 2098 2099 if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) { 2100 return; 2101 } 2102 2103 // Activate some packages, in order to backup them later. 2104 std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file}; 2105 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); 2106 2107 // Make sure that /data/apex/active has activated packages. 2108 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); 2109 ASSERT_TRUE(IsOk(active_pkgs)); 2110 ASSERT_THAT(*active_pkgs, 2111 UnorderedElementsAre(installer1.test_installed_file, 2112 installer2.test_installed_file)); 2113 2114 ApexInfoList list; 2115 ApexSessionParams params; 2116 params.sessionId = 23; 2117 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 2118 2119 auto backups = ReadEntireDir(kApexBackupDir); 2120 ASSERT_TRUE(IsOk(backups)); 2121 auto backup1 = 2122 StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir); 2123 auto backup2 = 2124 StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir); 2125 ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2)); 2126 } 2127 2128 TEST_F(ApexServiceTest, BackupActivePackagesClearsPreviousBackup) { 2129 if (supports_fs_checkpointing_) { 2130 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2131 } 2132 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); 2133 PrepareTestApexForInstall installer2( 2134 GetTestFile("apex.apexd_test_different_app.apex")); 2135 PrepareTestApexForInstall installer3(GetTestFile("apex.apexd_test_v2.apex"), 2136 "/data/app-staging/session_43", 2137 "staging_data_file"); 2138 2139 if (!installer1.Prepare() || !installer2.Prepare() || !installer3.Prepare()) { 2140 return; 2141 } 2142 2143 // Make sure /data/apex/backups exists. 2144 ASSERT_TRUE(IsOk(CreateDirIfNeeded(std::string(kApexBackupDir), 0700))); 2145 // Create some bogus files in /data/apex/backups. 2146 std::ofstream old_backup(StringPrintf("%s/file1", kApexBackupDir)); 2147 ASSERT_TRUE(old_backup.good()); 2148 old_backup.close(); 2149 2150 std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file}; 2151 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); 2152 2153 // Make sure that /data/apex/active has activated packages. 2154 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); 2155 ASSERT_TRUE(IsOk(active_pkgs)); 2156 ASSERT_THAT(*active_pkgs, 2157 UnorderedElementsAre(installer1.test_installed_file, 2158 installer2.test_installed_file)); 2159 2160 ApexInfoList list; 2161 ApexSessionParams params; 2162 params.sessionId = 43; 2163 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 2164 2165 auto backups = ReadEntireDir(kApexBackupDir); 2166 ASSERT_TRUE(IsOk(backups)); 2167 auto backup1 = 2168 StringPrintf("%s/com.android.apex.test_package@1.apex", kApexBackupDir); 2169 auto backup2 = 2170 StringPrintf("%s/com.android.apex.test_package_2@1.apex", kApexBackupDir); 2171 ASSERT_THAT(*backups, UnorderedElementsAre(backup1, backup2)); 2172 } 2173 2174 TEST_F(ApexServiceTest, BackupActivePackagesZeroActivePackages) { 2175 if (supports_fs_checkpointing_) { 2176 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2177 } 2178 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"), 2179 "/data/app-staging/session_41", 2180 "staging_data_file"); 2181 2182 if (!installer.Prepare()) { 2183 return; 2184 } 2185 2186 // Make sure that /data/apex/active exists and is empty 2187 ASSERT_TRUE( 2188 IsOk(CreateDirIfNeeded(std::string(kActiveApexPackagesDataDir), 0755))); 2189 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); 2190 ASSERT_TRUE(IsOk(active_pkgs)); 2191 ASSERT_EQ(0u, active_pkgs->size()); 2192 2193 ApexInfoList list; 2194 ApexSessionParams params; 2195 params.sessionId = 41; 2196 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 2197 2198 auto backups = ReadEntireDir(kApexBackupDir); 2199 ASSERT_TRUE(IsOk(backups)); 2200 ASSERT_EQ(0u, backups->size()); 2201 } 2202 2203 TEST_F(ApexServiceTest, ActivePackagesDirEmpty) { 2204 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex"), 2205 "/data/app-staging/session_41", 2206 "staging_data_file"); 2207 2208 if (!installer.Prepare()) { 2209 return; 2210 } 2211 2212 // Make sure that /data/apex/active is empty 2213 DeleteDirContent(kActiveApexPackagesDataDir); 2214 2215 ApexInfoList list; 2216 ApexSessionParams params; 2217 params.sessionId = 41; 2218 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 2219 2220 if (!supports_fs_checkpointing_) { 2221 auto backups = ReadEntireDir(kApexBackupDir); 2222 ASSERT_TRUE(IsOk(backups)); 2223 ASSERT_EQ(0u, backups->size()); 2224 } 2225 } 2226 2227 TEST_F(ApexServiceTest, UnstagePackagesSuccess) { 2228 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); 2229 PrepareTestApexForInstall installer2( 2230 GetTestFile("apex.apexd_test_different_app.apex")); 2231 2232 if (!installer1.Prepare() || !installer2.Prepare()) { 2233 return; 2234 } 2235 2236 std::vector<std::string> pkgs = {installer1.test_file, installer2.test_file}; 2237 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); 2238 2239 pkgs = {installer2.test_installed_file}; 2240 ASSERT_TRUE(IsOk(service_->unstagePackages(pkgs))); 2241 2242 auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir); 2243 ASSERT_TRUE(IsOk(active_packages)); 2244 ASSERT_THAT(*active_packages, 2245 UnorderedElementsAre(installer1.test_installed_file)); 2246 } 2247 2248 TEST_F(ApexServiceTest, UnstagePackagesFail) { 2249 PrepareTestApexForInstall installer1(GetTestFile("apex.apexd_test.apex")); 2250 PrepareTestApexForInstall installer2( 2251 GetTestFile("apex.apexd_test_different_app.apex")); 2252 2253 if (!installer1.Prepare() || !installer2.Prepare()) { 2254 return; 2255 } 2256 2257 std::vector<std::string> pkgs = {installer1.test_file}; 2258 ASSERT_TRUE(IsOk(service_->stagePackages(pkgs))); 2259 2260 pkgs = {installer1.test_installed_file, installer2.test_installed_file}; 2261 ASSERT_FALSE(IsOk(service_->unstagePackages(pkgs))); 2262 2263 // Check that first package wasn't unstaged. 2264 auto active_packages = ReadEntireDir(kActiveApexPackagesDataDir); 2265 ASSERT_TRUE(IsOk(active_packages)); 2266 ASSERT_THAT(*active_packages, 2267 UnorderedElementsAre(installer1.test_installed_file)); 2268 } 2269 2270 TEST_F(ApexServiceTest, UnstagePackagesFailPreInstalledApex) { 2271 auto status = service_->unstagePackages( 2272 {"/system/apex/com.android.apex.cts.shim.apex"}); 2273 ASSERT_FALSE(IsOk(status)); 2274 const std::string& error_message = 2275 std::string(status.exceptionMessage().c_str()); 2276 ASSERT_THAT(error_message, 2277 HasSubstr("Can't uninstall pre-installed apex " 2278 "/system/apex/com.android.apex.cts.shim.apex")); 2279 ASSERT_TRUE(RegularFileExists("/system/apex/com.android.apex.cts.shim.apex")); 2280 } 2281 2282 class ApexServiceRevertTest : public ApexServiceTest { 2283 protected: 2284 void SetUp() override { ApexServiceTest::SetUp(); } 2285 2286 void PrepareBackup(const std::vector<std::string>& pkgs) { 2287 ASSERT_TRUE(IsOk(CreateDirIfNeeded(std::string(kApexBackupDir), 0700))); 2288 for (const auto& pkg : pkgs) { 2289 PrepareTestApexForInstall installer(pkg); 2290 ASSERT_TRUE(installer.Prepare()) << " failed to prepare " << pkg; 2291 const std::string& from = installer.test_file; 2292 std::string to = std::string(kApexBackupDir) + "/" + installer.package + 2293 "@" + std::to_string(installer.version) + ".apex"; 2294 std::error_code ec; 2295 fs::copy(fs::path(from), fs::path(to), 2296 fs::copy_options::create_hard_links, ec); 2297 ASSERT_FALSE(ec) << "Failed to copy " << from << " to " << to << " : " 2298 << ec; 2299 } 2300 } 2301 2302 void CheckActiveApexContents(const std::vector<std::string>& expected_pkgs) { 2303 // First check that /data/apex/active exists and has correct permissions. 2304 struct stat sd; 2305 ASSERT_EQ(0, stat(kActiveApexPackagesDataDir, &sd)); 2306 ASSERT_EQ(0755u, sd.st_mode & ALLPERMS); 2307 2308 // Now read content and check it contains expected values. 2309 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); 2310 ASSERT_TRUE(IsOk(active_pkgs)); 2311 ASSERT_THAT(*active_pkgs, UnorderedElementsAreArray(expected_pkgs)); 2312 } 2313 }; 2314 2315 // Should be able to revert activated sessions 2316 TEST_F(ApexServiceRevertTest, RevertActiveSessionsSuccessful) { 2317 if (supports_fs_checkpointing_) { 2318 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2319 } 2320 2321 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); 2322 if (!installer.Prepare()) { 2323 return; 2324 } 2325 2326 auto session = ApexSession::CreateSession(1543); 2327 ASSERT_TRUE(IsOk(session)); 2328 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); 2329 2330 // Make sure /data/apex/active is non-empty. 2331 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2332 2333 PrepareBackup({GetTestFile("apex.apexd_test.apex")}); 2334 2335 ASSERT_TRUE(IsOk(service_->revertActiveSessions())); 2336 2337 auto pkg = StringPrintf("%s/com.android.apex.test_package@1.apex", 2338 kActiveApexPackagesDataDir); 2339 SCOPED_TRACE(""); 2340 CheckActiveApexContents({pkg}); 2341 } 2342 2343 // Calling revertActiveSessions should not restore backup on checkpointing 2344 // devices 2345 TEST_F(ApexServiceRevertTest, 2346 RevertActiveSessionsDoesNotRestoreBackupIfCheckpointingSupported) { 2347 if (!supports_fs_checkpointing_) { 2348 GTEST_SKIP() << "Can't run if filesystem checkpointing is not supported"; 2349 } 2350 2351 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); 2352 if (!installer.Prepare()) { 2353 return; 2354 } 2355 2356 auto session = ApexSession::CreateSession(1543); 2357 ASSERT_TRUE(IsOk(session)); 2358 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); 2359 2360 // Make sure /data/apex/active is non-empty. 2361 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2362 2363 PrepareBackup({GetTestFile("apex.apexd_test.apex")}); 2364 2365 ASSERT_TRUE(IsOk(service_->revertActiveSessions())); 2366 2367 // Check that active apexes were not reverted. 2368 auto pkg = StringPrintf("%s/com.android.apex.test_package@2.apex", 2369 kActiveApexPackagesDataDir); 2370 SCOPED_TRACE(""); 2371 CheckActiveApexContents({pkg}); 2372 } 2373 2374 // Should fail to revert active sessions when there are none 2375 TEST_F(ApexServiceRevertTest, RevertActiveSessionsWithoutActiveSessions) { 2376 // This test simulates a situation that should never happen on user builds: 2377 // revertActiveSessions was called, but there were no active sessions. 2378 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); 2379 if (!installer.Prepare()) { 2380 return; 2381 } 2382 2383 // Make sure /data/apex/active is non-empty. 2384 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2385 2386 PrepareBackup({GetTestFile("apex.apexd_test.apex")}); 2387 2388 // Even though backup is there, no sessions are active, hence revert request 2389 // should fail. 2390 ASSERT_FALSE(IsOk(service_->revertActiveSessions())); 2391 } 2392 2393 TEST_F(ApexServiceRevertTest, RevertFailsNoBackupFolder) { 2394 ASSERT_FALSE(IsOk(service_->revertActiveSessions())); 2395 } 2396 2397 TEST_F(ApexServiceRevertTest, RevertFailsNoActivePackagesFolder) { 2398 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test.apex")); 2399 ASSERT_FALSE(IsOk(service_->revertActiveSessions())); 2400 } 2401 2402 TEST_F(ApexServiceRevertTest, MarkStagedSessionSuccessfulCleanupBackup) { 2403 PrepareBackup({GetTestFile("apex.apexd_test.apex"), 2404 GetTestFile("apex.apexd_test_different_app.apex")}); 2405 2406 auto session = ApexSession::CreateSession(101); 2407 ASSERT_TRUE(IsOk(session)); 2408 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); 2409 2410 ASSERT_TRUE(IsOk(service_->markStagedSessionSuccessful(101))); 2411 2412 ASSERT_TRUE(fs::is_empty(fs::path(kApexBackupDir))); 2413 } 2414 2415 TEST_F(ApexServiceRevertTest, ResumesRevert) { 2416 if (supports_fs_checkpointing_) { 2417 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2418 } 2419 PrepareBackup({GetTestFile("apex.apexd_test.apex"), 2420 GetTestFile("apex.apexd_test_different_app.apex")}); 2421 2422 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); 2423 if (!installer.Prepare()) { 2424 return; 2425 } 2426 2427 // Make sure /data/apex/active is non-empty. 2428 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2429 2430 auto session = ApexSession::CreateSession(17239); 2431 ASSERT_TRUE(IsOk(session)); 2432 ASSERT_TRUE( 2433 IsOk(session->UpdateStateAndCommit(SessionState::REVERT_IN_PROGRESS))); 2434 2435 ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded())); 2436 2437 auto pkg1 = StringPrintf("%s/com.android.apex.test_package@1.apex", 2438 kActiveApexPackagesDataDir); 2439 auto pkg2 = StringPrintf("%s/com.android.apex.test_package_2@1.apex", 2440 kActiveApexPackagesDataDir); 2441 SCOPED_TRACE(""); 2442 CheckActiveApexContents({pkg1, pkg2}); 2443 2444 std::vector<ApexSessionInfo> sessions; 2445 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 2446 ApexSessionInfo expected = CreateSessionInfo(17239); 2447 expected.isReverted = true; 2448 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); 2449 } 2450 2451 TEST_F(ApexServiceRevertTest, DoesNotResumeRevert) { 2452 if (supports_fs_checkpointing_) { 2453 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2454 } 2455 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); 2456 if (!installer.Prepare()) { 2457 return; 2458 } 2459 2460 // Make sure /data/apex/active is non-empty. 2461 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2462 2463 auto session = ApexSession::CreateSession(53); 2464 ASSERT_TRUE(IsOk(session)); 2465 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::SUCCESS))); 2466 2467 ASSERT_TRUE(IsOk(service_->resumeRevertIfNeeded())); 2468 2469 // Check that revert wasn't resumed. 2470 auto active_pkgs = ReadEntireDir(kActiveApexPackagesDataDir); 2471 ASSERT_TRUE(IsOk(active_pkgs)); 2472 ASSERT_THAT(*active_pkgs, 2473 UnorderedElementsAre(installer.test_installed_file)); 2474 2475 std::vector<ApexSessionInfo> sessions; 2476 ASSERT_TRUE(IsOk(service_->getSessions(&sessions))); 2477 ApexSessionInfo expected = CreateSessionInfo(53); 2478 expected.isSuccess = true; 2479 ASSERT_THAT(sessions, UnorderedElementsAre(SessionInfoEq(expected))); 2480 } 2481 2482 // Should mark sessions as REVERT_FAILED on failed revert 2483 TEST_F(ApexServiceRevertTest, SessionsMarkedAsRevertFailed) { 2484 if (supports_fs_checkpointing_) { 2485 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2486 } 2487 2488 auto session = ApexSession::CreateSession(53); 2489 ASSERT_TRUE(IsOk(session)); 2490 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); 2491 2492 ASSERT_FALSE(IsOk(service_->revertActiveSessions())); 2493 ApexSessionInfo session_info; 2494 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(53, &session_info))); 2495 ApexSessionInfo expected = CreateSessionInfo(53); 2496 expected.isRevertFailed = true; 2497 ASSERT_THAT(session_info, SessionInfoEq(expected)); 2498 } 2499 2500 TEST_F(ApexServiceRevertTest, RevertFailedStateRevertAttemptFails) { 2501 if (supports_fs_checkpointing_) { 2502 GTEST_SKIP() << "Can't run if filesystem checkpointing is enabled"; 2503 } 2504 2505 auto session = ApexSession::CreateSession(17239); 2506 ASSERT_TRUE(IsOk(session)); 2507 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::REVERT_FAILED))); 2508 2509 ASSERT_FALSE(IsOk(service_->revertActiveSessions())); 2510 ApexSessionInfo session_info; 2511 ASSERT_TRUE(IsOk(service_->getStagedSessionInfo(17239, &session_info))); 2512 ApexSessionInfo expected = CreateSessionInfo(17239); 2513 expected.isRevertFailed = true; 2514 ASSERT_THAT(session_info, SessionInfoEq(expected)); 2515 } 2516 2517 TEST_F(ApexServiceRevertTest, RevertStoresCrashingNativeProcess) { 2518 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); 2519 if (!installer.Prepare()) { 2520 return; 2521 } 2522 auto session = ApexSession::CreateSession(1543); 2523 ASSERT_TRUE(IsOk(session)); 2524 ASSERT_TRUE(IsOk(session->UpdateStateAndCommit(SessionState::ACTIVATED))); 2525 2526 // Make sure /data/apex/active is non-empty. 2527 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2528 std::string native_process = "test_process"; 2529 // TODO(ioffe): this is calling into internals of apexd which makes test quite 2530 // britle. With some refactoring we should be able to call binder api, or 2531 // make this a unit test of apexd.cpp. 2532 Result<void> res = ::android::apex::RevertActiveSessions(native_process, ""); 2533 session = ApexSession::GetSession(1543); 2534 ASSERT_EQ(session->GetCrashingNativeProcess(), native_process); 2535 } 2536 2537 static pid_t GetPidOf(const std::string& name) { 2538 char buf[1024]; 2539 const std::string cmd = std::string("pidof -s ") + name; 2540 FILE* cmd_pipe = popen(cmd.c_str(), "r"); 2541 if (cmd_pipe == nullptr) { 2542 PLOG(ERROR) << "Cannot open pipe for " << cmd; 2543 return 0; 2544 } 2545 if (fgets(buf, 1024, cmd_pipe) == nullptr) { 2546 PLOG(ERROR) << "Cannot read pipe for " << cmd; 2547 pclose(cmd_pipe); 2548 return 0; 2549 } 2550 2551 pclose(cmd_pipe); 2552 return strtoul(buf, nullptr, 10); 2553 } 2554 2555 static void ExecInMountNamespaceOf(pid_t pid, 2556 const std::function<void(pid_t)>& func) { 2557 const std::string my_path = "/proc/self/ns/mnt"; 2558 android::base::unique_fd my_fd(open(my_path.c_str(), O_RDONLY | O_CLOEXEC)); 2559 ASSERT_TRUE(my_fd.get() >= 0); 2560 2561 const std::string target_path = 2562 std::string("/proc/") + std::to_string(pid) + "/ns/mnt"; 2563 android::base::unique_fd target_fd( 2564 open(target_path.c_str(), O_RDONLY | O_CLOEXEC)); 2565 ASSERT_TRUE(target_fd.get() >= 0); 2566 2567 int res = setns(target_fd.get(), CLONE_NEWNS); 2568 ASSERT_NE(-1, res); 2569 2570 func(pid); 2571 2572 res = setns(my_fd.get(), CLONE_NEWNS); 2573 ASSERT_NE(-1, res); 2574 } 2575 2576 TEST(ApexdTest, ApexdIsInSameMountNamespaceAsInit) { 2577 // TODO(b/136647373): Move this check to environment setup 2578 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 2579 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 2580 } 2581 std::string ns_apexd; 2582 std::string ns_init; 2583 2584 ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) { 2585 bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd); 2586 ASSERT_TRUE(res); 2587 }); 2588 2589 ExecInMountNamespaceOf(1, [&](pid_t /*pid*/) { 2590 bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_init); 2591 ASSERT_TRUE(res); 2592 }); 2593 2594 ASSERT_EQ(ns_apexd, ns_init); 2595 } 2596 2597 // These are NOT exhaustive list of early processes be should be enough 2598 static const std::vector<const std::string> kEarlyProcesses = { 2599 "servicemanager", 2600 "hwservicemanager", 2601 "vold", 2602 "logd", 2603 }; 2604 2605 TEST(ApexdTest, EarlyProcessesAreInDifferentMountNamespace) { 2606 // TODO(b/136647373): Move this check to environment setup 2607 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 2608 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 2609 } 2610 std::string ns_apexd; 2611 2612 ExecInMountNamespaceOf(GetPidOf("apexd"), [&](pid_t /*pid*/) { 2613 bool res = android::base::Readlink("/proc/self/ns/mnt", &ns_apexd); 2614 ASSERT_TRUE(res); 2615 }); 2616 2617 for (const auto& name : kEarlyProcesses) { 2618 std::string ns_early_process; 2619 ExecInMountNamespaceOf(GetPidOf(name), [&](pid_t /*pid*/) { 2620 bool res = 2621 android::base::Readlink("/proc/self/ns/mnt", &ns_early_process); 2622 ASSERT_TRUE(res); 2623 }); 2624 ASSERT_NE(ns_apexd, ns_early_process); 2625 } 2626 } 2627 2628 TEST(ApexdTest, ApexIsAPrivateMountPoint) { 2629 // TODO(b/136647373): Move this check to environment setup 2630 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 2631 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 2632 } 2633 std::string mountinfo; 2634 ASSERT_TRUE( 2635 android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo)); 2636 bool found_apex_mountpoint = false; 2637 for (const auto& line : android::base::Split(mountinfo, "\n")) { 2638 std::vector<std::string> tokens = android::base::Split(line, " "); 2639 // line format: 2640 // mnt_id parent_mnt_id major:minor source target option propagation_type 2641 // ex) 33 260:19 / /apex rw,nosuid,nodev - 2642 if (tokens.size() >= 7 && tokens[4] == "/apex") { 2643 found_apex_mountpoint = true; 2644 // Make sure that propagation type is set to - which means private 2645 ASSERT_EQ("-", tokens[6]); 2646 } 2647 } 2648 ASSERT_TRUE(found_apex_mountpoint); 2649 } 2650 2651 static const std::vector<const std::string> kEarlyApexes = { 2652 "/apex/com.android.runtime", 2653 "/apex/com.android.tzdata", 2654 }; 2655 2656 TEST(ApexdTest, ApexesAreActivatedForEarlyProcesses) { 2657 // TODO(b/136647373): Move this check to environment setup 2658 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 2659 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 2660 } 2661 for (const auto& name : kEarlyProcesses) { 2662 pid_t pid = GetPidOf(name); 2663 const std::string path = 2664 std::string("/proc/") + std::to_string(pid) + "/mountinfo"; 2665 std::string mountinfo; 2666 ASSERT_TRUE(android::base::ReadFileToString(path.c_str(), &mountinfo)); 2667 2668 std::unordered_set<std::string> mountpoints; 2669 for (const auto& line : android::base::Split(mountinfo, "\n")) { 2670 std::vector<std::string> tokens = android::base::Split(line, " "); 2671 // line format: 2672 // mnt_id parent_mnt_id major:minor source target option propagation_type 2673 // ex) 69 33 7:40 / /apex/com.android.conscrypt ro,nodev,noatime - 2674 if (tokens.size() >= 5) { 2675 // token[4] is the target mount point 2676 mountpoints.emplace(tokens[4]); 2677 } 2678 } 2679 for (const auto& apex_name : kEarlyApexes) { 2680 ASSERT_NE(mountpoints.end(), mountpoints.find(apex_name)); 2681 } 2682 } 2683 } 2684 2685 class ApexShimUpdateTest : public ApexServiceTest { 2686 protected: 2687 void SetUp() override { 2688 // TODO(b/136647373): Move this check to environment setup 2689 if (!android::base::GetBoolProperty("ro.apex.updatable", false)) { 2690 GTEST_SKIP() << "Skipping test because device doesn't support APEX"; 2691 } 2692 ApexServiceTest::SetUp(); 2693 2694 // Assert that shim apex is pre-installed. 2695 std::vector<ApexInfo> list; 2696 ASSERT_TRUE(IsOk(service_->getAllPackages(&list))); 2697 ApexInfo expected; 2698 expected.moduleName = "com.android.apex.cts.shim"; 2699 expected.modulePath = "/system/apex/com.android.apex.cts.shim.apex"; 2700 expected.preinstalledModulePath = 2701 "/system/apex/com.android.apex.cts.shim.apex"; 2702 expected.versionCode = 1; 2703 expected.isFactory = true; 2704 expected.isActive = true; 2705 ASSERT_THAT(list, Contains(ApexInfoEq(expected))); 2706 } 2707 }; 2708 2709 TEST_F(ApexShimUpdateTest, UpdateToV2Success) { 2710 PrepareTestApexForInstall installer( 2711 GetTestFile("com.android.apex.cts.shim.v2.apex")); 2712 2713 if (!installer.Prepare()) { 2714 FAIL() << GetDebugStr(&installer); 2715 } 2716 2717 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2718 } 2719 2720 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPreInstallHook) { 2721 PrepareTestApexForInstall installer( 2722 GetTestFile("com.android.apex.cts.shim.v2_with_pre_install_hook.apex"), 2723 "/data/app-staging/session_23", "staging_data_file"); 2724 2725 if (!installer.Prepare()) { 2726 FAIL() << GetDebugStr(&installer); 2727 } 2728 2729 ApexInfoList list; 2730 ApexSessionParams params; 2731 params.sessionId = 23; 2732 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 2733 } 2734 2735 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureHasPostInstallHook) { 2736 PrepareTestApexForInstall installer( 2737 GetTestFile("com.android.apex.cts.shim.v2_with_post_install_hook.apex"), 2738 "/data/app-staging/session_43", "staging_data_file"); 2739 2740 if (!installer.Prepare()) { 2741 FAIL() << GetDebugStr(&installer); 2742 } 2743 2744 ApexInfoList list; 2745 ApexSessionParams params; 2746 params.sessionId = 43; 2747 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 2748 } 2749 2750 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFile) { 2751 PrepareTestApexForInstall installer( 2752 GetTestFile("com.android.apex.cts.shim.v2_additional_file.apex"), 2753 "/data/app-staging/session_41", "staging_data_file"); 2754 if (!installer.Prepare()) { 2755 FAIL() << GetDebugStr(&installer); 2756 } 2757 2758 ApexInfoList list; 2759 ApexSessionParams params; 2760 params.sessionId = 41; 2761 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 2762 } 2763 2764 TEST_F(ApexShimUpdateTest, SubmitStagedSessionFailureAdditionalFolder) { 2765 PrepareTestApexForInstall installer( 2766 GetTestFile("com.android.apex.cts.shim.v2_additional_folder.apex"), 2767 "/data/app-staging/session_42", "staging_data_file"); 2768 if (!installer.Prepare()) { 2769 FAIL() << GetDebugStr(&installer); 2770 } 2771 2772 ApexInfoList list; 2773 ApexSessionParams params; 2774 params.sessionId = 42; 2775 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 2776 } 2777 2778 TEST_F(ApexShimUpdateTest, UpdateToV1Success) { 2779 PrepareTestApexForInstall installer( 2780 GetTestFile("com.android.apex.cts.shim.apex")); 2781 2782 if (!installer.Prepare()) { 2783 FAIL() << GetDebugStr(&installer); 2784 } 2785 2786 ASSERT_TRUE(IsOk(service_->stagePackages({installer.test_file}))); 2787 } 2788 2789 TEST_F(ApexShimUpdateTest, SubmitStagedSessionV1ShimApexSuccess) { 2790 PrepareTestApexForInstall installer( 2791 GetTestFile("com.android.apex.cts.shim.apex"), 2792 "/data/app-staging/session_97", "staging_data_file"); 2793 if (!installer.Prepare()) { 2794 FAIL() << GetDebugStr(&installer); 2795 } 2796 2797 ApexInfoList list; 2798 ApexSessionParams params; 2799 params.sessionId = 97; 2800 ASSERT_TRUE(IsOk(service_->submitStagedSession(params, &list))); 2801 } 2802 2803 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFails) { 2804 PrepareTestApexForInstall installer( 2805 GetTestFile("apex.apexd_test_corrupt_apex.apex"), 2806 "/data/app-staging/session_57", "staging_data_file"); 2807 2808 if (!installer.Prepare()) { 2809 FAIL() << GetDebugStr(&installer); 2810 } 2811 2812 ApexInfoList list; 2813 ApexSessionParams params; 2814 params.sessionId = 57; 2815 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 2816 } 2817 2818 TEST_F(ApexServiceTest, SubmitStagedSessionCorruptApexFailsB146895998) { 2819 PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex"), 2820 "/data/app-staging/session_71", 2821 "staging_data_file"); 2822 2823 if (!installer.Prepare()) { 2824 FAIL() << GetDebugStr(&installer); 2825 } 2826 2827 ApexInfoList list; 2828 ApexSessionParams params; 2829 params.sessionId = 71; 2830 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 2831 } 2832 2833 TEST_F(ApexServiceTest, StageCorruptApexFailsB146895998) { 2834 PrepareTestApexForInstall installer(GetTestFile("corrupted_b146895998.apex")); 2835 2836 if (!installer.Prepare()) { 2837 FAIL() << GetDebugStr(&installer); 2838 } 2839 2840 ASSERT_FALSE(IsOk(service_->stagePackages({installer.test_file}))); 2841 } 2842 2843 TEST_F(ApexServiceTest, RemountPackagesPackageOnSystemChanged) { 2844 static constexpr const char* kSystemPath = 2845 "/system_ext/apex/apex.apexd_test.apex"; 2846 static constexpr const char* kPackageName = "com.android.apex.test_package"; 2847 if (!fs_mgr_overlayfs_is_setup()) { 2848 GTEST_SKIP() << "/system_ext is not overlayed into read-write"; 2849 } 2850 if (auto res = IsActive(kPackageName); !res.ok()) { 2851 FAIL() << res.error(); 2852 } else { 2853 ASSERT_FALSE(*res) << kPackageName << " is active"; 2854 } 2855 ASSERT_EQ(0, access(kSystemPath, F_OK)) 2856 << "Failed to stat " << kSystemPath << " : " << strerror(errno); 2857 ASSERT_TRUE(IsOk(service_->activatePackage(kSystemPath))); 2858 std::string backup_path = GetTestFile("apex.apexd_test.apexd.bak"); 2859 // Copy original /system_ext apex file. We will need to restore it after test 2860 // runs. 2861 ASSERT_RESULT_OK(CopyFile(kSystemPath, backup_path, fs::copy_options::none)); 2862 2863 // Make sure we cleanup after ourselves. 2864 auto deleter = android::base::make_scope_guard([&]() { 2865 if (auto ret = service_->deactivatePackage(kSystemPath); !ret.isOk()) { 2866 LOG(ERROR) << ret.exceptionMessage(); 2867 } 2868 auto ret = CopyFile(backup_path, kSystemPath, 2869 fs::copy_options::overwrite_existing); 2870 if (!ret.ok()) { 2871 LOG(ERROR) << ret.error(); 2872 } 2873 }); 2874 2875 // Copy v2 version to /system_ext/apex/ and then call remountPackages. 2876 PrepareTestApexForInstall installer(GetTestFile("apex.apexd_test_v2.apex")); 2877 if (!installer.Prepare()) { 2878 FAIL() << GetDebugStr(&installer); 2879 } 2880 ASSERT_RESULT_OK(CopyFile(installer.test_file, kSystemPath, 2881 fs::copy_options::overwrite_existing)); 2882 // Don't check that remountPackages succeeded. Most likely it will fail, but 2883 // it should still remount our test apex. 2884 service_->remountPackages(); 2885 2886 // Check that v2 is now active. 2887 auto active_apex = GetActivePackage("com.android.apex.test_package"); 2888 ASSERT_RESULT_OK(active_apex); 2889 ASSERT_EQ(2u, active_apex->versionCode); 2890 // Check that module path didn't change, modulo symlink. 2891 std::string realSystemPath; 2892 ASSERT_TRUE(android::base::Realpath(kSystemPath, &realSystemPath)); 2893 ASSERT_EQ(realSystemPath, active_apex->modulePath); 2894 } 2895 2896 TEST_F(ApexServiceActivationSuccessTest, RemountPackagesPackageOnDataChanged) { 2897 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 2898 << GetDebugStr(installer_.get()); 2899 // Copy v2 version to /data/apex/active and then call remountPackages. 2900 PrepareTestApexForInstall installer2(GetTestFile("apex.apexd_test_v2.apex")); 2901 if (!installer2.Prepare()) { 2902 FAIL() << GetDebugStr(&installer2); 2903 } 2904 ASSERT_RESULT_OK(CopyFile(installer2.test_file, 2905 installer_->test_installed_file, 2906 fs::copy_options::overwrite_existing)); 2907 // Don't check that remountPackages succeeded. Most likely it will fail, but 2908 // it should still remount our test apex. 2909 service_->remountPackages(); 2910 2911 // Check that v2 is now active. 2912 auto active_apex = GetActivePackage("com.android.apex.test_package"); 2913 ASSERT_RESULT_OK(active_apex); 2914 ASSERT_EQ(2u, active_apex->versionCode); 2915 // Sanity check that module path didn't change. 2916 ASSERT_EQ(installer_->test_installed_file, active_apex->modulePath); 2917 } 2918 2919 TEST_F(ApexServiceTest, 2920 SubmitStagedSessionFailsManifestMismatchCleansUpHashtree) { 2921 PrepareTestApexForInstall installer( 2922 GetTestFile("apex.apexd_test_no_hashtree_manifest_mismatch.apex"), 2923 "/data/app-staging/session_83", "staging_data_file"); 2924 if (!installer.Prepare()) { 2925 return; 2926 } 2927 2928 ApexInfoList list; 2929 ApexSessionParams params; 2930 params.sessionId = 83; 2931 ASSERT_FALSE(IsOk(service_->submitStagedSession(params, &list))); 2932 std::string hashtree_file = std::string(kApexHashTreeDir) + "/" + 2933 installer.package + "@" + 2934 std::to_string(installer.version) + ".new"; 2935 ASSERT_FALSE(RegularFileExists(hashtree_file)); 2936 } 2937 2938 class LogTestToLogcat : public ::testing::EmptyTestEventListener { 2939 void OnTestStart(const ::testing::TestInfo& test_info) override { 2940 #ifdef __ANDROID__ 2941 using base::LogId; 2942 using base::LogSeverity; 2943 using base::StringPrintf; 2944 base::LogdLogger l; 2945 std::string msg = 2946 StringPrintf("=== %s::%s (%s:%d)", test_info.test_suite_name(), 2947 test_info.name(), test_info.file(), test_info.line()); 2948 l(LogId::MAIN, LogSeverity::INFO, "ApexTestCases", __FILE__, __LINE__, 2949 msg.c_str()); 2950 #else 2951 UNUSED(test_info); 2952 #endif 2953 } 2954 }; 2955 2956 struct NoCodeApexNameProvider { 2957 static std::string GetTestName() { return "apex.apexd_test_nocode.apex"; } 2958 static std::string GetPackageName() { 2959 return "com.android.apex.test_package"; 2960 } 2961 }; 2962 2963 class ApexServiceActivationNoCode 2964 : public ApexServiceActivationTest<NoCodeApexNameProvider> {}; 2965 2966 TEST_F(ApexServiceActivationNoCode, NoCodeApexIsNotExecutable) { 2967 ASSERT_TRUE(IsOk(service_->activatePackage(installer_->test_installed_file))) 2968 << GetDebugStr(installer_.get()); 2969 2970 std::string mountinfo; 2971 ASSERT_TRUE( 2972 android::base::ReadFileToString("/proc/self/mountinfo", &mountinfo)); 2973 bool found_apex_mountpoint = false; 2974 for (const auto& line : android::base::Split(mountinfo, "\n")) { 2975 std::vector<std::string> tokens = android::base::Split(line, " "); 2976 // line format: 2977 // mnt_id parent_mnt_id major:minor source target option propagation_type 2978 // ex) 33 260:19 / /apex rw,nosuid,nodev - 2979 if (tokens.size() >= 7 && 2980 tokens[4] == 2981 "/apex/" + NoCodeApexNameProvider::GetPackageName() + "@1") { 2982 found_apex_mountpoint = true; 2983 // Make sure that option contains noexec 2984 std::vector<std::string> options = android::base::Split(tokens[5], ","); 2985 EXPECT_NE(options.end(), 2986 std::find(options.begin(), options.end(), "noexec")); 2987 break; 2988 } 2989 } 2990 EXPECT_TRUE(found_apex_mountpoint); 2991 } 2992 2993 struct BannedNameProvider { 2994 static std::string GetTestName() { return "sharedlibs.apex"; } 2995 static std::string GetPackageName() { return "sharedlibs"; } 2996 }; 2997 2998 class ApexServiceActivationBannedName 2999 : public ApexServiceActivationTest<BannedNameProvider> { 3000 public: 3001 ApexServiceActivationBannedName() : ApexServiceActivationTest(false) {} 3002 }; 3003 3004 TEST_F(ApexServiceActivationBannedName, ApexWithBannedNameCannotBeActivated) { 3005 ASSERT_FALSE( 3006 IsOk(service_->activatePackage(installer_->test_installed_file))); 3007 } 3008 3009 namespace { 3010 void PrepareCompressedTestApex(const std::string& input_apex, 3011 const std::string& builtin_dir, 3012 const std::string& decompressed_dir, 3013 const std::string& active_apex_dir) { 3014 const Result<ApexFile>& apex_file = ApexFile::Open(input_apex); 3015 ASSERT_TRUE(apex_file.ok()); 3016 ASSERT_TRUE(apex_file->IsCompressed()) << "Not a compressed APEX"; 3017 3018 auto prebuilt_file_path = 3019 builtin_dir + "/" + android::base::Basename(input_apex); 3020 fs::copy(input_apex, prebuilt_file_path); 3021 3022 const ApexManifest& manifest = apex_file->GetManifest(); 3023 const std::string& package = manifest.name(); 3024 const int64_t& version = manifest.version(); 3025 3026 auto decompressed_file_path = decompressed_dir + "/" + package + "@" + 3027 std::to_string(version) + ".apex"; 3028 auto result = apex_file->Decompress(decompressed_file_path); 3029 ASSERT_TRUE(result.ok()) << "Failed to decompress " << result.error(); 3030 auto active_apex_file_path = 3031 active_apex_dir + "/" + package + "@" + std::to_string(version) + ".apex"; 3032 auto error = 3033 link(decompressed_file_path.c_str(), active_apex_file_path.c_str()); 3034 ASSERT_EQ(error, 0) << "Failed to hardlink decompressed APEX"; 3035 } 3036 3037 CompressedApexInfo CreateCompressedApex(const std::string& name, 3038 const int version, const int size) { 3039 CompressedApexInfo result; 3040 result.moduleName = name; 3041 result.versionCode = version; 3042 result.decompressedSize = size; 3043 return result; 3044 } 3045 } // namespace 3046 3047 class ApexServiceTestForCompressedApex : public ApexServiceTest { 3048 public: 3049 static constexpr const char* kTempPrebuiltDir = "/data/apex/temp_prebuilt"; 3050 3051 void SetUp() override { 3052 ApexServiceTest::SetUp(); 3053 ASSERT_NE(nullptr, service_.get()); 3054 3055 TemporaryDir decompression_dir, active_apex_dir; 3056 if (0 != mkdir(kTempPrebuiltDir, 0777)) { 3057 int saved_errno = errno; 3058 ASSERT_EQ(saved_errno, EEXIST) 3059 << kTempPrebuiltDir << ":" << strerror(saved_errno); 3060 } 3061 PrepareCompressedTestApex( 3062 GetTestFile("com.android.apex.compressed.v1.capex"), kTempPrebuiltDir, 3063 kApexDecompressedDir, kActiveApexPackagesDataDir); 3064 service_->recollectPreinstalledData({kTempPrebuiltDir}); 3065 service_->recollectDataApex(kActiveApexPackagesDataDir, 3066 kApexDecompressedDir); 3067 } 3068 3069 void TearDown() override { 3070 ApexServiceTest::TearDown(); 3071 DeleteDirContent(kTempPrebuiltDir); 3072 rmdir(kTempPrebuiltDir); 3073 DeleteDirContent(kApexDecompressedDir); 3074 DeleteDirContent(kActiveApexPackagesDataDir); 3075 } 3076 }; 3077 3078 TEST_F(ApexServiceTestForCompressedApex, CalculateSizeForCompressedApex) { 3079 int64_t result; 3080 // Empty list of compressed apex info 3081 { 3082 CompressedApexInfoList empty_list; 3083 ASSERT_TRUE( 3084 IsOk(service_->calculateSizeForCompressedApex(empty_list, &result))); 3085 ASSERT_EQ(result, 0ll); 3086 } 3087 3088 // Multiple compressed APEX should get summed 3089 { 3090 CompressedApexInfoList non_empty_list; 3091 CompressedApexInfo new_apex = CreateCompressedApex("new_apex", 1, 1); 3092 CompressedApexInfo new_apex_2 = CreateCompressedApex("new_apex_2", 1, 2); 3093 CompressedApexInfo compressed_apex_same_version = 3094 CreateCompressedApex("com.android.apex.compressed", 1, 4); 3095 CompressedApexInfo compressed_apex_higher_version = 3096 CreateCompressedApex("com.android.apex.compressed", 2, 8); 3097 non_empty_list.apexInfos.push_back(new_apex); 3098 non_empty_list.apexInfos.push_back(new_apex_2); 3099 non_empty_list.apexInfos.push_back(compressed_apex_same_version); 3100 non_empty_list.apexInfos.push_back(compressed_apex_higher_version); 3101 ASSERT_TRUE(IsOk( 3102 service_->calculateSizeForCompressedApex(non_empty_list, &result))); 3103 ASSERT_EQ(result, 11ll); // 1+2+8. compressed_apex_same_version is ignored 3104 } 3105 } 3106 3107 TEST_F(ApexServiceTestForCompressedApex, ReserveSpaceForCompressedApex) { 3108 // Multiple compressed APEX should reserve equal to 3109 // CalculateSizeForCompressedApex 3110 { 3111 CompressedApexInfoList non_empty_list; 3112 CompressedApexInfo new_apex = CreateCompressedApex("new_apex", 1, 1); 3113 CompressedApexInfo new_apex_2 = CreateCompressedApex("new_apex_2", 1, 2); 3114 CompressedApexInfo compressed_apex_same_version = 3115 CreateCompressedApex("com.android.apex.compressed", 1, 4); 3116 CompressedApexInfo compressed_apex_higher_version = 3117 CreateCompressedApex("com.android.apex.compressed", 2, 8); 3118 non_empty_list.apexInfos.push_back(new_apex); 3119 non_empty_list.apexInfos.push_back(new_apex_2); 3120 non_empty_list.apexInfos.push_back(compressed_apex_same_version); 3121 non_empty_list.apexInfos.push_back(compressed_apex_higher_version); 3122 int64_t required_size; 3123 ASSERT_TRUE(IsOk(service_->calculateSizeForCompressedApex(non_empty_list, 3124 &required_size))); 3125 ASSERT_EQ(required_size, 3126 11ll); // 1+2+8. compressed_apex_same_version is ignored 3127 3128 ASSERT_TRUE(IsOk(service_->reserveSpaceForCompressedApex(non_empty_list))); 3129 auto files = ReadDir(kOtaReservedDir, [](auto _) { return true; }); 3130 ASSERT_TRUE(IsOk(files)); 3131 ASSERT_EQ(files->size(), 1u); 3132 EXPECT_EQ((int64_t)fs::file_size((*files)[0]), required_size); 3133 } 3134 3135 // Sending empty list should delete reserved file 3136 { 3137 CompressedApexInfoList empty_list; 3138 ASSERT_TRUE(IsOk(service_->reserveSpaceForCompressedApex(empty_list))); 3139 auto files = ReadDir(kOtaReservedDir, [](auto _) { return true; }); 3140 ASSERT_TRUE(IsOk(files)); 3141 ASSERT_EQ(files->size(), 0u); 3142 } 3143 } 3144 3145 } // namespace apex 3146 } // namespace android 3147 3148 int main(int argc, char** argv) { 3149 android::base::InitLogging(argv, &android::base::StderrLogger); 3150 android::base::SetMinimumLogSeverity(android::base::VERBOSE); 3151 ::testing::InitGoogleTest(&argc, argv); 3152 ::testing::UnitTest::GetInstance()->listeners().Append( 3153 new android::apex::LogTestToLogcat()); 3154 return RUN_ALL_TESTS(); 3155 } 3156