diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp index ba7e6bd63..bdc292275 100644 --- a/init/firmware_handler.cpp +++ b/init/firmware_handler.cpp @@ -17,6 +17,7 @@ #include "firmware_handler.h" #include +#include #include #include #include @@ -46,6 +47,20 @@ using android::base::WriteFully; namespace android { namespace init { +namespace { +bool PrefixMatch(const std::string& pattern, const std::string& path) { + return android::base::StartsWith(path, pattern); +} + +bool FnMatch(const std::string& pattern, const std::string& path) { + return fnmatch(pattern.c_str(), path.c_str(), 0) == 0; +} + +bool EqualMatch(const std::string& pattern, const std::string& path) { + return pattern == path; +} +} // namespace + static void LoadFirmware(const std::string& firmware, const std::string& root, int fw_fd, size_t fw_size, int loading_fd, int data_fd) { // Start transfer. @@ -66,6 +81,22 @@ static bool IsBooting() { return access("/dev/.booting", F_OK) == 0; } +ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, + std::string handler_path) + : devpath(std::move(devpath)), uid(uid), handler_path(std::move(handler_path)) { + auto wildcard_position = this->devpath.find('*'); + if (wildcard_position != std::string::npos) { + if (wildcard_position == this->devpath.length() - 1) { + this->devpath.pop_back(); + match = std::bind(PrefixMatch, this->devpath, std::placeholders::_1); + } else { + match = std::bind(FnMatch, this->devpath, std::placeholders::_1); + } + } else { + match = std::bind(EqualMatch, this->devpath, std::placeholders::_1); + } +} + FirmwareHandler::FirmwareHandler(std::vector firmware_directories, std::vector external_firmware_handlers) : firmware_directories_(std::move(firmware_directories)), @@ -160,7 +191,7 @@ Result FirmwareHandler::RunExternalHandler(const std::string& handl std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const { for (const auto& external_handler : external_firmware_handlers_) { - if (external_handler.devpath == uevent.path) { + if (external_handler.match(uevent.path)) { LOG(INFO) << "Launching external firmware handler '" << external_handler.handler_path << "' for devpath: '" << uevent.path << "' firmware: '" << uevent.firmware << "'"; diff --git a/init/firmware_handler.h b/init/firmware_handler.h index 8b758aee7..3c35b1f16 100644 --- a/init/firmware_handler.h +++ b/init/firmware_handler.h @@ -30,11 +30,13 @@ namespace android { namespace init { struct ExternalFirmwareHandler { - ExternalFirmwareHandler(std::string devpath, uid_t uid, std::string handler_path) - : devpath(std::move(devpath)), uid(uid), handler_path(std::move(handler_path)) {} + ExternalFirmwareHandler(std::string devpath, uid_t uid, std::string handler_path); + std::string devpath; uid_t uid; std::string handler_path; + + std::function match; }; class FirmwareHandler : public UeventHandler { diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp index 4e63ba577..c5aa9e3b5 100644 --- a/init/ueventd_parser_test.cpp +++ b/init/ueventd_parser_test.cpp @@ -154,6 +154,9 @@ TEST(ueventd_parser, ExternalFirmwareHandlers) { external_firmware_handler devpath root handler_path external_firmware_handler /devices/path/firmware/something001.bin system /vendor/bin/firmware_handler.sh external_firmware_handler /devices/path/firmware/something002.bin radio "/vendor/bin/firmware_handler.sh --has --arguments" +external_firmware_handler /devices/path/firmware/* root "/vendor/bin/firmware_handler.sh" +external_firmware_handler /devices/path/firmware/something* system "/vendor/bin/firmware_handler.sh" +external_firmware_handler /devices/path/*/firmware/something*.bin radio "/vendor/bin/firmware_handler.sh" )"; auto external_firmware_handlers = std::vector{ @@ -172,6 +175,21 @@ external_firmware_handler /devices/path/firmware/something002.bin radio "/vendor AID_RADIO, "/vendor/bin/firmware_handler.sh --has --arguments", }, + { + "/devices/path/firmware/", + AID_ROOT, + "/vendor/bin/firmware_handler.sh", + }, + { + "/devices/path/firmware/something", + AID_SYSTEM, + "/vendor/bin/firmware_handler.sh", + }, + { + "/devices/path/*/firmware/something*.bin", + AID_RADIO, + "/vendor/bin/firmware_handler.sh", + }, }; TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});