diff options
author | 2024-05-03 13:07:59 +0100 | |
---|---|---|
committer | 2024-05-24 18:21:21 +0000 | |
commit | 31c355a3ecf77be13ad904722631a29e712fcd90 (patch) | |
tree | 79eade11a3aaefdfecfd872539bfdc7ee40852e6 /dexopt_chroot_setup | |
parent | 824b7e58b01e063a66dfcfd45cf55dc0804071f3 (diff) |
Add system requirement check.
It checks that the old system is at most one dessert release older than
the new one.
Bug: 311377497
Test: m test-art-host-gtest-art_artd_tests
Change-Id: Idd4e15d3ee03b3b1abceb707e592b88cb66fd757
Diffstat (limited to 'dexopt_chroot_setup')
4 files changed, 62 insertions, 1 deletions
diff --git a/dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl b/dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl index 0b50d22778..b0a5e31488 100644 --- a/dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl +++ b/dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl @@ -22,13 +22,21 @@ interface IDexoptChrootSetup { const @utf8InCpp String CHROOT_DIR = PRE_REBOOT_DEXOPT_DIR + "/chroot"; /** - * Sets up the chroot environment. + * Sets up the chroot environment. All files in chroot, except apexes and the linker config, are + * accessible after this method is called. * * @param otaSlot The slot that contains the OTA update, "_a" or "_b", or null for a Mainline * update. */ void setUp(@nullable @utf8InCpp String otaSlot); + /** + * Initializes the chroot environment. Can only be called after {@link #setUp}. Apexes and + * the linker config in chroot are accessible, and binaries are executable in chroot, after + * this method is called. + */ + void init(); + /** Tears down the chroot environment. */ void tearDown(); } diff --git a/dexopt_chroot_setup/dexopt_chroot_setup.cc b/dexopt_chroot_setup/dexopt_chroot_setup.cc index 35343c5b3c..6f01851e3d 100644 --- a/dexopt_chroot_setup/dexopt_chroot_setup.cc +++ b/dexopt_chroot_setup/dexopt_chroot_setup.cc @@ -68,6 +68,7 @@ using ::android::base::SetProperty; using ::android::base::Split; using ::android::base::Tokenize; using ::android::base::WaitForProperty; +using ::android::base::WriteStringToFile; using ::android::fs_mgr::FstabEntry; using ::art::tools::CmdlineBuilder; using ::art::tools::Fatal; @@ -79,6 +80,8 @@ using ::ndk::ScopedAStatus; constexpr const char* kServiceName = "dexopt_chroot_setup"; const NoDestructor<std::string> kBindMountTmpDir( std::string(DexoptChrootSetup::PRE_REBOOT_DEXOPT_DIR) + "/mount_tmp"); +const NoDestructor<std::string> kOtaSlotFile(std::string(DexoptChrootSetup::PRE_REBOOT_DEXOPT_DIR) + + "/ota_slot"); constexpr mode_t kChrootDefaultMode = 0755; constexpr std::chrono::milliseconds kSnapshotCtlTimeout = std::chrono::seconds(60); @@ -303,6 +306,20 @@ Result<void> MountTmpfs(const std::string& target, std::string_view se_context) return {}; } +Result<std::optional<std::string>> LoadOtaSlotFile() { + std::string content; + if (!ReadFileToString(*kOtaSlotFile, &content)) { + return ErrnoErrorf("Failed to read '{}'", *kOtaSlotFile); + } + if (content == "_a" || content == "_b") { + return content; + } + if (content.empty()) { + return std::nullopt; + } + return Errorf("Invalid content of '{}': '{}'", *kOtaSlotFile, content); +} + } // namespace ScopedAStatus DexoptChrootSetup::setUp(const std::optional<std::string>& in_otaSlot) { @@ -318,6 +335,16 @@ ScopedAStatus DexoptChrootSetup::setUp(const std::optional<std::string>& in_otaS return ScopedAStatus::ok(); } +ScopedAStatus DexoptChrootSetup::init() { + if (!mu_.try_lock()) { + return Fatal("Unexpected concurrent calls"); + } + std::lock_guard<std::mutex> lock(mu_, std::adopt_lock); + + OR_RETURN_NON_FATAL(InitChroot()); + return ScopedAStatus::ok(); +} + ScopedAStatus DexoptChrootSetup::tearDown() { if (!mu_.try_lock()) { return Fatal("Unexpected concurrent calls"); @@ -406,6 +433,16 @@ Result<void> DexoptChrootSetup::SetUpChroot(const std::optional<std::string>& ot OR_RETURN(BindMountRecursive(src, PathInChroot(src))); } + if (!WriteStringToFile(ota_slot.value_or(""), *kOtaSlotFile)) { + return ErrnoErrorf("Failed to write '{}'", *kOtaSlotFile); + } + + return {}; +} + +Result<void> DexoptChrootSetup::InitChroot() const { + std::optional<std::string> ota_slot = OR_RETURN(LoadOtaSlotFile()); + // Generate empty linker config to suppress warnings. if (!android::base::WriteStringToFile("", PathInChroot("/linkerconfig/ld.config.txt"))) { PLOG(WARNING) << "Failed to generate empty linker config to suppress warnings"; @@ -482,6 +519,11 @@ Result<void> DexoptChrootSetup::TearDownChroot() const { return Errorf("Failed to remove dir '{}': {}", *kBindMountTmpDir, ec.message()); } + std::filesystem::remove(*kOtaSlotFile, ec); + if (ec) { + return Errorf("Failed to remove file '{}': {}", *kOtaSlotFile, ec.message()); + } + if (!SetProperty("sys.snapshotctl.unmap", "requested")) { return Errorf("Failed to request snapshotctl unmap"); } diff --git a/dexopt_chroot_setup/dexopt_chroot_setup.h b/dexopt_chroot_setup/dexopt_chroot_setup.h index baceb1a480..466471b5ed 100644 --- a/dexopt_chroot_setup/dexopt_chroot_setup.h +++ b/dexopt_chroot_setup/dexopt_chroot_setup.h @@ -32,6 +32,8 @@ class DexoptChrootSetup : public aidl::com::android::server::art::BnDexoptChroot public: ndk::ScopedAStatus setUp(const std::optional<std::string>& in_otaSlot) override; + ndk::ScopedAStatus init() override; + ndk::ScopedAStatus tearDown() override; android::base::Result<void> Start(); @@ -40,6 +42,8 @@ class DexoptChrootSetup : public aidl::com::android::server::art::BnDexoptChroot android::base::Result<void> SetUpChroot(const std::optional<std::string>& ota_slot) const REQUIRES(mu_); + android::base::Result<void> InitChroot() const REQUIRES(mu_); + android::base::Result<void> TearDownChroot() const REQUIRES(mu_); std::mutex mu_; diff --git a/dexopt_chroot_setup/dexopt_chroot_setup_test.cc b/dexopt_chroot_setup/dexopt_chroot_setup_test.cc index bfa38e0aa0..2b90bb941f 100644 --- a/dexopt_chroot_setup/dexopt_chroot_setup_test.cc +++ b/dexopt_chroot_setup/dexopt_chroot_setup_test.cc @@ -103,6 +103,7 @@ TEST_F(DexoptChrootSetupTest, Run) { // We only test the Mainline update case here. There isn't an easy way to test the OTA update case // in such a unit test. The OTA update case is assumed to be covered by the E2E test. ASSERT_STATUS_OK(dexopt_chroot_setup_->setUp(/*in_otaSlot=*/std::nullopt)); + ASSERT_STATUS_OK(dexopt_chroot_setup_->init()); // Some important dirs that should be the same as outside. std::vector<const char*> same_dirs = { @@ -173,6 +174,7 @@ TEST_F(DexoptChrootSetupTest, Run) { // caller (typically system_server) called `setUp` and crashed later, and a new instance called // `setUp` again. ASSERT_STATUS_OK(dexopt_chroot_setup_->setUp(/*in_otaSlot=*/std::nullopt)); + ASSERT_STATUS_OK(dexopt_chroot_setup_->init()); ASSERT_STATUS_OK(dexopt_chroot_setup_->tearDown()); @@ -180,6 +182,11 @@ TEST_F(DexoptChrootSetupTest, Run) { // Check that `tearDown` can be repetitively called too. ASSERT_STATUS_OK(dexopt_chroot_setup_->tearDown()); + + // Check that `setUp` can be followed directly by a `tearDown`. + ASSERT_STATUS_OK(dexopt_chroot_setup_->setUp(/*in_otaSlot=*/std::nullopt)); + ASSERT_STATUS_OK(dexopt_chroot_setup_->tearDown()); + EXPECT_FALSE(std::filesystem::exists(DexoptChrootSetup::CHROOT_DIR)); } } // namespace |