diff --git a/init/Android.bp b/init/Android.bp index a31c5a587..63f3fca50 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -100,6 +100,7 @@ cc_library_static { "capabilities.cpp", "descriptors.cpp", "devices.cpp", + "epoll.cpp", "firmware_handler.cpp", "import_parser.cpp", "init.cpp", diff --git a/init/epoll.cpp b/init/epoll.cpp new file mode 100644 index 000000000..4bca09e6d --- /dev/null +++ b/init/epoll.cpp @@ -0,0 +1,84 @@ +/* + * 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 + +#include +#include +#include + +namespace android { +namespace init { + +Epoll::Epoll() {} + +Result 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 Epoll::RegisterHandler(int fd, std::function 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(&it->second); + if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ev) == -1) { + Result result = ErrnoError() << "epoll_ctl failed to add fd"; + epoll_handlers_.erase(fd); + return result; + } + return Success(); +} + +Result 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 Epoll::Wait(std::optional 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*>(ev.data.ptr)); + } + return Success(); +} + +} // namespace init +} // namespace android diff --git a/init/epoll.h b/init/epoll.h new file mode 100644 index 000000000..85a791c60 --- /dev/null +++ b/init/epoll.h @@ -0,0 +1,49 @@ +/* + * 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 +#include +#include +#include + +#include + +#include "result.h" + +namespace android { +namespace init { + +class Epoll { + public: + Epoll(); + + Result Open(); + Result RegisterHandler(int fd, std::function handler); + Result UnregisterHandler(int fd); + Result Wait(std::optional timeout); + + private: + android::base::unique_fd epoll_fd_; + std::map> epoll_handlers_; +}; + +} // namespace init +} // namespace android + +#endif diff --git a/init/init.cpp b/init/init.cpp index 645184b26..fd9a90cd7 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include #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 waiting_for_prop(nullptr); @@ -131,34 +131,6 @@ static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_ } } -static std::map> epoll_handlers; - -void register_epoll_handler(int fd, std::function 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(&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 wait_for_coldboot_done_action(const BuiltinArguments& arg return Success(); } -static Result KeychordInitAction(const BuiltinArguments& args) { - KeychordInit(); - return Success(); -} - static Result 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 { + 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{}; 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( - *next_process_restart_time - boot_clock::now()) - .count(); - if (epoll_timeout_ms < 0) epoll_timeout_ms = 0; + epoll_timeout = std::chrono::ceil( + *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*>(ev.data.ptr)); + if (auto result = epoll.Wait(epoll_timeout); !result) { + LOG(ERROR) << result.error(); } } diff --git a/init/init.h b/init/init.h index e7c4d8d80..6c82fa12c 100644 --- a/init/init.h +++ b/init/init.h @@ -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 handler); -void unregister_epoll_handler(int fd); - bool start_waiting_for_property(const char *name, const char *value); void DumpState(); diff --git a/init/keychords.cpp b/init/keychords.cpp index 293736d30..418cdeb22 100644 --- a/init/keychords.cpp +++ b/init/keychords.cpp @@ -36,6 +36,7 @@ #include #include "init.h" +#include "service.h" namespace android { namespace init { @@ -43,6 +44,7 @@ namespace init { namespace { int keychords_count; +Epoll* epoll; struct KeychordEntry { const std::vector keycodes; @@ -214,7 +216,7 @@ bool KeychordGeteventEnable(int fd) { keychord_current |= mask & available & set; KeychordLambdaCheck(); } - register_epoll_handler(fd, [fd]() { KeychordLambdaHandler(fd); }); + epoll->RegisterHandler(fd, [fd]() { KeychordLambdaHandler(fd); }); return true; } @@ -236,7 +238,7 @@ void GeteventCloseDevice(const std::string& device) { auto it = keychord_registration.find(device); if (it == keychord_registration.end()) return; auto fd = (*it).second; - unregister_epoll_handler(fd); + epoll->UnregisterHandler(fd); keychord_registration.erase(it); ::close(fd); } @@ -294,7 +296,7 @@ void GeteventOpenDevice() { } } - if (inotify_fd >= 0) register_epoll_handler(inotify_fd, InotifyHandler); + if (inotify_fd >= 0) epoll->RegisterHandler(inotify_fd, InotifyHandler); } void AddServiceKeycodes(Service* svc) { @@ -309,7 +311,8 @@ void AddServiceKeycodes(Service* svc) { } // namespace -void KeychordInit() { +void KeychordInit(Epoll* init_epoll) { + epoll = init_epoll; for (const auto& service : ServiceList::GetInstance()) { AddServiceKeycodes(service.get()); } diff --git a/init/keychords.h b/init/keychords.h index 689a3b578..f3aecbb56 100644 --- a/init/keychords.h +++ b/init/keychords.h @@ -17,12 +17,12 @@ #ifndef _INIT_KEYCHORDS_H_ #define _INIT_KEYCHORDS_H_ -#include "service.h" +#include "epoll.h" namespace android { namespace init { -void KeychordInit(); +void KeychordInit(Epoll* init_epoll); } // namespace init } // namespace android diff --git a/init/property_service.cpp b/init/property_service.cpp index 47e45efeb..32cf0eefd 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -56,6 +56,7 @@ #include #include +#include "epoll.h" #include "init.h" #include "persistent_properties.h" #include "property_type.h" @@ -808,7 +809,7 @@ void CreateSerializedPropertyInfo() { selinux_android_restorecon(kPropertyInfosPath, 0); } -void start_property_service() { +void StartPropertyService(Epoll* epoll) { selinux_callback cb; cb.func_audit = SelinuxAuditCallback; selinux_set_callback(SELINUX_CB_AUDIT, cb); @@ -823,7 +824,9 @@ void start_property_service() { listen(property_set_fd, 8); - register_epoll_handler(property_set_fd, handle_property_set_fd); + if (auto result = epoll->RegisterHandler(property_set_fd, handle_property_set_fd); !result) { + PLOG(FATAL) << result.error(); + } } } // namespace init diff --git a/init/property_service.h b/init/property_service.h index 29eaaa901..4a354c27f 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -21,6 +21,8 @@ #include +#include "epoll.h" + namespace android { namespace init { @@ -40,7 +42,7 @@ void property_init(void); void property_load_boot_defaults(void); void load_persist_props(void); void load_system_props(void); -void start_property_service(void); +void StartPropertyService(Epoll* epoll); } // namespace init } // namespace android