Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ca8b86c authored by Alex Light's avatar Alex Light
Browse files

Use apexd to set up chroot apex dir

Directly including elements of apexd into the otapreopt_chroot binary
has caused issues when apexd and installd fall out of sync. To avoid
this happening in the future move all apex setup into the apexd
binary and invoke it.

Bug: 181182967
Test: Manual OTA of blueline

Change-Id: I70ecff434e01e543045800ff9f8ff6b567530c33
parent fa8dc0f6
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -189,8 +189,8 @@ cc_binary {
        "liblog",
        "liblog",
        "libutils",
        "libutils",
    ],
    ],
    static_libs: [
    required: [
        "libapexd",
      "apexd"
    ],
    ],
}
}


+28 −57
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/wait.h>


#include <array>
#include <fstream>
#include <fstream>
#include <sstream>
#include <sstream>


@@ -31,10 +32,6 @@
#include <libdm/dm.h>
#include <libdm/dm.h>
#include <selinux/android.h>
#include <selinux/android.h>


#include <apex_file_repository.h>
#include <apex_constants.h>
#include <apexd.h>

#include "installd_constants.h"
#include "installd_constants.h"
#include "otapreopt_utils.h"
#include "otapreopt_utils.h"


@@ -64,47 +61,14 @@ static void CloseDescriptor(const char* descriptor_string) {
    }
    }
}
}


static std::vector<apex::ApexFile> ActivateApexPackages() {
static void ActivateApexPackages() {
    // The logic here is (partially) copied and adapted from
    std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--otachroot-bootstrap"};
    // system/apex/apexd/apexd.cpp.
    std::string apexd_error_msg;
    //
    // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir).
    std::vector<std::string> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir,
                                       apex::kApexPackageVendorDir};
    // Initialize ApexFileRepository used internally in ScanPackagesDirAndActivate.
    // This is a quick fix to fix apex activation in otapreopt_chroot.
    apex::ApexFileRepository::GetInstance().AddPreInstalledApex(apex_dirs);
    for (const auto& dir : apex_dirs) {
        // Cast call to void to suppress warn_unused_result.
        static_cast<void>(apex::ScanPackagesDirAndActivate(dir.c_str()));
    }
    return apex::GetActivePackages();
}

static void CreateApexInfoList(const std::vector<apex::ApexFile>& apex_files) {
    // Setup the apex-info-list.xml file
    const std::string apex_info_file = std::string(apex::kApexRoot) + "/" + apex::kApexInfoList;
    std::fstream xml(apex_info_file.c_str(), std::ios::out | std::ios::trunc);
    if (!xml.is_open()) {
        PLOG(ERROR) << "Failed to open " << apex_info_file;
        exit(216);
    }

    // we do not care about inactive apexs
    std::vector<apex::ApexFile> inactive;
    apex::CollectApexInfoList(xml, apex_files, inactive);
    xml.flush();
    xml.close();
}


static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
    bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
    for (const apex::ApexFile& apex_file : active_packages) {
    if (!exec_result) {
        const std::string& package_path = apex_file.GetPath();
        PLOG(ERROR) << "Running otapreopt failed: " << apexd_error_msg;
        base::Result<void> status = apex::DeactivatePackage(package_path);
        exit(220);
        if (!status.ok()) {
            LOG(ERROR) << "Failed to deactivate " << package_path << ": "
                       << status.error();
        }
    }
    }
}
}


@@ -269,8 +233,7 @@ static int otapreopt_chroot(const int argc, char **arg) {


    // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
    // 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.
    // the ART APEX, as it is required by otapreopt to run dex2oat.
    std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
    ActivateApexPackages();
    CreateApexInfoList(active_packages);


    // Check that an ART APEX has been activated; clean up and exit
    // Check that an ART APEX has been activated; clean up and exit
    // early otherwise.
    // early otherwise.
@@ -278,16 +241,27 @@ static int otapreopt_chroot(const int argc, char **arg) {
      "com.android.art",
      "com.android.art",
      "com.android.runtime",
      "com.android.runtime",
    };
    };
    for (std::string_view apex : kRequiredApexs) {
    std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false };
        if (std::none_of(active_packages.begin(), active_packages.end(),
    DIR* apex_dir = opendir("/apex");
                         [&](const apex::ApexFile& package) {
    if (apex_dir == nullptr) {
                             return package.GetManifest().name() == apex;
        PLOG(ERROR) << "unable to open /apex";
                         })) {
        exit(220);
            LOG(FATAL_WITHOUT_ABORT) << "No activated " << apex << " APEX package.";
    }
            DeactivateApexPackages(active_packages);
    for (dirent* entry = readdir(apex_dir); entry != nullptr; entry = readdir(apex_dir)) {
            exit(217);
        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
    // Setup /linkerconfig. Doing it after the chroot means it doesn't need its own category
    if (selinux_android_restorecon("/linkerconfig", 0) < 0) {
    if (selinux_android_restorecon("/linkerconfig", 0) < 0) {
@@ -323,9 +297,6 @@ static int otapreopt_chroot(const int argc, char **arg) {
        LOG(ERROR) << "Running otapreopt failed: " << error_msg;
        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) {
    if (!exec_result) {
        exit(213);
        exit(213);
    }
    }