ueventd: Allow pattern matching to find external firmware handler

Only the exact same devpath uevent can launch external handler specified
in ueventd.rc. So, you should specify all possible devpaths, even
firmware with different filenames on the same device. Pattern mactching
can be used to simplify this.

Test: atest CtsInitTestCases
Signed-off-by: Suchang Woo <suchang.woo@samsung.com>
Change-Id: If3b7a2cabb8055bf4b768d928f0fc0012da3c177
This commit is contained in:
Suchang Woo 2021-04-06 11:22:49 +09:00 committed by David Anderson
parent 78e26beb02
commit 22fdd0ae13
3 changed files with 54 additions and 3 deletions

View file

@ -17,6 +17,7 @@
#include "firmware_handler.h"
#include <fcntl.h>
#include <fnmatch.h>
#include <glob.h>
#include <pwd.h>
#include <signal.h>
@ -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<std::string> firmware_directories,
std::vector<ExternalFirmwareHandler> external_firmware_handlers)
: firmware_directories_(std::move(firmware_directories)),
@ -160,7 +191,7 @@ Result<std::string> 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
<< "'";

View file

@ -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<bool(const std::string&)> match;
};
class FirmwareHandler : public UeventHandler {

View file

@ -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<ExternalFirmwareHandler>{
@ -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});