From 6400bbc65555324b74b0b7991e0072a40754222d Mon Sep 17 00:00:00 2001 From: meijjaa Date: Sun, 27 Mar 2016 10:31:42 +0200 Subject: [PATCH] Add powerbtnd from Android-x86 libhardware_legacy --- Android.mk | 20 ++++++++ powerbtnd.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 Android.mk create mode 100644 powerbtnd.c diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..2798a7a --- /dev/null +++ b/Android.mk @@ -0,0 +1,20 @@ +# +# Copyright (C) 2016 The Android-x86 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 +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := powerbtnd.c + +LOCAL_MODULE := powerbtnd +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := liblog libcutils + +include $(BUILD_EXECUTABLE) diff --git a/powerbtnd.c b/powerbtnd.c new file mode 100644 index 0000000..855bdc8 --- /dev/null +++ b/powerbtnd.c @@ -0,0 +1,155 @@ +/** + * A daemon to simulate power button of Android + * + * Copyright (C) 2011-2012 The Android-x86 Open Source Project + * + * by Chih-Wei Huang + * + * Licensed under GPLv2 or later + * + **/ + +#define LOG_TAG "powerbtn" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const int MAX_POWERBTNS = 3; + +int openfds(struct pollfd pfds[]) +{ + int cnt = 0; + const char *dirname = "/dev/input"; + DIR *dir; + if ((dir = opendir(dirname))) { + int fd; + struct dirent *de; + while ((de = readdir(dir))) { + if (de->d_name[0] != 'e') // eventX + continue; + char name[PATH_MAX]; + snprintf(name, PATH_MAX, "%s/%s", dirname, de->d_name); + fd = open(name, O_RDWR | O_NONBLOCK); + if (fd < 0) { + ALOGE("could not open %s, %s", name, strerror(errno)); + continue; + } + name[sizeof(name) - 1] = '\0'; + if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { + ALOGE("could not get device name for %s, %s", name, strerror(errno)); + name[0] = '\0'; + } + + // TODO: parse /etc/excluded-input-devices.xml + if (!strcmp(name, "Power Button")) { + ALOGI("open %s(%s) ok fd=%d", de->d_name, name, fd); + pfds[cnt].events = POLLIN; + pfds[cnt++].fd = fd; + if (cnt < MAX_POWERBTNS) + continue; + else + break; + } + close(fd); + } + closedir(dir); + } + + return cnt; +} + +void send_power(int ufd, int down) +{ + struct input_event iev; + iev.type = EV_KEY; + iev.code = KEY_POWER; + iev.value = down; + write(ufd, &iev, sizeof(iev)); + iev.type = EV_SYN; + iev.code = SYN_REPORT; + iev.value = 0; + write(ufd, &iev, sizeof(iev)); +} + +void simulate_powerkey(int ufd, int longpress) +{ + send_power(ufd, 1); + if (longpress) + sleep(2); + send_power(ufd, 0); +} + +int main() +{ + struct pollfd pfds[MAX_POWERBTNS]; + int cnt = openfds(pfds); + int timeout = -1; + int longpress = 1; + char prop[PROPERTY_VALUE_MAX]; + + int ufd = open("/dev/uinput", O_WRONLY | O_NDELAY); + if (ufd >= 0) { + struct uinput_user_dev ud; + memset(&ud, 0, sizeof(ud)); + strcpy(ud.name, "Android Power Button"); + write(ufd, &ud, sizeof(ud)); + ioctl(ufd, UI_SET_EVBIT, EV_KEY); + ioctl(ufd, UI_SET_KEYBIT, KEY_POWER); + ioctl(ufd, UI_DEV_CREATE, 0); + } else { + ALOGE("could not open uinput device: %s", strerror(errno)); + return -1; + } + + property_get("poweroff.doubleclick", prop, NULL); + + for (;;) { + int i; + int pollres = poll(pfds, cnt, timeout) ; + ALOGV("pollres=%d %d\n", pollres, timeout); + if (pollres < 0) { + ALOGE("poll error: %s", strerror(errno)); + break; + } + if (pollres == 0) { + ALOGI("timeout, send one power key"); + simulate_powerkey(ufd, 0); + timeout = -1; + longpress = 1; + continue; + } + for (i = 0; i < cnt; ++i) { + if (pfds[i].revents & POLLIN) { + struct input_event iev; + size_t res = read(pfds[i].fd, &iev, sizeof(iev)); + if (res < sizeof(iev)) { + ALOGW("insufficient input data(%zd)? fd=%d", res, pfds[i].fd); + continue; + } + ALOGD("type=%d scancode=%d value=%d from fd=%d", iev.type, iev.code, iev.value, pfds[i].fd); + if (iev.type == EV_KEY && iev.code == KEY_POWER && !iev.value) { + if (prop[0] != '1' || timeout > 0) { + simulate_powerkey(ufd, longpress); + timeout = -1; + } else { + timeout = 1000; // one second + } + } else if (iev.type == EV_SYN && iev.code == SYN_REPORT && iev.value) { + ALOGI("got a resuming event"); + longpress = 0; + timeout = 1000; // one second + } + } + } + } + + return 0; +} -- 2.11.0