Skip to content

Commit

Permalink
wayne: Import Pixel AIDL power HAL impl
Browse files Browse the repository at this point in the history
* From android-13.0.0_r16

Change-Id: I4916e6c4b70da74e059e9ece09d12bdc8010739f
Signed-off-by: xiaoleGun <1592501605@qq.com>
  • Loading branch information
xiaoleGun committed Jan 1, 2023
1 parent 8b384b5 commit eea11e1
Show file tree
Hide file tree
Showing 14 changed files with 2,150 additions and 0 deletions.
26 changes: 26 additions & 0 deletions power-libperfmgr/Android.bp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cc_binary {
name: "android.hardware.power-service.pixel-libperfmgr",
relative_install_path: "hw",
init_rc: ["android.hardware.power-service.pixel-libperfmgr.rc"],
vintf_fragments: ["android.hardware.power-service.pixel.xml"],
vendor: true,
shared_libs: [
"android.hardware.power-V3-ndk",
"libbase",
"libcutils",
"liblog",
"libutils",
"libbinder_ndk",
"libperfmgr",
"libprocessgroup",
"pixel-power-ext-V1-ndk",
],
srcs: [
"service.cpp",
"InteractionHandler.cpp",
"Power.cpp",
"PowerExt.cpp",
"PowerHintSession.cpp",
"PowerSessionManager.cpp",
],
}
283 changes: 283 additions & 0 deletions power-libperfmgr/InteractionHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
/*
* Copyright (C) 2018 The Android 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#define LOG_TAG "powerhal-libperfmgr"
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)

#include "InteractionHandler.h"

#include <android-base/properties.h>
#include <fcntl.h>
#include <perfmgr/HintManager.h>
#include <poll.h>
#include <sys/eventfd.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
#include <utils/Trace.h>

#include <array>
#include <memory>

#define MAX_LENGTH 64

#define MSINSEC 1000L
#define NSINMS 1000000L

namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {

namespace {

static const bool kDisplayIdleSupport =
::android::base::GetBoolProperty("vendor.powerhal.disp.idle_support", true);
static const std::array<const char *, 2> kDispIdlePath = {"/sys/class/drm/card0/device/idle_state",
"/sys/class/graphics/fb0/idle_state"};
static const uint32_t kWaitMs =
::android::base::GetUintProperty("vendor.powerhal.disp.idle_wait", /*default*/ 100U);
static const uint32_t kMinDurationMs =
::android::base::GetUintProperty("vendor.powerhal.interaction.min", /*default*/ 1400U);
static const uint32_t kMaxDurationMs =
::android::base::GetUintProperty("vendor.powerhal.interaction.max", /*default*/ 5650U);
static const uint32_t kDurationOffsetMs =
::android::base::GetUintProperty("vendor.powerhal.interaction.offset", /*default*/ 650U);

static size_t CalcTimespecDiffMs(struct timespec start, struct timespec end) {
size_t diff_in_ms = 0;
diff_in_ms += (end.tv_sec - start.tv_sec) * MSINSEC;
diff_in_ms += (end.tv_nsec - start.tv_nsec) / NSINMS;
return diff_in_ms;
}

static int FbIdleOpen(void) {
int fd;
for (const auto &path : kDispIdlePath) {
fd = open(path, O_RDONLY);
if (fd >= 0)
return fd;
}
ALOGE("Unable to open fb idle state path (%d)", errno);
return -1;
}

} // namespace

using ::android::perfmgr::HintManager;

InteractionHandler::InteractionHandler()
: mState(INTERACTION_STATE_UNINITIALIZED), mDurationMs(0) {}

InteractionHandler::~InteractionHandler() {
Exit();
}

bool InteractionHandler::Init() {
std::lock_guard<std::mutex> lk(mLock);

if (mState != INTERACTION_STATE_UNINITIALIZED)
return true;

int fd = FbIdleOpen();
if (fd < 0)
return false;
mIdleFd = fd;

mEventFd = eventfd(0, EFD_NONBLOCK);
if (mEventFd < 0) {
ALOGE("Unable to create event fd (%d)", errno);
close(mIdleFd);
return false;
}

mState = INTERACTION_STATE_IDLE;
mThread = std::unique_ptr<std::thread>(new std::thread(&InteractionHandler::Routine, this));

return true;
}

void InteractionHandler::Exit() {
std::unique_lock<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_UNINITIALIZED)
return;

AbortWaitLocked();
mState = INTERACTION_STATE_UNINITIALIZED;
lk.unlock();

mCond.notify_all();
mThread->join();

close(mEventFd);
close(mIdleFd);
}

void InteractionHandler::PerfLock() {
ALOGV("%s: acquiring perf lock", __func__);
if (!HintManager::GetInstance()->DoHint("INTERACTION")) {
ALOGE("%s: do hint INTERACTION failed", __func__);
}
}

void InteractionHandler::PerfRel() {
ALOGV("%s: releasing perf lock", __func__);
if (!HintManager::GetInstance()->EndHint("INTERACTION")) {
ALOGE("%s: end hint INTERACTION failed", __func__);
}
}

