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