1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "powerhal-libperfmgr"
18 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
19
20 #include "InteractionHandler.h"
21
22 #include <android-base/properties.h>
23 #include <fcntl.h>
24 #include <perfmgr/HintManager.h>
25 #include <poll.h>
26 #include <sys/eventfd.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <utils/Log.h>
30 #include <utils/Trace.h>
31
32 #include <array>
33 #include <memory>
34
35 #define MAX_LENGTH 64
36
37 #define MSINSEC 1000L
38 #define NSINMS 1000000L
39
40 namespace aidl {
41 namespace google {
42 namespace hardware {
43 namespace power {
44 namespace impl {
45 namespace pixel {
46
47 namespace {
48
49 static const bool kDisplayIdleSupport =
50 ::android::base::GetBoolProperty("vendor.powerhal.disp.idle_support", true);
51 static const std::array<const char *, 3> kDispIdlePath = {"/sys/class/drm/card0/device/idle_state",
52 "/sys/class/graphics/fb0/idle_state",
53 "/sys/class/graphics/fb0/device/idle_state"};
54 static const uint32_t kWaitMs =
55 ::android::base::GetUintProperty("vendor.powerhal.disp.idle_wait", /*default*/ 100U);
56 static const uint32_t kMinDurationMs =
57 ::android::base::GetUintProperty("vendor.powerhal.interaction.min", /*default*/ 1400U);
58 static const uint32_t kMaxDurationMs =
59 ::android::base::GetUintProperty("vendor.powerhal.interaction.max", /*default*/ 5650U);
60 static const uint32_t kDurationOffsetMs =
61 ::android::base::GetUintProperty("vendor.powerhal.interaction.offset", /*default*/ 650U);
62
CalcTimespecDiffMs(struct timespec start,struct timespec end)63 static size_t CalcTimespecDiffMs(struct timespec start, struct timespec end) {
64 size_t diff_in_ms = 0;
65 diff_in_ms += (end.tv_sec - start.tv_sec) * MSINSEC;
66 diff_in_ms += (end.tv_nsec - start.tv_nsec) / NSINMS;
67 return diff_in_ms;
68 }
69
FbIdleOpen(void)70 static int FbIdleOpen(void) {
71 int fd;
72 for (const auto &path : kDispIdlePath) {
73 fd = open(path, O_RDONLY);
74 if (fd >= 0)
75 return fd;
76 }
77 ALOGE("Unable to open fb idle state path (%d)", errno);
78 return -1;
79 }
80
81 } // namespace
82
83 using ::android::perfmgr::HintManager;
84
InteractionHandler()85 InteractionHandler::InteractionHandler()
86 : mState(INTERACTION_STATE_UNINITIALIZED), mDurationMs(0) {}
87
~InteractionHandler()88 InteractionHandler::~InteractionHandler() {
89 Exit();
90 }
91
Init()92 bool InteractionHandler::Init() {
93 std::lock_guard<std::mutex> lk(mLock);
94
95 if (mState != INTERACTION_STATE_UNINITIALIZED)
96 return true;
97
98 int fd = FbIdleOpen();
99 if (fd < 0)
100 return false;
101 mIdleFd = fd;
102
103 mEventFd = eventfd(0, EFD_NONBLOCK);
104 if (mEventFd < 0) {
105 ALOGE("Unable to create event fd (%d)", errno);
106 close(mIdleFd);
107 return false;
108 }
109
110 mState = INTERACTION_STATE_IDLE;
111 mThread = std::unique_ptr<std::thread>(new std::thread(&InteractionHandler::Routine, this));
112
113 return true;
114 }
115
Exit()116 void InteractionHandler::Exit() {
117 std::unique_lock<std::mutex> lk(mLock);
118 if (mState == INTERACTION_STATE_UNINITIALIZED)
119 return;
120
121 AbortWaitLocked();
122 mState = INTERACTION_STATE_UNINITIALIZED;
123 lk.unlock();
124
125 mCond.notify_all();
126 mThread->join();
127
128 close(mEventFd);
129 close(mIdleFd);
130 }
131
PerfLock()132 void InteractionHandler::PerfLock() {
133 ALOGV("%s: acquiring perf lock", __func__);
134 if (!HintManager::GetInstance()->DoHint("INTERACTION")) {
135 ALOGE("%s: do hint INTERACTION failed", __func__);
136 }
137 }
138
PerfRel()139 void InteractionHandler::PerfRel() {
140 ALOGV("%s: releasing perf lock", __func__);
141 if (!HintManager::GetInstance()->EndHint("INTERACTION")) {
142 ALOGE("%s: end hint INTERACTION failed", __func__);
143 }
144 }
145
Acquire(int32_t duration)146 void InteractionHandler::Acquire(int32_t duration) {
147 ATRACE_CALL();
148
149 std::lock_guard<std::mutex> lk(mLock);
150
151 int inputDuration = duration + kDurationOffsetMs;
152 int finalDuration;
153 if (inputDuration > kMaxDurationMs)
154 finalDuration = kMaxDurationMs;
155 else if (inputDuration > kMinDurationMs)
156 finalDuration = inputDuration;
157 else
158 finalDuration = kMinDurationMs;
159
160 // Fallback to do boost directly
161 // 1) override property is set OR
162 // 2) InteractionHandler not initialized
163 if (!kDisplayIdleSupport || mState == INTERACTION_STATE_UNINITIALIZED) {
164 HintManager::GetInstance()->DoHint("INTERACTION", std::chrono::milliseconds(finalDuration));
165 return;
166 }
167
168 struct timespec cur_timespec;
169 clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
170 if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
171 size_t elapsed_time = CalcTimespecDiffMs(mLastTimespec, cur_timespec);
172 // don't hint if previous hint's duration covers this hint's duration
173 if (elapsed_time <= (mDurationMs - finalDuration)) {
174 ALOGV("%s: Previous duration (%d) cover this (%d) elapsed: %lld", __func__,
175 static_cast<int>(mDurationMs), static_cast<int>(finalDuration),
176 static_cast<long long>(elapsed_time));
177 return;
178 }
179 }
180 mLastTimespec = cur_timespec;
181 mDurationMs = finalDuration;
182
183 ALOGV("%s: input: %d final duration: %d", __func__, duration, finalDuration);
184
185 if (mState == INTERACTION_STATE_WAITING)
186 AbortWaitLocked();
187 else if (mState == INTERACTION_STATE_IDLE)
188 PerfLock();
189
190 mState = INTERACTION_STATE_INTERACTION;
191 mCond.notify_one();
192 }
193
Release()194 void InteractionHandler::Release() {
195 std::lock_guard<std::mutex> lk(mLock);
196 if (mState == INTERACTION_STATE_WAITING) {
197 ATRACE_CALL();
198 PerfRel();
199 mState = INTERACTION_STATE_IDLE;
200 } else {
201 // clear any wait aborts pending in event fd
202 uint64_t val;
203 ssize_t ret = read(mEventFd, &val, sizeof(val));
204
205 ALOGW_IF(ret < 0, "%s: failed to clear eventfd (%zd, %d)", __func__, ret, errno);
206 }
207 }
208
209 // should be called while locked
AbortWaitLocked()210 void InteractionHandler::AbortWaitLocked() {
211 uint64_t val = 1;
212 ssize_t ret = write(mEventFd, &val, sizeof(val));
213 if (ret != sizeof(val))
214 ALOGW("Unable to write to event fd (%zd)", ret);
215 }
216
WaitForIdle(int32_t wait_ms,int32_t timeout_ms)217 void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) {
218 char data[MAX_LENGTH];
219 ssize_t ret;
220 struct pollfd pfd[2];
221
222 ATRACE_CALL();
223
224 ALOGV("%s: wait:%d timeout:%d", __func__, wait_ms, timeout_ms);
225
226 pfd[0].fd = mEventFd;
227 pfd[0].events = POLLIN;
228 pfd[1].fd = mIdleFd;
229 pfd[1].events = POLLPRI | POLLERR;
230
231 ret = poll(pfd, 1, wait_ms);
232 if (ret > 0) {
233 ALOGV("%s: wait aborted", __func__);
234 return;
235 } else if (ret < 0) {
236 ALOGE("%s: error in poll while waiting", __func__);
237 return;
238 }
239
240 ret = pread(mIdleFd, data, sizeof(data), 0);
241 if (!ret) {
242 ALOGE("%s: Unexpected EOF!", __func__);
243 return;
244 }
245
246 if (!strncmp(data, "idle", 4)) {
247 ALOGV("%s: already idle", __func__);
248 return;
249 }
250
251 ret = poll(pfd, 2, timeout_ms);
252 if (ret < 0)
253 ALOGE("%s: Error on waiting for idle (%zd)", __func__, ret);
254 else if (ret == 0)
255 ALOGV("%s: timed out waiting for idle", __func__);
256 else if (pfd[0].revents)
257 ALOGV("%s: wait for idle aborted", __func__);
258 else if (pfd[1].revents)
259 ALOGV("%s: idle detected", __func__);
260 }
261
Routine()262 void InteractionHandler::Routine() {
263 pthread_setname_np(pthread_self(), "DispIdle");
264 std::unique_lock<std::mutex> lk(mLock, std::defer_lock);
265
266 while (true) {
267 lk.lock();
268 mCond.wait(lk, [&] { return mState != INTERACTION_STATE_IDLE; });
269 if (mState == INTERACTION_STATE_UNINITIALIZED)
270 return;
271 mState = INTERACTION_STATE_WAITING;
272 lk.unlock();
273
274 WaitForIdle(kWaitMs, mDurationMs);
275 Release();
276 }
277 }
278
279 } // namespace pixel
280 } // namespace impl
281 } // namespace power
282 } // namespace hardware
283 } // namespace google
284 } // namespace aidl
285