From 1385725e0995052ad96b482a60e9ffd5b663ddb5 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Fri, 18 May 2018 15:25:15 -0700 Subject: [PATCH] init: switch out keychord id with std::vector match of chords Drop all references to keychord_id and id and instead use keycodes_ as the id. The keycodes are a std::vector with an unique sorted-order emplacement method added in the parser. Solves the academic issue with duplicate keychords and trigger all services that match rather than first match only. Test: init_tests Bug: 64114943 Change-Id: I5582779d81458fda393004c551c0d3c03d9471e0 --- init/init.cpp | 32 ++++++++++++++++++++------------ init/keychords.cpp | 33 +++++++++++++++------------------ init/keychords.h | 13 +++++-------- init/service.cpp | 3 +-- init/service.h | 5 +---- init/service_test.cpp | 2 -- 6 files changed, 42 insertions(+), 46 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index 5652c5e51..82648d991 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -553,22 +553,30 @@ static void InstallSignalFdHandler(Epoll* epoll) { } } -void HandleKeychord(int id) { +void HandleKeychord(const std::vector& keycodes) { // Only handle keychords if adb is enabled. std::string adb_enabled = android::base::GetProperty("init.svc.adbd", ""); - if (adb_enabled == "running") { - Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id); - if (svc) { - LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id; + if (adb_enabled != "running") { + LOG(WARNING) << "Not starting service for keychord " << android::base::Join(keycodes, ' ') + << " because ADB is disabled"; + return; + } + + auto found = false; + for (const auto& service : ServiceList::GetInstance()) { + auto svc = service.get(); + if (svc->keycodes() == keycodes) { + found = true; + LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " + << android::base::Join(keycodes, ' '); if (auto result = svc->Start(); !result) { - LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id - << ": " << result.error(); + LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " + << android::base::Join(keycodes, ' ') << ": " << result.error(); } - } else { - LOG(ERROR) << "Service for keychord " << id << " not found"; } - } else { - LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled"; + } + if (!found) { + LOG(ERROR) << "Service for keychord " << android::base::Join(keycodes, ' ') << " not found"; } } @@ -753,7 +761,7 @@ int main(int argc, char** argv) { am.QueueBuiltinAction( [&epoll, &keychords](const BuiltinArguments& args) -> Result { for (const auto& svc : ServiceList::GetInstance()) { - svc->set_keychord_id(keychords.GetId(svc->keycodes())); + keychords.Register(svc->keycodes()); } keychords.Start(&epoll, HandleKeychord); return Success(); diff --git a/init/keychords.cpp b/init/keychords.cpp index 9aa8b2a78..1af06dd6c 100644 --- a/init/keychords.cpp +++ b/init/keychords.cpp @@ -37,7 +37,7 @@ namespace android { namespace init { -Keychords::Keychords() : epoll_(nullptr), count_(0), inotify_fd_(-1) {} +Keychords::Keychords() : epoll_(nullptr), inotify_fd_(-1) {} Keychords::~Keychords() noexcept { if (inotify_fd_ >= 0) { @@ -108,23 +108,22 @@ void Keychords::Mask::operator|=(const Keychords::Mask& rval) { } } -Keychords::Entry::Entry(const std::vector& keycodes, int id) - : keycodes(keycodes), id(id), notified(false) {} +Keychords::Entry::Entry() : notified(false) {} void Keychords::LambdaCheck() { - for (auto& e : entries_) { + for (auto& [keycodes, entry] : entries_) { auto found = true; - for (auto& code : e.keycodes) { + for (auto& code : keycodes) { if (!current_.GetBit(code)) { - e.notified = false; + entry.notified = false; found = false; break; } } if (!found) continue; - if (e.notified) continue; - e.notified = true; - handler_(e.id); + if (entry.notified) continue; + entry.notified = true; + handler_(keycodes); } } @@ -158,8 +157,8 @@ bool Keychords::GeteventEnable(int fd) { #endif Keychords::Mask mask; - for (auto& e : entries_) { - for (auto& code : e.keycodes) { + for (auto& [keycodes, entry] : entries_) { + for (auto& code : keycodes) { mask.resize(code); mask.SetBit(code); } @@ -271,17 +270,15 @@ void Keychords::GeteventOpenDevice() { } } -int Keychords::GetId(const std::vector& keycodes) { - if (keycodes.empty()) return 0; - ++count_; - entries_.emplace_back(Entry(keycodes, count_)); - return count_; +void Keychords::Register(const std::vector& keycodes) { + if (keycodes.empty()) return; + entries_.try_emplace(keycodes, Entry()); } -void Keychords::Start(Epoll* epoll, std::function handler) { +void Keychords::Start(Epoll* epoll, std::function&)> handler) { epoll_ = epoll; handler_ = handler; - if (count_) GeteventOpenDevice(); + if (entries_.size()) GeteventOpenDevice(); } } // namespace init diff --git a/init/keychords.h b/init/keychords.h index 74a91951b..00ed2052e 100644 --- a/init/keychords.h +++ b/init/keychords.h @@ -36,8 +36,8 @@ class Keychords { Keychords& operator=(Keychords&&) = delete; ~Keychords() noexcept; - int GetId(const std::vector& keycodes); - void Start(Epoll* epoll, std::function handler); + void Register(const std::vector& keycodes); + void Start(Epoll* epoll, std::function&)> handler); private: // Bit management @@ -65,10 +65,8 @@ class Keychords { }; struct Entry { - Entry(const std::vector& keycodes, int id); + Entry(); - const std::vector keycodes; - const int id; bool notified; }; @@ -84,12 +82,11 @@ class Keychords { void GeteventCloseDevice(const std::string& device); Epoll* epoll_; - std::function handler_; + std::function&)> handler_; std::map registration_; - int count_; - std::vector entries_; + std::map, Entry> entries_; Mask current_; diff --git a/init/service.cpp b/init/service.cpp index 5778a93b0..41188f234 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -229,7 +229,6 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, seclabel_(seclabel), onrestart_(false, subcontext_for_restart_commands, "", 0, "onrestart", {}), - keychord_id_(0), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0), @@ -549,7 +548,7 @@ Result Service::ParseKeycodes(const std::vector& args) { for (auto& key : keycodes_) { if (key == code) return Error() << "duplicate keycode: " << args[i]; } - keycodes_.emplace_back(code); + keycodes_.insert(std::upper_bound(keycodes_.begin(), keycodes_.end(), code), code); } else { return Error() << "invalid keycode: " << args[i]; } diff --git a/init/service.h b/init/service.h index cbfd52f29..ea79a0744 100644 --- a/init/service.h +++ b/init/service.h @@ -108,8 +108,6 @@ class Service { const std::vector& supp_gids() const { return supp_gids_; } const std::string& seclabel() const { return seclabel_; } const std::vector& keycodes() const { return keycodes_; } - int keychord_id() const { return keychord_id_; } - void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; } IoSchedClass ioprio_class() const { return ioprio_class_; } int ioprio_pri() const { return ioprio_pri_; } const std::set& interfaces() const { return interfaces_; } @@ -199,9 +197,8 @@ class Service { std::set interfaces_; // e.g. some.package.foo@1.0::IBaz/instance-name - // keycodes for triggering this service via /dev/keychord + // keycodes for triggering this service via /dev/input/input* std::vector keycodes_; - int keychord_id_; IoSchedClass ioprio_class_; int ioprio_pri_; diff --git a/init/service_test.cpp b/init/service_test.cpp index b43c2e9b4..194aa2be0 100644 --- a/init/service_test.cpp +++ b/init/service_test.cpp @@ -46,7 +46,6 @@ TEST(service, pod_initialized) { EXPECT_EQ(0U, service_in_old_memory->uid()); EXPECT_EQ(0U, service_in_old_memory->gid()); EXPECT_EQ(0U, service_in_old_memory->namespace_flags()); - EXPECT_EQ(0, service_in_old_memory->keychord_id()); EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory->ioprio_class()); EXPECT_EQ(0, service_in_old_memory->ioprio_pri()); EXPECT_EQ(0, service_in_old_memory->priority()); @@ -66,7 +65,6 @@ TEST(service, pod_initialized) { EXPECT_EQ(0U, service_in_old_memory2->uid()); EXPECT_EQ(0U, service_in_old_memory2->gid()); EXPECT_EQ(0U, service_in_old_memory2->namespace_flags()); - EXPECT_EQ(0, service_in_old_memory2->keychord_id()); EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory2->ioprio_class()); EXPECT_EQ(0, service_in_old_memory2->ioprio_pri()); EXPECT_EQ(0, service_in_old_memory2->priority());