init: separate out epoll into a class

Test: init_tests
Bug: 64114943
Change-Id: I5f03314773b02b9e30e8e21895b6bdcfd4909e88
This commit is contained in:
Mark Salyzyn 2015-10-24 16:20:18 -07:00
parent e0a52774b4
commit 6c6ec7240c
9 changed files with 175 additions and 67 deletions

View file

@ -100,6 +100,7 @@ cc_library_static {
"capabilities.cpp",
"descriptors.cpp",
"devices.cpp",
"epoll.cpp",
"firmware_handler.cpp",
"import_parser.cpp",
"init.cpp",

84
init/epoll.cpp Normal file
View file

@ -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

49
init/epoll.h Normal file
View file

@ -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

View file

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

View file

@ -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();

View file

@ -36,6 +36,7 @@
#include <android-base/properties.h>
#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<int> 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());
}

View file

@ -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

View file

@ -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 @@ 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

View file

@ -21,6 +21,8 @@
#include <string>
#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