init: separate out epoll into a class
Test: init_tests Bug: 64114943 Change-Id: I5f03314773b02b9e30e8e21895b6bdcfd4909e88
This commit is contained in:
parent
e0a52774b4
commit
6c6ec7240c
|
@ -100,6 +100,7 @@ cc_library_static {
|
|||
"capabilities.cpp",
|
||||
"descriptors.cpp",
|
||||
"devices.cpp",
|
||||
"epoll.cpp",
|
||||
"firmware_handler.cpp",
|
||||
"import_parser.cpp",
|
||||
"init.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
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue