summaryrefslogtreecommitdiff
path: root/dexopt_chroot_setup
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2024-05-03 13:07:59 +0100
committer Jiakai Zhang <jiakaiz@google.com> 2024-05-24 18:21:21 +0000
commit31c355a3ecf77be13ad904722631a29e712fcd90 (patch)
tree79eade11a3aaefdfecfd872539bfdc7ee40852e6 /dexopt_chroot_setup
parent824b7e58b01e063a66dfcfd45cf55dc0804071f3 (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')
-rw-r--r--dexopt_chroot_setup/binder/com/android/server/art/IDexoptChrootSetup.aidl10
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup.cc42
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup.h4
-rw-r--r--dexopt_chroot_setup/dexopt_chroot_setup_test.cc7
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