void InteractionHandler::Acquire(int32_t duration) {
ATRACE_CALL();

std::lock_guard<std::mutex> lk(mLock);

int inputDuration = duration + kDurationOffsetMs;
int finalDuration;
if (inputDuration > kMaxDurationMs)
finalDuration = kMaxDurationMs;
else if (inputDuration > kMinDurationMs)
finalDuration = inputDuration;
else
finalDuration = kMinDurationMs;

// Fallback to do boost directly
// 1) override property is set OR
// 2) InteractionHandler not initialized
if (!kDisplayIdleSupport || mState == INTERACTION_STATE_UNINITIALIZED) {
HintManager::GetInstance()->DoHint("INTERACTION", std::chrono::milliseconds(finalDuration));
return;
}

struct timespec cur_timespec;
clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
size_t elapsed_time = CalcTimespecDiffMs(mLastTimespec, cur_timespec);
// don't hint if previous hint's duration covers this hint's duration
if (elapsed_time <= (mDurationMs - finalDuration)) {
ALOGV("%s: Previous duration (%d) cover this (%d) elapsed: %lld", __func__,
static_cast<int>(mDurationMs), static_cast<int>(finalDuration),
static_cast<long long>(elapsed_time));
return;
}
}
mLastTimespec = cur_timespec;
mDurationMs = finalDuration;

ALOGV("%s: input: %d final duration: %d", __func__, duration, finalDuration);

if (mState == INTERACTION_STATE_WAITING)
AbortWaitLocked();
else if (mState == INTERACTION_STATE_IDLE)
PerfLock();

mState = INTERACTION_STATE_INTERACTION;
mCond.notify_one();
}

void InteractionHandler::Release() {
std::lock_guard<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_WAITING) {
ATRACE_CALL();
PerfRel();
mState = INTERACTION_STATE_IDLE;
} else {
// clear any wait aborts pending in event fd
uint64_t val;
ssize_t ret = read(mEventFd, &val, sizeof(val));

ALOGW_IF(ret < 0, "%s: failed to clear eventfd (%zd, %d)", __func__, ret, errno);
}
}

// should be called while locked
void InteractionHandler::AbortWaitLocked() {
uint64_t val = 1;
ssize_t ret = write(mEventFd, &val, sizeof(val));
if (ret != sizeof(val))
ALOGW("Unable to write to event fd (%zd)", ret);
}

void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) {
char data[MAX_LENGTH];
ssize_t ret;
struct pollfd pfd[2];

ATRACE_CALL();

ALOGV("%s: wait:%d timeout:%d", __func__, wait_ms, timeout_ms);

pfd[0].fd = mEventFd;
pfd[0].events = POLLIN;
pfd[1].fd = mIdleFd;
pfd[1].events = POLLPRI | POLLERR;

ret = poll(pfd, 1, wait_ms);
if (ret > 0) {
ALOGV("%s: wait aborted", __func__);
return;
} else if (ret < 0) {
ALOGE("%s: error in poll while waiting", __func__);
return;
}

ret = pread(mIdleFd, data, sizeof(data), 0);
if (!ret) {
ALOGE("%s: Unexpected EOF!", __func__);
return;
}

if (!strncmp(data, "idle", 4)) {
ALOGV("%s: already idle", __func__);
return;
}

ret = poll(pfd, 2, timeout_ms);
if (ret < 0)
ALOGE("%s: Error on waiting for idle (%zd)", __func__, ret);
else if (ret == 0)
ALOGV("%s: timed out waiting for idle", __func__);
else if (pfd[0].revents)
ALOGV("%s: wait for idle aborted", __func__);
else if (pfd[1].revents)
ALOGV("%s: idle detected", __func__);
}

void InteractionHandler::Routine() {
pthread_setname_np(pthread_self(), "DispIdle");
std::unique_lock<std::mutex> lk(mLock, std::defer_lock);

while (true) {
lk.lock();
mCond.wait(lk, [&] { return mState != INTERACTION_STATE_IDLE; });
if (mState == INTERACTION_STATE_UNINITIALIZED)
return;
mState = INTERACTION_STATE_WAITING;
lk.unlock();

WaitForIdle(kWaitMs, mDurationMs);
Release();
}
}

} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl
71 changes: 71 additions & 0 deletions power-libperfmgr/InteractionHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2018 The Android 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <condition_variable>
#include <memory>
#include <mutex>
#include <string>
#include <thread>

namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {

enum InteractionState {
INTERACTION_STATE_UNINITIALIZED,
INTERACTION_STATE_IDLE,
INTERACTION_STATE_INTERACTION,
INTERACTION_STATE_WAITING,
};

class InteractionHandler {
public:
InteractionHandler();
~InteractionHandler();
bool Init();
void Exit();
void Acquire(int32_t duration);

private:
void Release();
void WaitForIdle(int32_t wait_ms, int32_t timeout_ms);
void AbortWaitLocked();
void Routine();

void PerfLock();
void PerfRel();

enum InteractionState mState;
int mIdleFd;
int mEventFd;
int32_t mDurationMs;
struct timespec mLastTimespec;
std::unique_ptr<std::thread> mThread;
std::mutex mLock;
std::condition_variable mCond;
};

} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl
Loading

0 comments on commit eea11e1

Please sign in to comment.