Merge changes from topic "b/64114943"
* changes: init: switch from /dev/keychord to /dev/input/ init: use std::function for epoll handling
This commit is contained in:
commit
98caf20a65
|
@ -31,6 +31,10 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
|
@ -43,9 +47,6 @@
|
|||
#include <private/android_filesystem_config.h>
|
||||
#include <selinux/android.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "action_parser.h"
|
||||
#include "import_parser.h"
|
||||
#include "init_first_stage.h"
|
||||
|
@ -130,12 +131,31 @@ static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_
|
|||
}
|
||||
}
|
||||
|
||||
void register_epoll_handler(int fd, void (*fn)()) {
|
||||
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;
|
||||
ev.data.ptr = reinterpret_cast<void*>(fn);
|
||||
// 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";
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,8 +354,8 @@ static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& arg
|
|||
return Success();
|
||||
}
|
||||
|
||||
static Result<Success> keychord_init_action(const BuiltinArguments& args) {
|
||||
keychord_init();
|
||||
static Result<Success> KeychordInitAction(const BuiltinArguments& args) {
|
||||
KeychordInit();
|
||||
return Success();
|
||||
}
|
||||
|
||||
|
@ -752,7 +772,7 @@ int main(int argc, char** argv) {
|
|||
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
|
||||
am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
|
||||
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
|
||||
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
|
||||
am.QueueBuiltinAction(KeychordInitAction, "KeychordInit");
|
||||
am.QueueBuiltinAction(console_init_action, "console_init");
|
||||
|
||||
// Trigger all the boot actions to get us started.
|
||||
|
@ -809,7 +829,7 @@ int main(int argc, char** argv) {
|
|||
if (nr == -1) {
|
||||
PLOG(ERROR) << "epoll_wait failed";
|
||||
} else if (nr == 1) {
|
||||
((void (*)()) ev.data.ptr)();
|
||||
std::invoke(*reinterpret_cast<std::function<void()>*>(ev.data.ptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -42,7 +43,8 @@ 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, void (*fn)());
|
||||
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);
|
||||
|
||||
|
|
|
@ -16,13 +16,20 @@
|
|||
|
||||
#include "keychords.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/input.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/keychord.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
|
||||
|
@ -31,51 +38,87 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
static struct input_keychord *keychords = 0;
|
||||
static int keychords_count = 0;
|
||||
static int keychords_length = 0;
|
||||
static int keychord_fd = -1;
|
||||
namespace {
|
||||
|
||||
void add_service_keycodes(Service* svc)
|
||||
{
|
||||
struct input_keychord *keychord;
|
||||
size_t i, size;
|
||||
int keychords_count;
|
||||
|
||||
if (!svc->keycodes().empty()) {
|
||||
/* add a new keychord to the list */
|
||||
size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
|
||||
keychords = (input_keychord*) realloc(keychords, keychords_length + size);
|
||||
if (!keychords) {
|
||||
PLOG(ERROR) << "could not allocate keychords";
|
||||
keychords_length = 0;
|
||||
keychords_count = 0;
|
||||
return;
|
||||
struct KeychordEntry {
|
||||
const std::vector<int> keycodes;
|
||||
bool notified;
|
||||
int id;
|
||||
|
||||
KeychordEntry(const std::vector<int>& keycodes, int id)
|
||||
: keycodes(keycodes), notified(false), id(id) {}
|
||||
};
|
||||
|
||||
std::vector<KeychordEntry> keychord_entries;
|
||||
|
||||
// Bit management
|
||||
class KeychordMask {
|
||||
private:
|
||||
typedef unsigned int mask_t;
|
||||
std::vector<mask_t> bits;
|
||||
static constexpr size_t bits_per_byte = 8;
|
||||
|
||||
public:
|
||||
explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
|
||||
|
||||
void SetBit(size_t bit, bool value = true) {
|
||||
auto idx = bit / (bits_per_byte * sizeof(mask_t));
|
||||
if (idx >= bits.size()) return;
|
||||
if (value) {
|
||||
bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
|
||||
} else {
|
||||
bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
|
||||
}
|
||||
|
||||
keychord = (struct input_keychord *)((char *)keychords + keychords_length);
|
||||
keychord->version = KEYCHORD_VERSION;
|
||||
keychord->id = keychords_count + 1;
|
||||
keychord->count = svc->keycodes().size();
|
||||
svc->set_keychord_id(keychord->id);
|
||||
|
||||
for (i = 0; i < svc->keycodes().size(); i++) {
|
||||
keychord->keycodes[i] = svc->keycodes()[i];
|
||||
}
|
||||
keychords_count++;
|
||||
keychords_length += size;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_keychord() {
|
||||
int ret;
|
||||
__u16 id;
|
||||
|
||||
ret = read(keychord_fd, &id, sizeof(id));
|
||||
if (ret != sizeof(id)) {
|
||||
PLOG(ERROR) << "could not read keychord id";
|
||||
return;
|
||||
}
|
||||
|
||||
bool GetBit(size_t bit) const {
|
||||
auto idx = bit / (bits_per_byte * sizeof(mask_t));
|
||||
return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
|
||||
}
|
||||
|
||||
size_t bytesize() const { return bits.size() * sizeof(mask_t); }
|
||||
void* data() { return bits.data(); }
|
||||
size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
|
||||
void resize(size_t bit) {
|
||||
auto idx = bit / (bits_per_byte * sizeof(mask_t));
|
||||
if (idx >= bits.size()) {
|
||||
bits.resize(idx + 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
for (size_t i = 0; i < bits.size(); ++i) {
|
||||
if (bits[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
KeychordMask operator&(const KeychordMask& rval) const {
|
||||
auto len = std::min(bits.size(), rval.bits.size());
|
||||
KeychordMask ret;
|
||||
ret.bits.resize(len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
ret.bits[i] = bits[i] & rval.bits[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void operator|=(const KeychordMask& rval) {
|
||||
size_t len = rval.bits.size();
|
||||
bits.resize(len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
bits[i] |= rval.bits[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
KeychordMask keychord_current;
|
||||
|
||||
constexpr char kDevicePath[] = "/dev/input";
|
||||
|
||||
void HandleKeychord(int id) {
|
||||
// Only handle keychords if adb is enabled.
|
||||
std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
|
||||
if (adb_enabled == "running") {
|
||||
|
@ -94,32 +137,125 @@ static void handle_keychord() {
|
|||
}
|
||||
}
|
||||
|
||||
void keychord_init() {
|
||||
void KeychordLambdaCheck() {
|
||||
for (auto& e : keychord_entries) {
|
||||
bool found = true;
|
||||
for (auto& code : e.keycodes) {
|
||||
if (!keychord_current.GetBit(code)) {
|
||||
e.notified = false;
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) continue;
|
||||
if (e.notified) continue;
|
||||
e.notified = true;
|
||||
HandleKeychord(e.id);
|
||||
}
|
||||
}
|
||||
|
||||
void KeychordLambdaHandler(int fd) {
|
||||
input_event event;
|
||||
auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
|
||||
if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
|
||||
keychord_current.SetBit(event.code, event.value);
|
||||
KeychordLambdaCheck();
|
||||
}
|
||||
|
||||
bool KeychordGeteventEnable(int fd) {
|
||||
static bool EviocsmaskSupported = true;
|
||||
|
||||
// Make sure it is an event channel, should pass this ioctl call
|
||||
int version;
|
||||
if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
|
||||
|
||||
if (EviocsmaskSupported) {
|
||||
KeychordMask mask(EV_KEY);
|
||||
mask.SetBit(EV_KEY);
|
||||
input_mask msg = {};
|
||||
msg.type = EV_SYN;
|
||||
msg.codes_size = mask.bytesize();
|
||||
msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
|
||||
if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
|
||||
PLOG(WARNING) << "EVIOCSMASK not supported";
|
||||
EviocsmaskSupported = false;
|
||||
}
|
||||
}
|
||||
|
||||
KeychordMask mask;
|
||||
for (auto& e : keychord_entries) {
|
||||
for (auto& code : e.keycodes) {
|
||||
mask.resize(code);
|
||||
mask.SetBit(code);
|
||||
}
|
||||
}
|
||||
|
||||
keychord_current.resize(mask.size());
|
||||
KeychordMask available(mask.size());
|
||||
auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
|
||||
if (res == -1) return false;
|
||||
if (!(available & mask)) return false;
|
||||
|
||||
if (EviocsmaskSupported) {
|
||||
input_mask msg = {};
|
||||
msg.type = EV_KEY;
|
||||
msg.codes_size = mask.bytesize();
|
||||
msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
|
||||
::ioctl(fd, EVIOCSMASK, &msg);
|
||||
}
|
||||
|
||||
KeychordMask set(mask.size());
|
||||
res = ::ioctl(fd, EVIOCGKEY(res), set.data());
|
||||
if (res > 0) {
|
||||
keychord_current |= mask & available & set;
|
||||
KeychordLambdaCheck();
|
||||
}
|
||||
register_epoll_handler(fd, [fd]() { KeychordLambdaHandler(fd); });
|
||||
return true;
|
||||
}
|
||||
|
||||
void GeteventOpenDevice(const std::string& device) {
|
||||
auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
|
||||
if (fd == -1) {
|
||||
PLOG(ERROR) << "Can not open " << device;
|
||||
return;
|
||||
}
|
||||
if (!KeychordGeteventEnable(fd)) {
|
||||
::close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void GeteventOpenDevice() {
|
||||
std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
|
||||
if (!device) return;
|
||||
|
||||
dirent* entry;
|
||||
while ((entry = readdir(device.get()))) {
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
std::string devname(kDevicePath);
|
||||
devname += '/';
|
||||
devname += entry->d_name;
|
||||
GeteventOpenDevice(devname);
|
||||
}
|
||||
}
|
||||
|
||||
void AddServiceKeycodes(Service* svc) {
|
||||
if (svc->keycodes().empty()) return;
|
||||
for (auto& code : svc->keycodes()) {
|
||||
if ((code < 0) || (code >= KEY_MAX)) return;
|
||||
}
|
||||
++keychords_count;
|
||||
keychord_entries.emplace_back(KeychordEntry(svc->keycodes(), keychords_count));
|
||||
svc->set_keychord_id(keychords_count);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void KeychordInit() {
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
add_service_keycodes(service.get());
|
||||
AddServiceKeycodes(service.get());
|
||||
}
|
||||
|
||||
// Nothing to do if no services require keychords.
|
||||
if (!keychords) {
|
||||
return;
|
||||
}
|
||||
|
||||
keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
|
||||
if (keychord_fd == -1) {
|
||||
PLOG(ERROR) << "could not open /dev/keychord";
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = write(keychord_fd, keychords, keychords_length);
|
||||
if (ret != keychords_length) {
|
||||
PLOG(ERROR) << "could not configure /dev/keychord " << ret;
|
||||
close(keychord_fd);
|
||||
}
|
||||
|
||||
free(keychords);
|
||||
keychords = nullptr;
|
||||
|
||||
register_epoll_handler(keychord_fd, handle_keychord);
|
||||
if (keychords_count) GeteventOpenDevice();
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
|
|
|
@ -22,8 +22,7 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
void add_service_keycodes(Service* svc);
|
||||
void keychord_init();
|
||||
void KeychordInit();
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
Loading…
Reference in New Issue