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

Commit 6c6ec724 authored by Mark Salyzyn's avatar Mark Salyzyn
Browse files

init: separate out epoll into a class

Test: init_tests
Bug: 64114943
Change-Id: I5f03314773b02b9e30e8e21895b6bdcfd4909e88
parent e0a52774
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ cc_library_static {
        "capabilities.cpp",
        "descriptors.cpp",
        "devices.cpp",
        "epoll.cpp",
        "firmware_handler.cpp",
        "import_parser.cpp",
        "init.cpp",

init/epoll.cpp

0 → 100644
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "epoll.h"

#include <sys/epoll.h>

#include <chrono>
#include <functional>
#include <map>

namespace android {
namespace init {

Epoll::Epoll() {}

Result<Success> Epoll::Open() {
    if (epoll_fd_ >= 0) return Success();
    epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));

    if (epoll_fd_ == -1) {
        return ErrnoError() << "epoll_create1 failed";
    }
    return Success();
}

Result<Success> Epoll::RegisterHandler(int fd, std::function<void()> handler) {
    auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(handler));
    if (!inserted) {
        return Error() << "Cannot specify two epoll handlers for a given FD";
    }
    epoll_event ev;
    ev.events = EPOLLIN;
    // std::map's iterators do not get invalidated until erased, so we use the
    // pointer to the std::function in the map directly for epoll_ctl.
    ev.data.ptr = reinterpret_cast<void*>(&it->second);
    if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
        Result<Success> result = ErrnoError() << "epoll_ctl failed to add fd";
        epoll_handlers_.erase(fd);
        return result;
    }
    return Success();
}

Result<Success> Epoll::UnregisterHandler(int fd) {
    if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr) == -1) {
        return ErrnoError() << "epoll_ctl failed to remove fd";
    }
    if (epoll_handlers_.erase(fd) != 1) {
        return Error() << "Attempting to remove epoll handler for FD without an existing handler";
    }
    return Success();
}

Result<Success> Epoll::Wait(std::optional<std::chrono::milliseconds> timeout) {
    int timeout_ms = -1;
    if (timeout && timeout->count() < INT_MAX) {
        timeout_ms = timeout->count();
    }
    epoll_event ev;
    auto nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_, &ev, 1, timeout_ms));
    if (nr == -1) {
        return ErrnoError() << "epoll_wait failed";
    } else if (nr == 1) {
        std::invoke(*reinterpret_cast<std::function<void()>*>(ev.data.ptr));
    }
    return Success();
}

}  // namespace init
}  // namespace android

init/epoll.h

0 → 100644
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _INIT_EPOLL_H
#define _INIT_EPOLL_H

#include <chrono>
#include <functional>
#include <map>
#include <optional>

#include <android-base/unique_fd.h>

#include "result.h"

namespace android {
namespace init {

class Epoll {
  public:
    Epoll();

    Result<Success> Open();
    Result<Success> RegisterHandler(int fd, std::function<void()> handler);
    Result<Success> UnregisterHandler(int fd);
    Result<Success> Wait(std::optional<std::chrono::milliseconds> timeout);

  private:
    android::base::unique_fd epoll_fd_;
    std::map<int, std::function<void()>> epoll_handlers_;
};

}  // namespace init
}  // namespace android

#endif
+24 −55
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
#include <sys/sysmacros.h>
@@ -48,6 +47,7 @@
#include <selinux/android.h>

#include "action_parser.h"
#include "epoll.h"
#include "import_parser.h"
#include "init_first_stage.h"
#include "keychords.h"
@@ -61,6 +61,7 @@
#include "util.h"
#include "watchdogd.h"

using namespace std::chrono_literals;
using namespace std::string_literals;

using android::base::boot_clock;
@@ -79,7 +80,6 @@ static char qemu[32];

std::string default_console = "/dev/console";

static int epoll_fd = -1;
static int signal_fd = -1;

static std::unique_ptr<Timer> waiting_for_prop(nullptr);
@@ -131,34 +131,6 @@ static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_
    }
}

static std::map<int, std::function<void()>> epoll_handlers;

