From 21cad321db247a84633e118667c8f267da1a1de2 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Fri, 18 Sep 2020 14:41:22 +0900 Subject: [PATCH] ueventd: scans /apex/*/firmware for firmwares In addition to "firmware_directories", ueventd scans /apex/*/firmware/ directory as well to find firmware files. Bug: 167942098 Test: loading firmware from vibrator apex successfully. (sunfish) Change-Id: I90fc8f9ad843a08b1ca98a2be1b5d22c0c5954a3 --- init/README.ueventd.md | 2 ++ init/firmware_handler.cpp | 46 +++++++++++++++++++++++++++++++++------ init/firmware_handler.h | 2 ++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/init/README.ueventd.md b/init/README.ueventd.md index 053ebf813..0f584b2c3 100644 --- a/init/README.ueventd.md +++ b/init/README.ueventd.md @@ -86,6 +86,8 @@ Ueventd by default serves firmware requests by searching through a list of firmw for a file matching the uevent `FIRMWARE`. It then forks a process to serve this firmware to the kernel. +`/apex/*/firmware` is also searched after a list of firmware directories. + The list of firmware directories is customized by a `firmware_directories` line in a ueventd.rc file. This line takes the format of diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp index dff7b6948..b50b4efa1 100644 --- a/init/firmware_handler.cpp +++ b/init/firmware_handler.cpp @@ -17,6 +17,7 @@ #include "firmware_handler.h" #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include @@ -203,25 +205,28 @@ void FirmwareHandler::ProcessFirmwareEvent(const std::string& root, } std::vector attempted_paths_and_errors; - - int booting = IsBooting(); -try_loading_again: - attempted_paths_and_errors.clear(); - for (const auto& firmware_directory : firmware_directories_) { + auto TryLoadFirmware = [&](const std::string& firmware_directory) { std::string file = firmware_directory + firmware; unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC)); if (fw_fd == -1) { attempted_paths_and_errors.emplace_back("firmware: attempted " + file + ", open failed: " + strerror(errno)); - continue; + return false; } struct stat sb; if (fstat(fw_fd, &sb) == -1) { attempted_paths_and_errors.emplace_back("firmware: attempted " + file + ", fstat failed: " + strerror(errno)); - continue; + return false; } LoadFirmware(firmware, root, fw_fd, sb.st_size, loading_fd, data_fd); + return true; + }; + + int booting = IsBooting(); +try_loading_again: + attempted_paths_and_errors.clear(); + if (ForEachFirmwareDirectory(TryLoadFirmware)) { return; } @@ -242,6 +247,33 @@ try_loading_again: write(loading_fd, "-1", 2); } +bool FirmwareHandler::ForEachFirmwareDirectory( + std::function handler) const { + for (const std::string& firmware_directory : firmware_directories_) { + if (std::invoke(handler, firmware_directory)) { + return true; + } + } + + glob_t glob_result; + glob("/apex/*/firmware/", GLOB_MARK, nullptr, &glob_result); + auto free_glob = android::base::make_scope_guard(std::bind(&globfree, &glob_result)); + for (size_t i = 0; i < glob_result.gl_pathc; i++) { + char* apex_firmware_directory = glob_result.gl_pathv[i]; + // Filter-out /apex/@ paths. The paths are bind-mounted to + // /apex/ paths, so unless we filter them out, we will look into the + // same apex twice. + if (strchr(apex_firmware_directory, '@')) { + continue; + } + if (std::invoke(handler, apex_firmware_directory)) { + return true; + } + } + + return false; +} + void FirmwareHandler::HandleUevent(const Uevent& uevent) { if (uevent.subsystem != "firmware" || uevent.action != "add") return; diff --git a/init/firmware_handler.h b/init/firmware_handler.h index b4138f127..8b758aee7 100644 --- a/init/firmware_handler.h +++ b/init/firmware_handler.h @@ -18,6 +18,7 @@ #include +#include #include #include @@ -52,6 +53,7 @@ class FirmwareHandler : public UeventHandler { const Uevent& uevent) const; std::string GetFirmwarePath(const Uevent& uevent) const; void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const; + bool ForEachFirmwareDirectory(std::function handler) const; std::vector firmware_directories_; std::vector external_firmware_handlers_;