init: separate out epoll into a class
Test: init_tests
Bug: 64114943
Change-Id: I5f03314773b02b9e30e8e21895b6bdcfd4909e88
diff --git a/init/Android.bp b/init/Android.bp
index a31c5a5..63f3fca 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -100,6 +100,7 @@
"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 0000000..4bca09e
--- /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 <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
diff --git a/init/epoll.h b/init/epoll.h
new file mode 100644
index 0000000..85a791c
--- /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 <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
diff --git a/init/init.cpp b/init/init.cpp
index 645184b..fd9a90c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -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 @@
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 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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
// 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();
}
}
diff --git a/init/init.h b/init/init.h
index e7c4d8d..6c82fa1 100644
--- a/init/init.h
+++ b/init/init.h
@@ -43,9 +43,6 @@
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();
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 293736d..418cdeb 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -36,6 +36,7 @@
#include <android-base/properties.h>
#include "init.h"
+#include "service.h"
namespace android {
namespace init {
@@ -43,6 +44,7 @@
namespace {
int keychords_count;
+Epoll* epoll;
struct KeychordEntry {
const std::vector<int> keycodes;
@@ -214,7 +216,7 @@
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 @@
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 @@
}
}
- 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 @@
} // 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 689a3b5..f3aecbb 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 47e45ef..32cf0ee 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -56,6 +56,7 @@
#include <selinux/label.h>
#include <selinux/selinux.h>
+#include "epoll.h"
#include "init.h"
#include "persistent_properties.h"
#include "property_type.h"
@@ -808,7 +809,7 @@
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 @@
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 29eaaa9..4a354c2 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -21,6 +21,8 @@
#include <string>
+#include "epoll.h"
+
namespace android {
namespace init {
@@ -40,7 +42,7 @@
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