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 "[email protected]"
18 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
19 
20 #include <fcntl.h>
21 #include <poll.h>
22 #include <sys/eventfd.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <utils/Log.h>
26 #include <utils/Trace.h>
27 #include <memory>
28 
29 #include "InteractionHandler.h"
30 
31 #define MAX_LENGTH 64
32 
33 #define MSINSEC 1000L
34 #define USINMS 1000000L
35 
36 static const std::vector<std::string> fb_idle_patch = {"/sys/class/drm/card0/device/idle_state",
37                                                        "/sys/class/graphics/fb0/idle_state"};
38 
InteractionHandler(std::shared_ptr<HintManager> const & hint_manager)39 InteractionHandler::InteractionHandler(std::shared_ptr<HintManager> const &hint_manager)
40     : mState(INTERACTION_STATE_UNINITIALIZED),
41       mWaitMs(100),
42       mMinDurationMs(1400),
43       mMaxDurationMs(5650),
44       mDurationMs(0),
45       mHintManager(hint_manager) {}
46 
~InteractionHandler()47 InteractionHandler::~InteractionHandler() {
48     Exit();
49 }
50 
fb_idle_open(void)51 static int fb_idle_open(void) {
52     int fd;
53     for (auto &path : fb_idle_patch) {
54         fd = open(path.c_str(), O_RDONLY);
55         if (fd >= 0)
56             return fd;
57     }
58     ALOGE("Unable to open fb idle state path (%d)", errno);
59     return -1;
60 }
61 
Init()62 bool InteractionHandler::Init() {
63     std::lock_guard<std::mutex> lk(mLock);
64 
65     if (mState != INTERACTION_STATE_UNINITIALIZED)
66         return true;
67 
68     int fd = fb_idle_open();
69     if (fd < 0)
70         return false;
71     mIdleFd = fd;
72 
73     mEventFd = eventfd(0, EFD_NONBLOCK);
74     if (mEventFd < 0) {
75         ALOGE("Unable to create event fd (%d)", errno);
76         close(mIdleFd);
77         return false;
78     }
79 
80     mState = INTERACTION_STATE_IDLE;
81     mThread = std::unique_ptr<std::thread>(new std::thread(&InteractionHandler::Routine, this));
82 
83     return true;
84 }
85 
Exit()86 void InteractionHandler::Exit() {
87     std::unique_lock<std::mutex> lk(mLock);
88     if (mState == INTERACTION_STATE_UNINITIALIZED)
89         return;
90 
91     AbortWaitLocked();
92     mState = INTERACTION_STATE_UNINITIALIZED;
93     lk.unlock();
94 
95     mCond.notify_all();
96     mThread->join();
97 
98     close(mEventFd);
99     close(mIdleFd);
100 }
101 
PerfLock()102 void InteractionHandler::PerfLock() {
103     ALOGV("%s: acquiring perf lock", __func__);
104     if (!mHintManager->DoHint("INTERACTION")) {
105         ALOGE("%s: do hint INTERACTION failed", __func__);
106     }
107     ATRACE_INT("interaction_lock", 1);
108 }
109 
PerfRel()110 void InteractionHandler::PerfRel() {
111     ALOGV("%s: releasing perf lock", __func__);
112     if (!mHintManager->EndHint("INTERACTION")) {
113         ALOGE("%s: end hint INTERACTION failed", __func__);
114     }
115     ATRACE_INT("interaction_lock", 0);
116 }
117 
CalcTimespecDiffMs(struct timespec start,struct timespec end)118 size_t InteractionHandler::CalcTimespecDiffMs(struct timespec start, struct timespec end) {
119     size_t diff_in_us = 0;
120     diff_in_us += (end.tv_sec - start.tv_sec) * MSINSEC;
121     diff_in_us += (end.tv_nsec - start.tv_nsec) / USINMS;
122     return diff_in_us;
123 }
124 
Acquire(int32_t duration)125 void InteractionHandler::Acquire(int32_t duration) {
126     ATRACE_CALL();
127 
128     std::lock_guard<std::mutex> lk(mLock);
129     if (mState == INTERACTION_STATE_UNINITIALIZED) {
130         ALOGW("%s: called while uninitialized", __func__);
131         return;
132     }
133 
134     int inputDuration = duration + 650;
135     int finalDuration;
136     if (inputDuration > mMaxDurationMs)
137         finalDuration = mMaxDurationMs;
138     else if (inputDuration > mMinDurationMs)
139         finalDuration = inputDuration;
140     else
141         finalDuration = mMinDurationMs;
142 
143     struct timespec cur_timespec;
144     clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
145     if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
146         size_t elapsed_time = CalcTimespecDiffMs(mLastTimespec, cur_timespec);
147         // don't hint if previous hint's duration covers this hint's duration
148         if (elapsed_time <= (mDurationMs - finalDuration)) {
149             ALOGV("%s: Previous duration (%d) cover this (%d) elapsed: %lld", __func__,
150                   static_cast<int>(mDurationMs), static_cast<int>(finalDuration),
151                   static_cast<long long>(elapsed_time));
152             return;
153         }
154     }
155     mLastTimespec = cur_timespec;
156     mDurationMs = finalDuration;
157 
158     ALOGV("%s: input: %d final duration: %d", __func__, duration, finalDuration);
159 
160     if (mState == INTERACTION_STATE_WAITING)
161         AbortWaitLocked();
162     else if (mState == INTERACTION_STATE_IDLE)
163         PerfLock();
164 
165     mState = INTERACTION_STATE_INTERACTION;
166     mCond.notify_one();
167 }
168 
Release()169 void InteractionHandler::Release() {
170     std::lock_guard<std::mutex> lk(mLock);
171     if (mState == INTERACTION_STATE_WAITING) {
172         ATRACE_CALL();
173         PerfRel();
174         mState = INTERACTION_STATE_IDLE;
175     } else {
176         // clear any wait aborts pending in event fd
177         uint64_t val;
178         ssize_t ret = read(mEventFd, &val, sizeof(val));
179 
180         ALOGW_IF(ret < 0, "%s: failed to clear eventfd (%zd, %d)", __func__, ret, errno);
181     }
182 }
183 
184 // should be called while locked
AbortWaitLocked()185 void InteractionHandler::AbortWaitLocked() {
186     uint64_t val = 1;
187     ssize_t ret = write(mEventFd, &val, sizeof(val));
188     if (ret != sizeof(val))
189         ALOGW("Unable to write to event fd (%zd)", ret);
190 }
191 
WaitForIdle(int32_t wait_ms,int32_t timeout_ms)192 void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) {
193     char data[MAX_LENGTH];
194     ssize_t ret;
195     struct pollfd pfd[2];
196 
197     ATRACE_CALL();
198 
199     ALOGV("%s: wait:%d timeout:%d", __func__, wait_ms, timeout_ms);
200 
201     pfd[0].fd = mEventFd;
202     pfd[0].events = POLLIN;
203     pfd[1].fd = mIdleFd;
204     pfd[1].events = POLLPRI | POLLERR;
205 
206     ret = poll(pfd, 1, wait_ms);
207     if (ret > 0) {
208         ALOGV("%s: wait aborted", __func__);
209         return;
210     } else if (ret < 0) {
211         ALOGE("%s: error in poll while waiting", __func__);
212         return;
213     }
214 
215     ret = pread(mIdleFd, data, sizeof(data), 0);
216     if (!ret) {
217         ALOGE("%s: Unexpected EOF!", __func__);
218         return;
219     }
220 
221     if (!strncmp(data, "idle", 4)) {
222         ALOGV("%s: already idle", __func__);
223         return;
224     }
225 
226     ret = poll(pfd, 2, timeout_ms);
227     if (ret < 0)
228         ALOGE("%s: Error on waiting for idle (%zd)", __func__, ret);
229     else if (ret == 0)
230         ALOGV("%s: timed out waiting for idle", __func__);
231     else if (pfd[0].revents)
232         ALOGV("%s: wait for idle aborted", __func__);
233     else if (pfd[1].revents)
234         ALOGV("%s: idle detected", __func__);
235 }
236 
Routine()237 void InteractionHandler::Routine() {
238     std::unique_lock<std::mutex> lk(mLock, std::defer_lock);
239 
240     while (true) {
241         lk.lock();
242         mCond.wait(lk, [&] { return mState != INTERACTION_STATE_IDLE; });
243         if (mState == INTERACTION_STATE_UNINITIALIZED)
244             return;
245         mState = INTERACTION_STATE_WAITING;
246         lk.unlock();
247 
248         WaitForIdle(mWaitMs, mDurationMs);
249         Release();
250     }
251 }
252