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

Commit 96c031b2 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Merge cherrypicks of ['android-review.googlesource.com/3560367',...

Merge cherrypicks of ['android-review.googlesource.com/3560367', 'android-review.googlesource.com/3560368', 'android-review.googlesource.com/3562025'] into 25Q2-release.

Change-Id: Iac89858f66d54789ced30de883a93865c2c365d4
parents 157af3f5 b5583de7
Loading
Loading
Loading
Loading
+8 −16
Original line number Diff line number Diff line
@@ -211,8 +211,8 @@ std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) {
}

#define MODULE_BASE_DIR "/lib/modules"
bool LoadKernelModules(BootMode boot_mode, bool want_console,
                       Modprobe::LoadParallelMode want_parallel_mode, int& modules_loaded) {
bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel,
                       int& modules_loaded) {
    struct utsname uts {};
    if (uname(&uts)) {
        LOG(FATAL) << "Failed to get kernel version.";
@@ -279,9 +279,8 @@ bool LoadKernelModules(BootMode boot_mode, bool want_console,
    }

    Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(boot_mode, MODULE_BASE_DIR));
    bool retval = (want_parallel_mode != Modprobe::LoadParallelMode::NONE) ?
            m.LoadModulesParallel(std::thread::hardware_concurrency(), want_parallel_mode) :
            m.LoadListedModules(!want_console);
    bool retval = (want_parallel) ? m.LoadModulesParallel(std::thread::hardware_concurrency())
                                  : m.LoadListedModules(!want_console);
    modules_loaded = m.GetModuleCount();
    if (modules_loaded > 0) {
        LOG(INFO) << "Loaded " << modules_loaded << " modules from " << MODULE_BASE_DIR;
@@ -438,21 +437,14 @@ int FirstStageMain(int argc, char** argv) {
    }

    auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0;
    auto want_parallel_mode = Modprobe::LoadParallelMode::NONE;
    if (bootconfig.find("androidboot.load_modules_parallel = \"true\"")
        != std::string::npos)
        want_parallel_mode = Modprobe::LoadParallelMode::NORMAL;
    else if (bootconfig.find("androidboot.load_modules_parallel_mode = \"performance\"")
        != std::string::npos)
        want_parallel_mode = Modprobe::LoadParallelMode::PERFORMANCE;
    else if (bootconfig.find("androidboot.load_modules_parallel = \"conservative\"")
        != std::string::npos)
        want_parallel_mode = Modprobe::LoadParallelMode::CONSERVATIVE;
    auto want_parallel =
            bootconfig.find("androidboot.load_modules_parallel = \"true\"") != std::string::npos;

    boot_clock::time_point module_start_time = boot_clock::now();
    int module_count = 0;
    BootMode boot_mode = GetBootMode(cmdline, bootconfig);
    if (!LoadKernelModules(boot_mode, want_console, want_parallel_mode, module_count)) {
    if (!LoadKernelModules(boot_mode, want_console,
                           want_parallel, module_count)) {
        if (want_console != FirstStageConsoleParam::DISABLED) {
            LOG(ERROR) << "Failed to load kernel modules, starting console";
        } else {
+1 −9
Original line number Diff line number Diff line
@@ -28,17 +28,10 @@

class Modprobe {
  public:
    enum LoadParallelMode {
      NONE = 0,
      NORMAL,
      PERFORMANCE,
      CONSERVATIVE,
    };

    Modprobe(const std::vector<std::string>&, const std::string load_file = "modules.load",
             bool use_blocklist = true);

    bool LoadModulesParallel(int num_threads, int mode);
    bool LoadModulesParallel(int num_threads);
    bool LoadListedModules(bool strict = true);
    bool LoadWithAliases(const std::string& module_name, bool strict,
                         const std::string& parameters = "");
@@ -52,7 +45,6 @@ class Modprobe {
    bool IsBlocklisted(const std::string& module_name);

  private:
    bool IsLoadSequential(const std::string& module);
    std::string MakeCanonical(const std::string& module_path);
    bool InsmodWithDeps(const std::string& module_name, const std::string& parameters);
    bool Insmod(const std::string& path_name, const std::string& parameters);
+55 −103
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@
#include <sys/wait.h>

#include <algorithm>
#include <condition_variable>
#include <map>
#include <set>
#include <string>
@@ -507,18 +506,9 @@ bool Modprobe::IsBlocklisted(const std::string& module_name) {
// repeat these steps until all modules are loaded.
// Discard all blocklist.
// Softdeps are taken care in InsmodWithDeps().
bool Modprobe::LoadModulesParallel(int num_threads, int mode) {
    std::map<std::string, std::vector<std::string>> mods_with_deps;
    std::unordered_set<std::string> mods_loading;
    std::vector<std::string> parallel_modules, sequential_modules;
    std::vector<std::thread> threads;
    std::atomic<bool> ret(true);
    std::atomic<bool> finish(false);
    std::mutex mods_to_load_lock;
    std::condition_variable cv_update_module, cv_load_module;
    int sleeping_threads = 0;

    LOG(INFO) << "LoadParallelMode:" << mode;
bool Modprobe::LoadModulesParallel(int num_threads) {
    bool ret = true;
    std::map<std::string, std::vector<std::string>> mod_with_deps;

    // Get dependencies
    for (const auto& module : module_load_) {
@@ -527,61 +517,22 @@ bool Modprobe::LoadModulesParallel(int num_threads, int mode) {
            LOG(VERBOSE) << "LMP: Blocklist: Module " << module << " skipping...";
            continue;
        }

        auto dependencies = GetDependencies(MakeCanonical(module));
        if (dependencies.empty()) {
            LOG(ERROR) << "LMP: Hard-dep: Module " << module
                       << " not in .dep file";
            return false;
        }

        mods_with_deps[MakeCanonical(module)] = dependencies;
    }

    // Consumers load modules in parallel or sequentially
    auto thread_function = [&] {
        while (!mods_with_deps.empty() && ret.load()) {
            std::unique_lock<std::mutex> lock(mods_to_load_lock);

            if (sequential_modules.empty() && parallel_modules.empty()) {
                sleeping_threads++;

                if (mode == LoadParallelMode::PERFORMANCE)
                    cv_update_module.notify_one();
                else if (sleeping_threads == num_threads)
                    cv_update_module.notify_one();

                cv_load_module.wait(lock, [&](){
                    return !parallel_modules.empty() ||
                           !sequential_modules.empty() ||
                           finish.load(); });

                sleeping_threads--;
            }

            while (!sequential_modules.empty()) {
                auto mod_to_load = std::move(sequential_modules.back());
                sequential_modules.pop_back();
                ret.store(ret.load() && LoadWithAliases(mod_to_load, true));
        mod_with_deps[MakeCanonical(module)] = dependencies;
    }

            if (!parallel_modules.empty()) {
                auto mod_to_load = std::move(parallel_modules.back());
                parallel_modules.pop_back();

                lock.unlock();
                ret.store(ret.load() && LoadWithAliases(mod_to_load, true));
            }
        }
    };

    std::generate_n(std::back_inserter(threads), num_threads,
        [&] { return std::thread(thread_function); });
    while (!mod_with_deps.empty()) {
        std::vector<std::thread> threads;
        std::vector<std::string> mods_path_to_load;
        std::mutex vector_lock;

    // Producer check there's any independent module
    while (!mods_with_deps.empty()) {
        std::unique_lock<std::mutex> lock(mods_to_load_lock);
        for (const auto& [it_mod, it_dep] : mods_with_deps) {
        // Find independent modules
        for (const auto& [it_mod, it_dep] : mod_with_deps) {
            auto itd_last = it_dep.rbegin();
            if (itd_last == it_dep.rend())
                continue;
@@ -591,55 +542,69 @@ bool Modprobe::LoadModulesParallel(int num_threads, int mode) {
            if (IsBlocklisted(cnd_last)) {
                LOG(ERROR) << "LMP: Blocklist: Module-dep " << cnd_last
                           << " : failed to load module " << it_mod;
                ret.store(0);
                break;
                return false;
            }

            if (mods_loading.find(cnd_last) == mods_loading.end()) {
                mods_loading.insert(cnd_last);
            std::string str = "load_sequential=1";
            auto it = module_options_[cnd_last].find(str);
            if (it != std::string::npos) {
                module_options_[cnd_last].erase(it, it + str.size());

                if (IsLoadSequential(cnd_last))
                    sequential_modules.emplace_back(cnd_last);
                else
                    parallel_modules.emplace_back(cnd_last);
                if (!LoadWithAliases(cnd_last, true)) {
                    return false;
                }
            } else {
                if (std::find(mods_path_to_load.begin(), mods_path_to_load.end(),
                            cnd_last) == mods_path_to_load.end()) {
                    mods_path_to_load.emplace_back(cnd_last);
                }
            }
        }

        // Load independent modules in parallel
        auto thread_function = [&] {
            std::unique_lock lk(vector_lock);
            while (!mods_path_to_load.empty()) {
                auto ret_load = true;
                auto mod_to_load = std::move(mods_path_to_load.back());
                mods_path_to_load.pop_back();

            if (mode == LoadParallelMode::CONSERVATIVE &&
                parallel_modules.size() >= num_threads)
                break;
                lk.unlock();
                ret_load &= LoadWithAliases(mod_to_load, true);
                lk.lock();
                if (!ret_load) {
                    ret &= ret_load;
                }
            }
        };

        cv_load_module.notify_all();
        cv_update_module.wait(lock, [&](){
            return parallel_modules.empty() &&
                   sequential_modules.empty(); });
        std::generate_n(std::back_inserter(threads), num_threads,
                        [&] { return std::thread(thread_function); });

        // Wait for the threads.
        for (auto& thread : threads) {
            thread.join();
        }

        if (!ret.load())
            break;
        if (!ret) return ret;

        std::lock_guard guard(module_loaded_lock_);
        // Remove loaded module from mods_with_deps
        // Remove loaded module form mod_with_deps and soft dependencies of other modules
        for (const auto& module_loaded : module_loaded_)
            mods_with_deps.erase(module_loaded);
            mod_with_deps.erase(module_loaded);

        // Remove loaded module from dependency list
        // Remove loaded module form dependencies of other modules which are not loaded yet
        for (const auto& module_loaded_path : module_loaded_paths_) {
            for (auto& [mod, deps] : mods_with_deps) {
            for (auto& [mod, deps] : mod_with_deps) {
                auto it = std::find(deps.begin(), deps.end(), module_loaded_path);
                if (it != deps.end())
                if (it != deps.end()) {
                    deps.erase(it);
                }
            }
        }

    finish.store(true);
    cv_load_module.notify_all();

    for (auto& thread : threads) {
        thread.join();
    }

    return ret.load();
    return ret;
}

bool Modprobe::LoadListedModules(bool strict) {
@@ -676,19 +641,6 @@ std::vector<std::string> Modprobe::ListModules(const std::string& pattern) {
    return rv;
}

bool Modprobe::IsLoadSequential(const std::string& module)
{
    std::string str = "load_sequential=1";
    auto it = module_options_[module].find(str);

    if (it != std::string::npos) {
        module_options_[module].erase(it, it + str.size());
        return true;
    }

    return false;
}

bool Modprobe::GetAllDependencies(const std::string& module,
                                  std::vector<std::string>* pre_dependencies,
                                  std::vector<std::string>* dependencies,