summaryrefslogtreecommitdiff
path: root/cmds/installd/otapreopt_chroot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/installd/otapreopt_chroot.cpp')
-rw-r--r--cmds/installd/otapreopt_chroot.cpp126
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);
}