system/hardware/interfaces-mnstshlylh
Revisão | 78688b149314ec16cb2d90507a5908e5f2ba0fda (tree) |
---|---|
Hora | 2020-04-21 00:04:02 |
Autor | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
Add powerbtnd thread
Also send wakeup key on resume to ensure the system wakes up
normally.
@@ -19,11 +19,15 @@ | ||
19 | 19 | #include <android-base/file.h> |
20 | 20 | #include <android-base/logging.h> |
21 | 21 | #include <android-base/properties.h> |
22 | +#include <android-base/stringprintf.h> | |
22 | 23 | #include <android-base/strings.h> |
23 | 24 | #include <google/protobuf/text_format.h> |
24 | 25 | #include <hidl/Status.h> |
25 | 26 | #include <hwbinder/IPCThreadState.h> |
26 | 27 | |
28 | +#include <linux/uinput.h> | |
29 | +#include <dirent.h> | |
30 | +#include <poll.h> | |
27 | 31 | #include <sys/stat.h> |
28 | 32 | #include <sys/types.h> |
29 | 33 |
@@ -32,9 +36,11 @@ | ||
32 | 36 | #include <string> |
33 | 37 | #include <thread> |
34 | 38 | |
39 | +using ::android::base::GetBoolProperty; | |
35 | 40 | using ::android::base::GetProperty; |
36 | 41 | using ::android::base::ReadFdToString; |
37 | 42 | using ::android::base::WriteStringToFd; |
43 | +using ::android::base::StringPrintf; | |
38 | 44 | using ::android::hardware::Void; |
39 | 45 | using ::std::string; |
40 | 46 |
@@ -49,6 +55,146 @@ static const char kSleepState[] = "mem"; | ||
49 | 55 | static constexpr char kSysPowerWakeLock[] = "/sys/power/wake_lock"; |
50 | 56 | static constexpr char kSysPowerWakeUnlock[] = "/sys/power/wake_unlock"; |
51 | 57 | |
58 | +class PowerbtndThread { | |
59 | + public: | |
60 | + PowerbtndThread(); | |
61 | + void sendKeyPower(bool longpress); | |
62 | + void sendKeyWakeup(); | |
63 | + | |
64 | + private: | |
65 | + void emitKey(int key_code, int val); | |
66 | + void run(); | |
67 | + unique_fd mUinputFd; | |
68 | +}; | |
69 | + | |
70 | +PowerbtndThread::PowerbtndThread() | |
71 | + : mUinputFd(open("/dev/uinput", O_WRONLY | O_NDELAY)) | |
72 | +{ | |
73 | + if (mUinputFd < 0) { | |
74 | + LOG(ERROR) << "could not open uinput device: " << strerror(errno); | |
75 | + return; | |
76 | + } | |
77 | + | |
78 | + struct uinput_user_dev ud; | |
79 | + memset(&ud, 0, sizeof(ud)); | |
80 | + strcpy(ud.name, "Android Power Button"); | |
81 | + write(mUinputFd, &ud, sizeof(ud)); | |
82 | + ioctl(mUinputFd, UI_SET_EVBIT, EV_KEY); | |
83 | + ioctl(mUinputFd, UI_SET_KEYBIT, KEY_POWER); | |
84 | + ioctl(mUinputFd, UI_SET_KEYBIT, KEY_WAKEUP); | |
85 | + ioctl(mUinputFd, UI_DEV_CREATE, 0); | |
86 | + | |
87 | + std::thread([this] { run(); }).detach(); | |
88 | + LOG(INFO) << "automatic system suspend enabled"; | |
89 | +} | |
90 | + | |
91 | +void PowerbtndThread::sendKeyPower(bool longpress) | |
92 | +{ | |
93 | + emitKey(KEY_POWER, 1); | |
94 | + if (longpress) sleep(2); | |
95 | + emitKey(KEY_POWER, 0); | |
96 | +} | |
97 | + | |
98 | +void PowerbtndThread::sendKeyWakeup() | |
99 | +{ | |
100 | + emitKey(KEY_WAKEUP, 1); | |
101 | + emitKey(KEY_WAKEUP, 0); | |
102 | +} | |
103 | + | |
104 | +void PowerbtndThread::emitKey(int key_code, int val) | |
105 | +{ | |
106 | + struct input_event iev; | |
107 | + iev.type = EV_KEY; | |
108 | + iev.code = key_code; | |
109 | + iev.value = val; | |
110 | + iev.time.tv_sec = 0; | |
111 | + iev.time.tv_usec = 0; | |
112 | + write(mUinputFd, &iev, sizeof(iev)); | |
113 | + iev.type = EV_SYN; | |
114 | + iev.code = SYN_REPORT; | |
115 | + iev.value = 0; | |
116 | + write(mUinputFd, &iev, sizeof(iev)); | |
117 | + LOG(INFO) << StringPrintf("send key %d (%d) on fd %d", key_code, val, mUinputFd.get()); | |
118 | +} | |
119 | + | |
120 | +void PowerbtndThread::run() | |
121 | +{ | |
122 | + int cnt = 0, timeout = -1, pollres; | |
123 | + bool longpress = true; | |
124 | + bool doubleclick = GetBoolProperty("poweroff.doubleclick", false); | |
125 | + struct pollfd pfds[3]; | |
126 | + const char *dirname = "/dev/input"; | |
127 | + | |
128 | + if (DIR *dir = opendir(dirname)) { | |
129 | + struct dirent *de; | |
130 | + while ((cnt < 3) && (de = readdir(dir))) { | |
131 | + int fd; | |
132 | + char name[PATH_MAX]; | |
133 | + if (de->d_name[0] != 'e') /* eventX */ | |
134 | + continue; | |
135 | + snprintf(name, PATH_MAX, "%s/%s", dirname, de->d_name); | |
136 | + fd = open(name, O_RDWR | O_NONBLOCK); | |
137 | + if (fd < 0) { | |
138 | + LOG(ERROR) << StringPrintf("could not open %s, %s", name, strerror(errno)); | |
139 | + continue; | |
140 | + } | |
141 | + name[sizeof(name) - 1] = '\0'; | |
142 | + if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { | |
143 | + LOG(ERROR) << StringPrintf("could not get device name for %s, %s", name, strerror(errno)); | |
144 | + name[0] = '\0'; | |
145 | + } | |
146 | + // TODO: parse /etc/excluded-input-devices.xml | |
147 | + if (strcmp(name, "Power Button")) { | |
148 | + close(fd); | |
149 | + continue; | |
150 | + } | |
151 | + | |
152 | + LOG(INFO) << StringPrintf("open %s(%s) ok fd=%d", de->d_name, name, fd); | |
153 | + pfds[cnt].events = POLLIN; | |
154 | + pfds[cnt++].fd = fd; | |
155 | + } | |
156 | + closedir(dir); | |
157 | + } | |
158 | + | |
159 | + while (cnt > 0) { | |
160 | + if ((pollres = poll(pfds, cnt, timeout)) < 0) { | |
161 | + LOG(ERROR) << "poll error: " << strerror(errno); | |
162 | + break; | |
163 | + } | |
164 | + LOG(VERBOSE) << "pollres=" << pollres << " timeout=" << timeout; | |
165 | + if (pollres == 0) { | |
166 | + LOG(INFO) << "timeout, send one power key"; | |
167 | + sendKeyPower(0); | |
168 | + timeout = -1; | |
169 | + longpress = true; | |
170 | + continue; | |
171 | + } | |
172 | + for (int i = 0; i < cnt; ++i) { | |
173 | + if (pfds[i].revents & POLLIN) { | |
174 | + struct input_event iev; | |
175 | + size_t res = read(pfds[i].fd, &iev, sizeof(iev)); | |
176 | + if (res < sizeof(iev)) { | |
177 | + LOG(WARNING) << StringPrintf("insufficient input data(%zd)? fd=%d", res, pfds[i].fd); | |
178 | + continue; | |
179 | + } | |
180 | + LOG(DEBUG) << StringPrintf("type=%d code=%d value=%d from fd=%d", iev.type, iev.code, iev.value, pfds[i].fd); | |
181 | + if (iev.type == EV_KEY && iev.code == KEY_POWER && !iev.value) { | |
182 | + if (!doubleclick || timeout > 0) { | |
183 | + sendKeyPower(longpress); | |
184 | + timeout = -1; | |
185 | + } else { | |
186 | + timeout = 1000; // one second | |
187 | + } | |
188 | + } else if (iev.type == EV_SYN && iev.code == SYN_REPORT && iev.value) { | |
189 | + LOG(INFO) << "got a resuming event"; | |
190 | + longpress = false; | |
191 | + timeout = 1000; // one second | |
192 | + } | |
193 | + } | |
194 | + } | |
195 | + } | |
196 | +} | |
197 | + | |
52 | 198 | // This function assumes that data in fd is small enough that it can be read in one go. |
53 | 199 | // We use this function instead of the ones available in libbase because it doesn't block |
54 | 200 | // indefinitely when reading from socket streams which are used for testing. |
@@ -101,6 +247,7 @@ SystemSuspend::SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd, size_t | ||
101 | 247 | : mSuspendCounter(0), |
102 | 248 | mWakeupCountFd(std::move(wakeupCountFd)), |
103 | 249 | mStateFd(std::move(stateFd)), |
250 | + mPwrbtnd(new PowerbtndThread()), | |
104 | 251 | mMaxStatsEntries(maxStatsEntries), |
105 | 252 | mBaseSleepTime(baseSleepTime), |
106 | 253 | mSleepTime(baseSleepTime), |
@@ -259,6 +406,8 @@ void SystemSuspend::initAutosuspend() { | ||
259 | 406 | |
260 | 407 | if (!success) { |
261 | 408 | PLOG(VERBOSE) << "error writing to /sys/power/state"; |
409 | + } else { | |
410 | + mPwrbtnd->sendKeyWakeup(); | |
262 | 411 | } |
263 | 412 | |
264 | 413 | mControlService->notifyWakeup(success); |
@@ -46,6 +46,7 @@ using WakeLockIdType = std::string; | ||
46 | 46 | |
47 | 47 | using namespace std::chrono_literals; |
48 | 48 | |
49 | +class PowerbtndThread; | |
49 | 50 | class SystemSuspend; |
50 | 51 | |
51 | 52 | std::string readFd(int fd); |
@@ -90,6 +91,7 @@ class SystemSuspend : public ISystemSuspend { | ||
90 | 91 | unique_fd mWakeupCountFd; |
91 | 92 | unique_fd mStateFd; |
92 | 93 | std::string mSleepState; |
94 | + PowerbtndThread *mPwrbtnd; | |
93 | 95 | |
94 | 96 | // mStats can be inconsistent with with mSuspendCounter since we use two separate locks to |
95 | 97 | // protect these. However, since mStats is only for debugging we prioritize performance. |
@@ -1,5 +1,5 @@ | ||
1 | 1 | service system_suspend /system/bin/hw/android.system.suspend@1.0-service |
2 | 2 | class hal |
3 | 3 | user system |
4 | - group system wakelock | |
4 | + group system wakelock uhid input | |
5 | 5 | capabilities BLOCK_SUSPEND |