init: refactor keychord for testing

Move things around so that keychords.cpp is independent of service
and init and can be individually tested with few dependencies.
Permits also rolling out the keychords as a class in a future commit.
Improve parser checking.

Test: init_tests
Bug: 64114943
Change-Id: I82570bc6269ed478db784ec38a8bc916da2be2be
This commit is contained in:
Mark Salyzyn 2018-05-16 15:10:24 -07:00
parent e82401e592
commit eca2507634
5 changed files with 52 additions and 44 deletions

View File

@ -232,6 +232,8 @@ cc_binary {
"action_parser.cpp",
"capabilities.cpp",
"descriptors.cpp",
"epoll.cpp",
"keychords.cpp",
"import_parser.cpp",
"host_init_parser.cpp",
"host_init_stubs.cpp",

View File

@ -553,6 +553,25 @@ static void InstallSignalFdHandler(Epoll* epoll) {
}
}
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") {
Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
if (svc) {
LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
if (auto result = svc->Start(); !result) {
LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
<< ": " << result.error();
}
} else {
LOG(ERROR) << "Service for keychord " << id << " not found";
}
} else {
LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
}
}
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
@ -732,7 +751,10 @@ int main(int argc, char** argv) {
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(
[&epoll](const BuiltinArguments& args) -> Result<Success> {
KeychordInit(&epoll);
for (const auto& svc : ServiceList::GetInstance()) {
svc->set_keychord_id(GetKeychordId(svc->keycodes()));
}
KeychordInit(&epoll, HandleKeychord);
return Success();
},
"KeychordInit");

View File

@ -33,10 +33,6 @@
#include <vector>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include "init.h"
#include "service.h"
namespace android {
namespace init {
@ -45,6 +41,7 @@ namespace {
int keychords_count;
Epoll* epoll;
std::function<void(int)> handle_keychord;
struct KeychordEntry {
const std::vector<int> keycodes;
@ -124,25 +121,6 @@ constexpr char kDevicePath[] = "/dev/input";
std::map<std::string, int> keychord_registration;
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") {
Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
if (svc) {
LOG(INFO) << "Starting service '" << svc->name() << "' from keychord " << id;
if (auto result = svc->Start(); !result) {
LOG(ERROR) << "Could not start service '" << svc->name() << "' from keychord " << id
<< ": " << result.error();
}
} else {
LOG(ERROR) << "Service for keychord " << id << " not found";
}
} else {
LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
}
}
void KeychordLambdaCheck() {
for (auto& e : keychord_entries) {
bool found = true;
@ -156,7 +134,7 @@ void KeychordLambdaCheck() {
if (!found) continue;
if (e.notified) continue;
e.notified = true;
HandleKeychord(e.id);
handle_keychord(e.id);
}
}
@ -169,12 +147,12 @@ void KeychordLambdaHandler(int fd) {
}
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;
#ifdef EVIOCSMASK
static auto EviocsmaskSupported = true;
if (EviocsmaskSupported) {
KeychordMask mask(EV_KEY);
mask.SetBit(EV_KEY);
@ -187,6 +165,7 @@ bool KeychordGeteventEnable(int fd) {
EviocsmaskSupported = false;
}
}
#endif
KeychordMask mask;
for (auto& e : keychord_entries) {
@ -202,6 +181,7 @@ bool KeychordGeteventEnable(int fd) {
if (res == -1) return false;
if (!(available & mask)) return false;
#ifdef EVIOCSMASK
if (EviocsmaskSupported) {
input_mask msg = {};
msg.type = EV_KEY;
@ -209,6 +189,7 @@ bool KeychordGeteventEnable(int fd) {
msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
::ioctl(fd, EVIOCSMASK, &msg);
}
#endif
KeychordMask set(mask.size());
res = ::ioctl(fd, EVIOCGKEY(res), set.data());
@ -299,23 +280,18 @@ void GeteventOpenDevice() {
if (inotify_fd >= 0) epoll->RegisterHandler(inotify_fd, InotifyHandler);
}
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(Epoll* init_epoll) {
int GetKeychordId(const std::vector<int>& keycodes) {
if (keycodes.empty()) return 0;
++keychords_count;
keychord_entries.emplace_back(KeychordEntry(keycodes, keychords_count));
return keychords_count;
}
void KeychordInit(Epoll* init_epoll, std::function<void(int)> handler) {
epoll = init_epoll;
for (const auto& service : ServiceList::GetInstance()) {
AddServiceKeycodes(service.get());
}
handle_keychord = handler;
if (keychords_count) GeteventOpenDevice();
}

View File

@ -17,12 +17,16 @@
#ifndef _INIT_KEYCHORDS_H_
#define _INIT_KEYCHORDS_H_
#include <functional>
#include <vector>
#include "epoll.h"
namespace android {
namespace init {
void KeychordInit(Epoll* init_epoll);
void KeychordInit(Epoll* init_epoll, std::function<void(int)> handler);
int GetKeychordId(const std::vector<int>& keycodes);
} // namespace init
} // namespace android

View File

@ -18,6 +18,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <linux/input.h>
#include <linux/securebits.h>
#include <sched.h>
#include <sys/mount.h>
@ -544,10 +545,13 @@ Result<Success> Service::ParseIoprio(const std::vector<std::string>& args) {
Result<Success> Service::ParseKeycodes(const std::vector<std::string>& args) {
for (std::size_t i = 1; i < args.size(); i++) {
int code;
if (ParseInt(args[i], &code)) {
if (ParseInt(args[i], &code, 0, KEY_MAX)) {
for (auto& key : keycodes_) {
if (key == code) return Error() << "duplicate keycode: " << args[i];
}
keycodes_.emplace_back(code);
} else {
LOG(WARNING) << "ignoring invalid keycode: " << args[i];
return Error() << "invalid keycode: " << args[i];
}
}
return Success();