diff --git a/init/init.cpp b/init/init.cpp index 43242b2dc..5652c5e51 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -749,12 +749,13 @@ int main(int argc, char** argv) { am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng"); am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits"); am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict"); + Keychords keychords; am.QueueBuiltinAction( - [&epoll](const BuiltinArguments& args) -> Result { + [&epoll, &keychords](const BuiltinArguments& args) -> Result { for (const auto& svc : ServiceList::GetInstance()) { - svc->set_keychord_id(GetKeychordId(svc->keycodes())); + svc->set_keychord_id(keychords.GetId(svc->keycodes())); } - KeychordInit(&epoll, HandleKeychord); + keychords.Start(&epoll, HandleKeychord); return Success(); }, "KeychordInit"); diff --git a/init/keychords.cpp b/init/keychords.cpp index 1a8f2aea3..9aa8b2a78 100644 --- a/init/keychords.cpp +++ b/init/keychords.cpp @@ -37,95 +37,85 @@ namespace android { namespace init { -namespace { +Keychords::Keychords() : epoll_(nullptr), count_(0), inotify_fd_(-1) {} -int keychords_count; -Epoll* epoll; -std::function handle_keychord; - -struct KeychordEntry { - const std::vector keycodes; - bool notified; - int id; - - KeychordEntry(const std::vector& keycodes, int id) - : keycodes(keycodes), notified(false), id(id) {} -}; - -std::vector keychord_entries; - -// Bit management -class KeychordMask { - private: - typedef unsigned int mask_t; - std::vector 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)))); - } +Keychords::~Keychords() noexcept { + if (inotify_fd_ >= 0) { + epoll_->UnregisterHandler(inotify_fd_); + ::close(inotify_fd_); } + while (!registration_.empty()) GeteventCloseDevice(registration_.begin()->first); +} - 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)))); +Keychords::Mask::Mask(size_t bit) : bits_((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {} + +void Keychords::Mask::SetBit(size_t bit, bool value) { + auto idx = bit / (kBitsPerByte * sizeof(mask_t)); + if (idx >= bits_.size()) return; + if (value) { + bits_[idx] |= mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t))); + } else { + bits_[idx] &= ~(mask_t(1) << (bit % (kBitsPerByte * 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); - } +bool Keychords::Mask::GetBit(size_t bit) const { + auto idx = bit / (kBitsPerByte * sizeof(mask_t)); + return bits_[idx] & (mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t)))); +} + +size_t Keychords::Mask::bytesize() const { + return bits_.size() * sizeof(mask_t); +} + +void* Keychords::Mask::data() { + return bits_.data(); +} + +size_t Keychords::Mask::size() const { + return bits_.size() * sizeof(mask_t) * kBitsPerByte; +} + +void Keychords::Mask::resize(size_t bit) { + auto idx = bit / (kBitsPerByte * 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; +Keychords::Mask::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; +Keychords::Mask Keychords::Mask::operator&(const Keychords::Mask& rval) const { + auto len = std::min(bits_.size(), rval.bits_.size()); + Keychords::Mask 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]; - } +void Keychords::Mask::operator|=(const Keychords::Mask& rval) { + auto len = rval.bits_.size(); + bits_.resize(len); + for (size_t i = 0; i < len; ++i) { + bits_[i] |= rval.bits_[i]; } -}; +} -KeychordMask keychord_current; +Keychords::Entry::Entry(const std::vector& keycodes, int id) + : keycodes(keycodes), id(id), notified(false) {} -constexpr char kDevicePath[] = "/dev/input"; - -std::map keychord_registration; - -void KeychordLambdaCheck() { - for (auto& e : keychord_entries) { - bool found = true; +void Keychords::LambdaCheck() { + for (auto& e : entries_) { + auto found = true; for (auto& code : e.keycodes) { - if (!keychord_current.GetBit(code)) { + if (!current_.GetBit(code)) { e.notified = false; found = false; break; @@ -134,19 +124,19 @@ void KeychordLambdaCheck() { if (!found) continue; if (e.notified) continue; e.notified = true; - handle_keychord(e.id); + handler_(e.id); } } -void KeychordLambdaHandler(int fd) { +void Keychords::LambdaHandler(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(); + current_.SetBit(event.code, event.value); + LambdaCheck(); } -bool KeychordGeteventEnable(int fd) { +bool Keychords::GeteventEnable(int fd) { // Make sure it is an event channel, should pass this ioctl call int version; if (::ioctl(fd, EVIOCGVERSION, &version)) return false; @@ -154,7 +144,7 @@ bool KeychordGeteventEnable(int fd) { #ifdef EVIOCSMASK static auto EviocsmaskSupported = true; if (EviocsmaskSupported) { - KeychordMask mask(EV_KEY); + Keychords::Mask mask(EV_KEY); mask.SetBit(EV_KEY); input_mask msg = {}; msg.type = EV_SYN; @@ -167,16 +157,16 @@ bool KeychordGeteventEnable(int fd) { } #endif - KeychordMask mask; - for (auto& e : keychord_entries) { + Keychords::Mask mask; + for (auto& e : entries_) { for (auto& code : e.keycodes) { mask.resize(code); mask.SetBit(code); } } - keychord_current.resize(mask.size()); - KeychordMask available(mask.size()); + current_.resize(mask.size()); + Keychords::Mask available(mask.size()); auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data()); if (res == -1) return false; if (!(available & mask)) return false; @@ -191,45 +181,43 @@ bool KeychordGeteventEnable(int fd) { } #endif - KeychordMask set(mask.size()); + Keychords::Mask set(mask.size()); res = ::ioctl(fd, EVIOCGKEY(res), set.data()); if (res > 0) { - keychord_current |= mask & available & set; - KeychordLambdaCheck(); + current_ |= mask & available & set; + LambdaCheck(); } - epoll->RegisterHandler(fd, [fd]() { KeychordLambdaHandler(fd); }); + epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); }); return true; } -void GeteventOpenDevice(const std::string& device) { - if (keychord_registration.count(device)) return; +void Keychords::GeteventOpenDevice(const std::string& device) { + if (registration_.count(device)) return; 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)) { + if (!GeteventEnable(fd)) { ::close(fd); } else { - keychord_registration.emplace(device, fd); + registration_.emplace(device, fd); } } -void GeteventCloseDevice(const std::string& device) { - auto it = keychord_registration.find(device); - if (it == keychord_registration.end()) return; +void Keychords::GeteventCloseDevice(const std::string& device) { + auto it = registration_.find(device); + if (it == registration_.end()) return; auto fd = (*it).second; - epoll->UnregisterHandler(fd); - keychord_registration.erase(it); + epoll_->UnregisterHandler(fd); + registration_.erase(it); ::close(fd); } -int inotify_fd = -1; +void Keychords::InotifyHandler() { + unsigned char buf[512]; // History shows 32-64 bytes typical -void InotifyHandler() { - unsigned char buf[512]; - - auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf))); + auto res = TEMP_FAILURE_RETRY(::read(inotify_fd_, buf, sizeof(buf))); if (res < 0) { PLOG(WARNING) << "could not get event"; return; @@ -255,14 +243,15 @@ void InotifyHandler() { } } -void GeteventOpenDevice() { - inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (inotify_fd < 0) { +void Keychords::GeteventOpenDevice() { + inotify_fd_ = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (inotify_fd_ < 0) { PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath; - } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) < 0) { + } else if (::inotify_add_watch(inotify_fd_, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) < + 0) { PLOG(WARNING) << "Could not add watch for " << kDevicePath; - ::close(inotify_fd); - inotify_fd = -1; + ::close(inotify_fd_); + inotify_fd_ = -1; } std::unique_ptr device(opendir(kDevicePath), closedir); @@ -277,22 +266,22 @@ void GeteventOpenDevice() { } } - if (inotify_fd >= 0) epoll->RegisterHandler(inotify_fd, InotifyHandler); + if (inotify_fd_ >= 0) { + epoll_->RegisterHandler(inotify_fd_, [this]() { this->InotifyHandler(); }); + } } -} // namespace - -int GetKeychordId(const std::vector& keycodes) { +int Keychords::GetId(const std::vector& keycodes) { if (keycodes.empty()) return 0; - ++keychords_count; - keychord_entries.emplace_back(KeychordEntry(keycodes, keychords_count)); - return keychords_count; + ++count_; + entries_.emplace_back(Entry(keycodes, count_)); + return count_; } -void KeychordInit(Epoll* init_epoll, std::function handler) { - epoll = init_epoll; - handle_keychord = handler; - if (keychords_count) GeteventOpenDevice(); +void Keychords::Start(Epoll* epoll, std::function handler) { + epoll_ = epoll; + handler_ = handler; + if (count_) GeteventOpenDevice(); } } // namespace init diff --git a/init/keychords.h b/init/keychords.h index f273c8c2e..74a91951b 100644 --- a/init/keychords.h +++ b/init/keychords.h @@ -18,6 +18,8 @@ #define _INIT_KEYCHORDS_H_ #include +#include +#include #include #include "epoll.h" @@ -25,8 +27,74 @@ namespace android { namespace init { -void KeychordInit(Epoll* init_epoll, std::function handler); -int GetKeychordId(const std::vector& keycodes); +class Keychords { + public: + Keychords(); + Keychords(const Keychords&) = delete; + Keychords(Keychords&&) = delete; + Keychords& operator=(const Keychords&) = delete; + Keychords& operator=(Keychords&&) = delete; + ~Keychords() noexcept; + + int GetId(const std::vector& keycodes); + void Start(Epoll* epoll, std::function handler); + + private: + // Bit management + class Mask { + public: + explicit Mask(size_t bit = 0); + + void SetBit(size_t bit, bool value = true); + bool GetBit(size_t bit) const; + + size_t bytesize() const; + void* data(); + size_t size() const; + void resize(size_t bit); + + operator bool() const; + Mask operator&(const Mask& rval) const; + void operator|=(const Mask& rval); + + private: + typedef unsigned int mask_t; + static constexpr size_t kBitsPerByte = 8; + + std::vector bits_; + }; + + struct Entry { + Entry(const std::vector& keycodes, int id); + + const std::vector keycodes; + const int id; + bool notified; + }; + + static constexpr char kDevicePath[] = "/dev/input"; + + void LambdaCheck(); + void LambdaHandler(int fd); + void InotifyHandler(); + + bool GeteventEnable(int fd); + void GeteventOpenDevice(const std::string& device); + void GeteventOpenDevice(); + void GeteventCloseDevice(const std::string& device); + + Epoll* epoll_; + std::function handler_; + + std::map registration_; + + int count_; + std::vector entries_; + + Mask current_; + + int inotify_fd_; +}; } // namespace init } // namespace android