void register_epoll_handler(int fd, std::function<void()> handler) {
    auto[it, inserted] = epoll_handlers.emplace(fd, std::move(handler));
    if (!inserted) {
        LOG(ERROR) << "Cannot specify two epoll handlers for a given FD";
        return;
    }
    epoll_event ev;
    ev.events = EPOLLIN;
    // std::map's iterators do not get invalidated until erased, so we use the pointer to the
    // std::function in the map directly for epoll_ctl.
    ev.data.ptr = reinterpret_cast<void*>(&it->second);
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
        PLOG(ERROR) << "epoll_ctl failed to add fd";
        epoll_handlers.erase(fd);
    }
}

void unregister_epoll_handler(int fd) {
    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
        PLOG(ERROR) << "epoll_ctl failed to remove fd";
    }
    if (epoll_handlers.erase(fd) != 1) {
        LOG(ERROR) << "Attempting to remove epoll handler for FD without an existing handler";
    }
}

bool start_waiting_for_property(const char *name, const char *value)
{
    if (waiting_for_prop) {
@@ -343,11 +315,6 @@ static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& arg
    return Success();
}

static Result<Success> KeychordInitAction(const BuiltinArguments& args) {
    KeychordInit();
    return Success();
}

static Result<Success> console_init_action(const BuiltinArguments& args) {
    std::string console = GetProperty("ro.boot.console", "");
    if (!console.empty()) {
@@ -550,7 +517,7 @@ static void UnblockSignals() {
    }
}

static void InstallSignalFdHandler() {
static void InstallSignalFdHandler(Epoll* epoll) {
    // Applying SA_NOCLDSTOP to a defaulted SIGCHLD handler prevents the signalfd from receiving
    // SIGCHLD when a child process stops or continues (b/77867680#comment9).
    const struct sigaction act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDSTOP };
@@ -581,7 +548,9 @@ static void InstallSignalFdHandler() {
        PLOG(FATAL) << "failed to create signalfd";
    }

    register_epoll_handler(signal_fd, HandleSignalFd);
    if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result) {
        LOG(FATAL) << result.error();
    }
}

int main(int argc, char** argv) {
@@ -727,16 +696,16 @@ int main(int argc, char** argv) {
    SelabelInitialize();
    SelinuxRestoreContext();

    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (epoll_fd == -1) {
        PLOG(FATAL) << "epoll_create1 failed";
    Epoll epoll;
    if (auto result = epoll.Open(); !result) {
        PLOG(FATAL) << result.error();
    }

    InstallSignalFdHandler();
    InstallSignalFdHandler(&epoll);

    property_load_boot_defaults();
    export_oem_lock_status();
    start_property_service();
    StartPropertyService(&epoll);
    set_usb_controller();

    const BuiltinFunctionMap function_map;
@@ -761,7 +730,12 @@ int main(int argc, char** argv) {
    am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
    am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
    am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
    am.QueueBuiltinAction(KeychordInitAction, "KeychordInit");
    am.QueueBuiltinAction(
        [&epoll](const BuiltinArguments& args) -> Result<Success> {
            KeychordInit(&epoll);
            return Success();
        },
        "KeychordInit");
    am.QueueBuiltinAction(console_init_action, "console_init");

    // Trigger all the boot actions to get us started.
@@ -784,7 +758,7 @@ int main(int argc, char** argv) {

    while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;
        auto epoll_timeout = std::optional<std::chrono::milliseconds>{};

        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
@@ -802,23 +776,18 @@ int main(int argc, char** argv) {

                // If there's a process that needs restarting, wake up in time for that.
                if (next_process_restart_time) {
                    epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
                                           *next_process_restart_time - boot_clock::now())
                                           .count();
                    if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
                    epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
                        *next_process_restart_time - boot_clock::now());
                    if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
                }
            }

            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
            if (am.HasMoreCommands()) epoll_timeout = 0ms;
        }

        epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
        if (nr == -1) {
            PLOG(ERROR) << "epoll_wait failed";
        } else if (nr == 1) {
            std::invoke(*reinterpret_cast<std::function<void()>*>(ev.data.ptr));
        if (auto result = epoll.Wait(epoll_timeout); !result) {
            LOG(ERROR) << result.error();
        }
    }

+0 −3
Original line number Diff line number Diff line
@@ -43,9 +43,6 @@ void HandleControlMessage(const std::string& msg, const std::string& arg, pid_t

void property_changed(const std::string& name, const std::string& value);

void register_epoll_handler(int fd, std::function<void()> handler);
void unregister_epoll_handler(int fd);

bool start_waiting_for_property(const char *name, const char *value);

void DumpState();
Loading