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

Commit 83f735c2 authored by Takaya Saeki's avatar Takaya Saeki
Browse files

ueventd: allow FirmwareHandler to run in a single process after coldboot

FirmwareHandler::HandleUevent internally parallelizes the core work
independently from the main ueventd process by fork. Thus, we have two
parallelization on going when we do parallelization in ueventd.

On the other hand, we are working on giving the ueventd an option to
parallelize its main loop with multiple threads. In that case, we don't
want the internal parallelization of FirmwareHandler since the main loop
runs in parallel in the first place. In addition, fork syscall does not
work well with multi-threaded main loop.

Thus, This CL makes it possible to disable the FirmwareHandler internal
parallelization. For the backward compatibility sake, this is disabled
by default, and even with it enabled, FirmwareHandler becomes a single
process only after the coldboot gets done.

Bug: 400592897
Test: Cuttlefish boots
Change-Id: I4b395c48ea3e696cd221a3033b0e6b8dc4afd62d
parent 2b2a75dd
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -134,9 +134,17 @@ ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
    : ExternalFirmwareHandler(devpath, uid, 0, handler_path) {}

FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories,
                                 std::vector<ExternalFirmwareHandler> external_firmware_handlers)
                                 std::vector<ExternalFirmwareHandler> external_firmware_handlers,
                                 bool serial_handler_after_coldboot)
    : firmware_directories_(std::move(firmware_directories)),
      external_firmware_handlers_(std::move(external_firmware_handlers)) {}
      external_firmware_handlers_(std::move(external_firmware_handlers)),
      serial_handler_after_coldboot_(serial_handler_after_coldboot) {}

void FirmwareHandler::ColdbootDone() {
    if (serial_handler_after_coldboot_) {
        enables_parallel_handlers_ = false;
    }
}

std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const {
    for (const auto& external_handler : external_firmware_handlers_) {
@@ -265,21 +273,31 @@ bool FirmwareHandler::ForEachFirmwareDirectory(
    return false;
}

void FirmwareHandler::HandleUeventInternal(const Uevent& uevent) const {
    Timer t;
    auto firmware = GetFirmwarePath(uevent);
    ProcessFirmwareEvent(uevent.path, firmware);
    LOG(INFO) << "loading " << uevent.path << " took " << t;
}

void FirmwareHandler::HandleUevent(const Uevent& uevent) {
    if (uevent.subsystem != "firmware" || uevent.action != "add") return;

    if (enables_parallel_handlers_) {
        // Loading the firmware in a child means we can do that in parallel...
        auto pid = fork();
        if (pid == -1) {
            PLOG(ERROR) << "could not fork to process firmware event for " << uevent.firmware;
    }
    if (pid == 0) {
        Timer t;
        auto firmware = GetFirmwarePath(uevent);
        ProcessFirmwareEvent(uevent.path, firmware);
        LOG(INFO) << "loading " << uevent.path << " took " << t;
        } else if (pid == 0) {
            // Child does the actual work
            HandleUeventInternal(uevent);
            _exit(EXIT_SUCCESS);
        } else {
            // The main process returns here. Let the child do the actual work in parallel.
            return;
        }
    }
    HandleUeventInternal(uevent);
}

}  // namespace init
+6 −1
Original line number Diff line number Diff line
@@ -45,21 +45,26 @@ struct ExternalFirmwareHandler {
class FirmwareHandler : public UeventHandler {
  public:
    FirmwareHandler(std::vector<std::string> firmware_directories,
                    std::vector<ExternalFirmwareHandler> external_firmware_handlers);
                    std::vector<ExternalFirmwareHandler> external_firmware_handlers,
                    bool serial_handler_after_coldboot);
    virtual ~FirmwareHandler() = default;

    void HandleUevent(const Uevent& uevent) override;
    void ColdbootDone() override;

  private:
    friend void FirmwareTestWithExternalHandler(const std::string& test_name,
                                                bool expect_new_firmware);
    void HandleUeventInternal(const Uevent& uevent) const;

    std::string GetFirmwarePath(const Uevent& uevent) const;
    void ProcessFirmwareEvent(const std::string& path, const std::string& firmware) const;
    bool ForEachFirmwareDirectory(std::function<bool(const std::string&)> handler) const;

    std::atomic_bool enables_parallel_handlers_ = true;
    const std::vector<std::string> firmware_directories_;
    const std::vector<ExternalFirmwareHandler> external_firmware_handlers_;
    const bool serial_handler_after_coldboot_ = true;
};

}  // namespace init
+2 −1
Original line number Diff line number Diff line
@@ -35,7 +35,8 @@ void FirmwareTestWithExternalHandler(const std::string& test_name, bool expect_n
    auto external_firmware_handler = ExternalFirmwareHandler(
            "/devices/led/firmware/test_firmware001.bin", getuid(), test_path);

    auto firmware_handler = FirmwareHandler({"/test"}, {external_firmware_handler});
    auto firmware_handler = FirmwareHandler({"/test"}, {external_firmware_handler},
                                            /*serial_handler_after_cold_boot=*/false);

    auto uevent = Uevent{
            .path = "/devices/led/firmware/test_firmware001.bin",
+2 −1
Original line number Diff line number Diff line
@@ -104,7 +104,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
                        firmware_directories.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
                    }
                    FirmwareHandler firmware_handler =
                            FirmwareHandler(firmware_directories, external_handlers);
                            FirmwareHandler(firmware_directories, external_handlers,
                                            /*serial_handler_after_coldboot=*/false);
                    Uevent uevent = CreateUevent(&fdp);
                    if (fdp.ConsumeBool() && uevent.path.size() != 0 &&
                        uevent.path.find(kPath) == 0) {
+2 −1
Original line number Diff line number Diff line
@@ -377,7 +377,8 @@ int ueventd_main(int argc, char** argv) {
    uevent_handlers.emplace_back(std::move(device_handler));
    uevent_handlers.emplace_back(std::make_unique<FirmwareHandler>(
            std::move(ueventd_configuration.firmware_directories),
            std::move(ueventd_configuration.external_firmware_handlers)));
            std::move(ueventd_configuration.external_firmware_handlers),
            /*serial_handler_after_cold_boot=*/false));

    if (ueventd_configuration.enable_modalias_handling) {
        std::vector<std::string> base_paths = {"/odm/lib/modules", "/vendor/lib/modules"};