diff options
Diffstat (limited to 'cmds/installd/otapreopt_chroot.cpp')
-rw-r--r-- | cmds/installd/otapreopt_chroot.cpp | 126 |
1 files changed, 92 insertions, 34 deletions
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index 6459805ba3..c62734a925 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -20,16 +20,19 @@ #include <sys/stat.h> #include <sys/wait.h> +#include <array> +#include <fstream> #include <sstream> +#include <android-base/file.h> #include <android-base/logging.h> #include <android-base/macros.h> +#include <android-base/scopeguard.h> #include <android-base/stringprintf.h> +#include <android-base/unique_fd.h> #include <libdm/dm.h> #include <selinux/android.h> -#include <apexd.h> - #include "installd_constants.h" #include "otapreopt_utils.h" @@ -59,28 +62,23 @@ static void CloseDescriptor(const char* descriptor_string) { } } -static std::vector<apex::ApexFile> ActivateApexPackages() { - // The logic here is (partially) copied and adapted from - // system/apex/apexd/apexd.cpp. - // - // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir). - std::vector<const char*> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir, - apex::kApexPackageVendorDir}; - for (const auto& dir : apex_dirs) { - // Cast call to void to suppress warn_unused_result. - static_cast<void>(apex::scanPackagesDirAndActivate(dir)); +static void ActivateApexPackages() { + std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--otachroot-bootstrap"}; + std::string apexd_error_msg; + + bool exec_result = Exec(apexd_cmd, &apexd_error_msg); + if (!exec_result) { + PLOG(ERROR) << "Running otapreopt failed: " << apexd_error_msg; + exit(220); } - return apex::getActivePackages(); } -static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) { - for (const apex::ApexFile& apex_file : active_packages) { - const std::string& package_path = apex_file.GetPath(); - base::Result<void> status = apex::deactivatePackage(package_path); - if (!status.ok()) { - LOG(ERROR) << "Failed to deactivate " << package_path << ": " - << status.error(); - } +static void DeactivateApexPackages() { + std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"}; + std::string apexd_error_msg; + bool exec_result = Exec(apexd_cmd, &apexd_error_msg); + if (!exec_result) { + PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg; } } @@ -181,6 +179,18 @@ static int otapreopt_chroot(const int argc, char **arg) { // want it for product APKs. Same notes as vendor above. TryExtraMount("product", arg[2], "/postinstall/product"); + // Try to mount the system_ext partition. update_engine doesn't do this for + // us, but we want it for system_ext APKs. Same notes as vendor and product + // above. + TryExtraMount("system_ext", arg[2], "/postinstall/system_ext"); + + constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig"; + // Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot + if (mount("tmpfs", kPostInstallLinkerconfig, "tmpfs", 0, nullptr) != 0) { + PLOG(ERROR) << "Failed to mount a tmpfs for " << kPostInstallLinkerconfig; + exit(215); + } + // Setup APEX mount point and its security context. static constexpr const char* kPostinstallApexDir = "/postinstall/apex"; // The following logic is similar to the one in system/core/rootdir/init.rc: @@ -236,20 +246,71 @@ static int otapreopt_chroot(const int argc, char **arg) { exit(205); } + // Call apexd --unmount-all to free up loop and dm block devices, so that we can re-use + // them during the next invocation. Since otapreopt_chroot calls exit in case something goes + // wrong we need to register our own atexit handler. + // We want to register this handler before actually activating apex packages. This is mostly + // due to the fact that if fail to unmount apexes, then on the next run of otapreopt_chroot + // we will ask for new loop devices instead of re-using existing ones, and we really don't want + // to do that. :) + if (atexit(DeactivateApexPackages) != 0) { + LOG(ERROR) << "Failed to register atexit hander"; + exit(206); + } + // Try to mount APEX packages in "/apex" in the chroot dir. We need at least // the ART APEX, as it is required by otapreopt to run dex2oat. - std::vector<apex::ApexFile> active_packages = ActivateApexPackages(); - + ActivateApexPackages(); + + auto cleanup = android::base::make_scope_guard([](){ + std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"}; + std::string apexd_error_msg; + bool exec_result = Exec(apexd_cmd, &apexd_error_msg); + if (!exec_result) { + PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg; + } + }); // Check that an ART APEX has been activated; clean up and exit // early otherwise. - if (std::none_of(active_packages.begin(), - active_packages.end(), - [](const apex::ApexFile& package){ - return package.GetManifest().name() == "com.android.art"; - })) { - LOG(FATAL_WITHOUT_ABORT) << "No activated com.android.art APEX package."; - DeactivateApexPackages(active_packages); - exit(217); + static constexpr const std::string_view kRequiredApexs[] = { + "com.android.art", + "com.android.runtime", + "com.android.sdkext", // For derive_classpath + }; + std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false }; + DIR* apex_dir = opendir("/apex"); + if (apex_dir == nullptr) { + PLOG(ERROR) << "unable to open /apex"; + exit(220); + } + for (dirent* entry = readdir(apex_dir); entry != nullptr; entry = readdir(apex_dir)) { + for (int i = 0; i < found_apexs.size(); i++) { + if (kRequiredApexs[i] == std::string_view(entry->d_name)) { + found_apexs[i] = true; + break; + } + } + } + closedir(apex_dir); + auto it = std::find(found_apexs.cbegin(), found_apexs.cend(), false); + if (it != found_apexs.cend()) { + LOG(ERROR) << "No activated " << kRequiredApexs[std::distance(found_apexs.cbegin(), it)] + << " package!"; + exit(221); + } + + // Setup /linkerconfig. Doing it after the chroot means it doesn't need its own category + if (selinux_android_restorecon("/linkerconfig", 0) < 0) { + PLOG(ERROR) << "Failed to restorecon /linkerconfig"; + exit(219); + } + std::vector<std::string> linkerconfig_cmd{"/apex/com.android.runtime/bin/linkerconfig", + "--target", "/linkerconfig"}; + std::string linkerconfig_error_msg; + bool linkerconfig_exec_result = Exec(linkerconfig_cmd, &linkerconfig_error_msg); + if (!linkerconfig_exec_result) { + LOG(ERROR) << "Running linkerconfig failed: " << linkerconfig_error_msg; + exit(218); } // Now go on and run otapreopt. @@ -272,9 +333,6 @@ static int otapreopt_chroot(const int argc, char **arg) { LOG(ERROR) << "Running otapreopt failed: " << error_msg; } - // Tear down the work down by the apexd logic. (i.e. deactivate packages). - DeactivateApexPackages(active_packages); - if (!exec_result) { exit(213); } |