parent
16d83ce2a2
commit
acbc7f58dd
@ -0,0 +1,48 @@ |
||||
// |
||||
// 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. |
||||
|
||||
soong_namespace { |
||||
imports: [ |
||||
"hardware/google/pixel", |
||||
"hardware/google/interfaces", |
||||
], |
||||
} |
||||
|
||||
cc_binary { |
||||
name: "android.hardware.power-service.exynos9810-libperfmgr", |
||||
relative_install_path: "hw", |
||||
init_rc: ["android.hardware.power-service.exynos9810-libperfmgr.rc"], |
||||
vintf_fragments: ["android.hardware.power-service.exynos9810.xml"], |
||||
vendor: true, |
||||
shared_libs: [ |
||||
"android.hardware.power-V2-ndk", |
||||
"libbase", |
||||
"libcutils", |
||||
"liblog", |
||||
"libutils", |
||||
"libbinder_ndk", |
||||
"libperfmgr", |
||||
"libprocessgroup", |
||||
"pixel-power-ext-V1-ndk", |
||||
], |
||||
srcs: [ |
||||
"service.cpp", |
||||
"Power.cpp", |
||||
"PowerExt.cpp", |
||||
"InteractionHandler.cpp", |
||||
"PowerHintSession.cpp", |
||||
"PowerSessionManager.cpp", |
||||
], |
||||
} |
@ -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 <array> |
||||
#include <memory> |
||||
|
||||
#include <fcntl.h> |
||||
#include <poll.h> |
||||
#include <sys/eventfd.h> |
||||
#include <time.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <android-base/properties.h> |
||||
#include <utils/Log.h> |
||||
#include <utils/Trace.h> |
||||
|
||||
#include "InteractionHandler.h" |
||||
|
||||
#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
|
||||
|
||||
InteractionHandler::InteractionHandler(std::shared_ptr<HintManager> const &hint_manager) |
||||
: mState(INTERACTION_STATE_UNINITIALIZED), |
||||
mDurationMs(0), |
||||
mHintManager(hint_manager) {} |
||||
|
||||
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 (!mHintManager->DoHint("INTERACTION")) { |
||||
ALOGE("%s: do hint INTERACTION failed", __func__); |
||||
} |
||||
} |
||||
|
||||
void InteractionHandler::PerfRel() { |
||||
ALOGV("%s: releasing perf lock", __func__); |
||||
if (!mHintManager->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) { |
||||
mHintManager->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
|
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* 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> |
||||
|
||||
#include <perfmgr/HintManager.h> |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
using ::android::perfmgr::HintManager; |
||||
|
||||
enum InteractionState { |
||||
INTERACTION_STATE_UNINITIALIZED, |
||||
INTERACTION_STATE_IDLE, |
||||
INTERACTION_STATE_INTERACTION, |
||||
INTERACTION_STATE_WAITING, |
||||
}; |
||||
|
||||
class InteractionHandler { |
||||
public: |
||||
InteractionHandler(std::shared_ptr<HintManager> const &hint_manager); |
||||
~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; |
||||
std::shared_ptr<HintManager> mHintManager; |
||||
}; |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,296 @@ |
||||
/*
|
||||
* Copyright (C) 2020 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" |
||||
|
||||
#include "Power.h" |
||||
|
||||
#include <mutex> |
||||
|
||||
#include <android-base/file.h> |
||||
#include <android-base/logging.h> |
||||
#include <android-base/properties.h> |
||||
#include <android-base/stringprintf.h> |
||||
#include <android-base/strings.h> |
||||
|
||||
#include <utils/Log.h> |
||||
|
||||
#include "PowerHintSession.h" |
||||
#include "PowerSessionManager.h" |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
using ::aidl::google::hardware::power::impl::pixel::PowerHintSession; |
||||
|
||||
constexpr char kPowerHalStateProp[] = "vendor.powerhal.state"; |
||||
constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio"; |
||||
constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering"; |
||||
constexpr char kPowerHalAdpfRateProp[] = "vendor.powerhal.adpf.rate"; |
||||
constexpr int64_t kPowerHalAdpfRateDefault = -1; |
||||
|
||||
Power::Power(std::shared_ptr<HintManager> hm) |
||||
: mHintManager(hm), |
||||
mInteractionHandler(nullptr), |
||||
mVRModeOn(false), |
||||
mSustainedPerfModeOn(false), |
||||
mAdpfRateNs( |
||||
::android::base::GetIntProperty(kPowerHalAdpfRateProp, kPowerHalAdpfRateDefault)) { |
||||
mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager); |
||||
mInteractionHandler->Init(); |
||||
|
||||
std::string state = ::android::base::GetProperty(kPowerHalStateProp, ""); |
||||
if (state == "SUSTAINED_PERFORMANCE") { |
||||
LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE on"; |
||||
mHintManager->DoHint("SUSTAINED_PERFORMANCE"); |
||||
mSustainedPerfModeOn = true; |
||||
} else if (state == "VR") { |
||||
LOG(INFO) << "Initialize with VR on"; |
||||
mHintManager->DoHint(state); |
||||
mVRModeOn = true; |
||||
} else if (state == "VR_SUSTAINED_PERFORMANCE") { |
||||
LOG(INFO) << "Initialize with SUSTAINED_PERFORMANCE and VR on"; |
||||
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE"); |
||||
mSustainedPerfModeOn = true; |
||||
mVRModeOn = true; |
||||
} else { |
||||
LOG(INFO) << "Initialize PowerHAL"; |
||||
} |
||||
|
||||
state = ::android::base::GetProperty(kPowerHalAudioProp, ""); |
||||
if (state == "AUDIO_STREAMING_LOW_LATENCY") { |
||||
LOG(INFO) << "Initialize with AUDIO_LOW_LATENCY on"; |
||||
mHintManager->DoHint(state); |
||||
} |
||||
|
||||
state = ::android::base::GetProperty(kPowerHalRenderingProp, ""); |
||||
if (state == "EXPENSIVE_RENDERING") { |
||||
LOG(INFO) << "Initialize with EXPENSIVE_RENDERING on"; |
||||
mHintManager->DoHint("EXPENSIVE_RENDERING"); |
||||
} |
||||
|
||||
// Now start to take powerhint
|
||||
LOG(INFO) << "PowerHAL ready to take hints, Adpf update rate: " << mAdpfRateNs; |
||||
} |
||||
|
||||
ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) { |
||||
LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled; |
||||
PowerSessionManager::getInstance()->updateHintMode(toString(type), enabled); |
||||
switch (type) { |
||||
case Mode::LOW_POWER: |
||||
if (enabled) { |
||||
mHintManager->DoHint(toString(type)); |
||||
} else { |
||||
mHintManager->EndHint(toString(type)); |
||||
} |
||||
break; |
||||
case Mode::SUSTAINED_PERFORMANCE: |
||||
if (enabled && !mSustainedPerfModeOn) { |
||||
if (!mVRModeOn) { // Sustained mode only.
|
||||
mHintManager->DoHint("SUSTAINED_PERFORMANCE"); |
||||
} else { // Sustained + VR mode.
|
||||
mHintManager->EndHint("VR"); |
||||
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE"); |
||||
} |
||||
mSustainedPerfModeOn = true; |
||||
} else if (!enabled && mSustainedPerfModeOn) { |
||||
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE"); |
||||
mHintManager->EndHint("SUSTAINED_PERFORMANCE"); |
||||
if (mVRModeOn) { // Switch back to VR Mode.
|
||||
mHintManager->DoHint("VR"); |
||||
} |
||||
mSustainedPerfModeOn = false; |
||||
} |
||||
break; |
||||
case Mode::VR: |
||||
if (enabled && !mVRModeOn) { |
||||
if (!mSustainedPerfModeOn) { // VR mode only.
|
||||
mHintManager->DoHint("VR"); |
||||
} else { // Sustained + VR mode.
|
||||
mHintManager->EndHint("SUSTAINED_PERFORMANCE"); |
||||
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE"); |
||||
} |
||||
mVRModeOn = true; |
||||
} else if (!enabled && mVRModeOn) { |
||||
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE"); |
||||
mHintManager->EndHint("VR"); |
||||
if (mSustainedPerfModeOn) { // Switch back to sustained Mode.
|
||||
mHintManager->DoHint("SUSTAINED_PERFORMANCE"); |
||||
} |
||||
mVRModeOn = false; |
||||
} |
||||
break; |
||||
case Mode::LAUNCH: |
||||
if (mVRModeOn || mSustainedPerfModeOn) { |
||||
break; |
||||
} |
||||
[[fallthrough]]; |
||||
case Mode::DOUBLE_TAP_TO_WAKE: |
||||
[[fallthrough]]; |
||||
case Mode::FIXED_PERFORMANCE: |
||||
[[fallthrough]]; |
||||
case Mode::EXPENSIVE_RENDERING: |
||||
[[fallthrough]]; |
||||
case Mode::INTERACTIVE: |
||||
[[fallthrough]]; |
||||
case Mode::DEVICE_IDLE: |
||||
[[fallthrough]]; |
||||
case Mode::DISPLAY_INACTIVE: |
||||
[[fallthrough]]; |
||||
case Mode::AUDIO_STREAMING_LOW_LATENCY: |
||||
[[fallthrough]]; |
||||
case Mode::CAMERA_STREAMING_SECURE: |
||||
[[fallthrough]]; |
||||
case Mode::CAMERA_STREAMING_LOW: |
||||
[[fallthrough]]; |
||||
case Mode::CAMERA_STREAMING_MID: |
||||
[[fallthrough]]; |
||||
case Mode::CAMERA_STREAMING_HIGH: |
||||
[[fallthrough]]; |
||||
default: |
||||
if (enabled) { |
||||
mHintManager->DoHint(toString(type)); |
||||
} else { |
||||
mHintManager->EndHint(toString(type)); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus Power::isModeSupported(Mode type, bool *_aidl_return) { |
||||
bool supported = mHintManager->IsHintSupported(toString(type)); |
||||
switch (type) { |
||||
case Mode::LOW_POWER: // LOW_POWER handled insides PowerHAL specifically
|
||||
supported = true; |
||||
break; |
||||
case Mode::DOUBLE_TAP_TO_WAKE: |
||||
supported = true; |
||||
break; |
||||
case Mode::INTERACTIVE: |
||||
supported = true; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
LOG(INFO) << "Power mode " << toString(type) << " isModeSupported: " << supported; |
||||
*_aidl_return = supported; |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) { |
||||
LOG(DEBUG) << "Power setBoost: " << toString(type) << " duration: " << durationMs; |
||||
switch (type) { |
||||
case Boost::INTERACTION: |
||||
if (mVRModeOn || mSustainedPerfModeOn) { |
||||
break; |
||||
} |
||||
mInteractionHandler->Acquire(durationMs); |
||||
break; |
||||
case Boost::DISPLAY_UPDATE_IMMINENT: |
||||
[[fallthrough]]; |
||||
case Boost::ML_ACC: |
||||
[[fallthrough]]; |
||||
case Boost::AUDIO_LAUNCH: |
||||
[[fallthrough]]; |
||||
case Boost::CAMERA_LAUNCH: |
||||
[[fallthrough]]; |
||||
case Boost::CAMERA_SHOT: |
||||
[[fallthrough]]; |
||||
default: |
||||
if (mVRModeOn || mSustainedPerfModeOn) { |
||||
break; |
||||
} |
||||
if (durationMs > 0) { |
||||
mHintManager->DoHint(toString(type), std::chrono::milliseconds(durationMs)); |
||||
} else if (durationMs == 0) { |
||||
mHintManager->DoHint(toString(type)); |
||||
} else { |
||||
mHintManager->EndHint(toString(type)); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool *_aidl_return) { |
||||
bool supported = mHintManager->IsHintSupported(toString(type)); |
||||
LOG(INFO) << "Power boost " << toString(type) << " isBoostSupported: " << supported; |
||||
*_aidl_return = supported; |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
constexpr const char *boolToString(bool b) { |
||||
return b ? "true" : "false"; |
||||
} |
||||
|
||||
binder_status_t Power::dump(int fd, const char **, uint32_t) { |
||||
std::string buf(::android::base::StringPrintf( |
||||
"HintManager Running: %s\n" |
||||
"VRMode: %s\n" |
||||
"SustainedPerformanceMode: %s\n", |
||||
boolToString(mHintManager->IsRunning()), boolToString(mVRModeOn), |
||||
boolToString(mSustainedPerfModeOn))); |
||||
// Dump nodes through libperfmgr
|
||||
mHintManager->DumpToFd(fd); |
||||
if (!::android::base::WriteStringToFd(buf, fd)) { |
||||
PLOG(ERROR) << "Failed to dump state to fd"; |
||||
} |
||||
fsync(fd); |
||||
return STATUS_OK; |
||||
} |
||||
|
||||
ndk::ScopedAStatus Power::createHintSession(int32_t tgid, int32_t uid, |
||||
const std::vector<int32_t> &threadIds, |
||||
int64_t durationNanos, |
||||
std::shared_ptr<IPowerHintSession> *_aidl_return) { |
||||
if (mAdpfRateNs <= 0) { |
||||
*_aidl_return = nullptr; |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); |
||||
} |
||||
if (threadIds.size() == 0) { |
||||
LOG(ERROR) << "Error: threadIds.size() shouldn't be " << threadIds.size(); |
||||
*_aidl_return = nullptr; |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); |
||||
} |
||||
std::shared_ptr<IPowerHintSession> session = ndk::SharedRefBase::make<PowerHintSession>( |
||||
tgid, uid, threadIds, durationNanos, nanoseconds(mAdpfRateNs)); |
||||
*_aidl_return = session; |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t *outNanoseconds) { |
||||
*outNanoseconds = mAdpfRateNs; |
||||
if (mAdpfRateNs <= 0) { |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); |
||||
} |
||||
|
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,67 @@ |
||||
/*
|
||||
* Copyright (C) 2020 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 <atomic> |
||||
#include <memory> |
||||
#include <thread> |
||||
|
||||
#include <aidl/android/hardware/power/BnPower.h> |
||||
#include <perfmgr/HintManager.h> |
||||
|
||||
#include "InteractionHandler.h" |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
using ::aidl::android::hardware::power::Boost; |
||||
using ::aidl::android::hardware::power::IPowerHintSession; |
||||
using ::aidl::android::hardware::power::Mode; |
||||
using ::android::perfmgr::HintManager; |
||||
|
||||
class Power : public ::aidl::android::hardware::power::BnPower { |
||||
public: |
||||
Power(std::shared_ptr<HintManager> hm); |
||||
ndk::ScopedAStatus setMode(Mode type, bool enabled) override; |
||||
ndk::ScopedAStatus isModeSupported(Mode type, bool *_aidl_return) override; |
||||
ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override; |
||||
ndk::ScopedAStatus isBoostSupported(Boost type, bool *_aidl_return) override; |
||||
ndk::ScopedAStatus createHintSession(int32_t tgid, int32_t uid, |
||||
const std::vector<int32_t> &threadIds, |
||||
int64_t durationNanos, |
||||
std::shared_ptr<IPowerHintSession> *_aidl_return) override; |
||||
ndk::ScopedAStatus getHintSessionPreferredRate(int64_t *outNanoseconds) override; |
||||
binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; |
||||
|
||||
private: |
||||
std::shared_ptr<HintManager> mHintManager; |
||||
std::unique_ptr<InteractionHandler> mInteractionHandler; |
||||
std::atomic<bool> mVRModeOn; |
||||
std::atomic<bool> mSustainedPerfModeOn; |
||||
const int64_t mAdpfRateNs; |
||||
}; |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,85 @@ |
||||
/*
|
||||
* Copyright (C) 2020 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 "android.hardware.power-service.exynos9810.ext-libperfmgr" |
||||
|
||||
#include "PowerExt.h" |
||||
#include "PowerSessionManager.h" |
||||
|
||||
#include <mutex> |
||||
|
||||
#include <android-base/file.h> |
||||
#include <android-base/logging.h> |
||||
#include <android-base/properties.h> |
||||
#include <android-base/stringprintf.h> |
||||
#include <android-base/strings.h> |
||||
|
||||
#include <utils/Log.h> |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
ndk::ScopedAStatus PowerExt::setMode(const std::string &mode, bool enabled) { |
||||
LOG(DEBUG) << "PowerExt setMode: " << mode << " to: " << enabled; |
||||
|
||||
if (enabled) { |
||||
mHintManager->DoHint(mode); |
||||
} else { |
||||
mHintManager->EndHint(mode); |
||||
} |
||||
PowerSessionManager::getInstance()->updateHintMode(mode, enabled); |
||||
|
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerExt::isModeSupported(const std::string &mode, bool *_aidl_return) { |
||||
bool supported = mHintManager->IsHintSupported(mode); |
||||
LOG(INFO) << "PowerExt mode " << mode << " isModeSupported: " << supported; |
||||
*_aidl_return = supported; |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerExt::setBoost(const std::string &boost, int32_t durationMs) { |
||||
LOG(DEBUG) << "PowerExt setBoost: " << boost << " duration: " << durationMs; |
||||
|
||||
if (durationMs > 0) { |
||||
mHintManager->DoHint(boost, std::chrono::milliseconds(durationMs)); |
||||
} else if (durationMs == 0) { |
||||
mHintManager->DoHint(boost); |
||||
} else { |
||||
mHintManager->EndHint(boost); |
||||
} |
||||
|
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerExt::isBoostSupported(const std::string &boost, bool *_aidl_return) { |
||||
bool supported = mHintManager->IsHintSupported(boost); |
||||
LOG(INFO) << "PowerExt boost " << boost << " isBoostSupported: " << supported; |
||||
*_aidl_return = supported; |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,53 @@ |
||||
/*
|
||||
* Copyright (C) 2020 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 <atomic> |
||||
#include <memory> |
||||
#include <thread> |
||||
|
||||
#include <aidl/google/hardware/power/extension/pixel/BnPowerExt.h> |
||||
#include <perfmgr/HintManager.h> |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
using ::android::perfmgr::HintManager; |
||||
|
||||
class PowerExt : public ::aidl::google::hardware::power::extension::pixel::BnPowerExt { |
||||
public: |
||||
PowerExt(std::shared_ptr<HintManager> hm) |
||||
: mHintManager(hm) {} |
||||
ndk::ScopedAStatus setMode(const std::string &mode, bool enabled) override; |
||||
ndk::ScopedAStatus isModeSupported(const std::string &mode, bool *_aidl_return) override; |
||||
ndk::ScopedAStatus setBoost(const std::string &boost, int32_t durationMs) override; |
||||
ndk::ScopedAStatus isBoostSupported(const std::string &boost, bool *_aidl_return) override; |
||||
|
||||
private: |
||||
std::shared_ptr<HintManager> mHintManager; |
||||
}; |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,481 @@ |
||||
/*
|
||||
* Copyright 2021 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 <android-base/logging.h> |
||||
#include <android-base/parsedouble.h> |
||||
#include <android-base/properties.h> |
||||
#include <android-base/stringprintf.h> |
||||
#include <sys/syscall.h> |
||||
#include <time.h> |
||||
#include <utils/Trace.h> |
||||
#include <atomic> |
||||
|
||||
#include "PowerHintSession.h" |
||||
#include "PowerSessionManager.h" |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
using ::android::base::StringPrintf; |
||||
using std::chrono::duration_cast; |
||||
using std::chrono::nanoseconds; |
||||
using std::literals::chrono_literals::operator""s; |
||||
|
||||
constexpr char kPowerHalAdpfPidPOver[] = "vendor.powerhal.adpf.pid_p.over"; |
||||
constexpr char kPowerHalAdpfPidPUnder[] = "vendor.powerhal.adpf.pid_p.under"; |
||||
constexpr char kPowerHalAdpfPidI[] = "vendor.powerhal.adpf.pid_i"; |
||||
constexpr char kPowerHalAdpfPidDOver[] = "vendor.powerhal.adpf.pid_d.over"; |
||||
constexpr char kPowerHalAdpfPidDUnder[] = "vendor.powerhal.adpf.pid_d.under"; |
||||
constexpr char kPowerHalAdpfPidIInit[] = "vendor.powerhal.adpf.pid_i.init"; |
||||
constexpr char kPowerHalAdpfPidIHighLimit[] = "vendor.powerhal.adpf.pid_i.high_limit"; |
||||
constexpr char kPowerHalAdpfPidILowLimit[] = "vendor.powerhal.adpf.pid_i.low_limit"; |
||||
constexpr char kPowerHalAdpfUclampEnable[] = "vendor.powerhal.adpf.uclamp"; |
||||
constexpr char kPowerHalAdpfUclampMinGranularity[] = "vendor.powerhal.adpf.uclamp_min.granularity"; |
||||
constexpr char kPowerHalAdpfUclampMinHighLimit[] = "vendor.powerhal.adpf.uclamp_min.high_limit"; |
||||
constexpr char kPowerHalAdpfUclampMinLowLimit[] = "vendor.powerhal.adpf.uclamp_min.low_limit"; |
||||
constexpr char kPowerHalAdpfStaleTimeFactor[] = "vendor.powerhal.adpf.stale_timeout_factor"; |
||||
constexpr char kPowerHalAdpfPSamplingWindow[] = "vendor.powerhal.adpf.p.window"; |
||||
constexpr char kPowerHalAdpfISamplingWindow[] = "vendor.powerhal.adpf.i.window"; |
||||
constexpr char kPowerHalAdpfDSamplingWindow[] = "vendor.powerhal.adpf.d.window"; |
||||
|
||||
namespace { |
||||
/* there is no glibc or bionic wrapper */ |
||||
struct sched_attr { |
||||
__u32 size; |
||||
__u32 sched_policy; |
||||
__u64 sched_flags; |
||||
__s32 sched_nice; |
||||
__u32 sched_priority; |
||||
__u64 sched_runtime; |
||||
__u64 sched_deadline; |
||||
__u64 sched_period; |
||||
__u32 sched_util_min; |
||||
__u32 sched_util_max; |
||||
}; |
||||
|
||||
static int sched_setattr(int pid, struct sched_attr *attr, unsigned int flags) { |
||||
static const bool kPowerHalAdpfUclamp = |
||||
::android::base::GetBoolProperty(kPowerHalAdpfUclampEnable, true); |
||||
if (!kPowerHalAdpfUclamp) { |
||||
ALOGV("PowerHintSession:%s: skip", __func__); |
||||
return 0; |
||||
} |
||||
return syscall(__NR_sched_setattr, pid, attr, flags); |
||||
} |
||||
|
||||
static inline int64_t ns_to_100us(int64_t ns) { |
||||
return ns / 100000; |
||||
} |
||||
|
||||
static double getDoubleProperty(const char *prop, double value) { |
||||
std::string result = ::android::base::GetProperty(prop, std::to_string(value).c_str()); |
||||
if (!::android::base::ParseDouble(result.c_str(), &value)) { |
||||
ALOGE("PowerHintSession : failed to parse double in %s", prop); |
||||
} |
||||
return value; |
||||
} |
||||
|
||||
static double sPidPOver = getDoubleProperty(kPowerHalAdpfPidPOver, 2.0); |
||||
static double sPidPUnder = getDoubleProperty(kPowerHalAdpfPidPUnder, 1.0); |
||||
static double sPidI = getDoubleProperty(kPowerHalAdpfPidI, 0.001); |
||||
static double sPidDOver = getDoubleProperty(kPowerHalAdpfPidDOver, 500.0); |
||||
static double sPidDUnder = getDoubleProperty(kPowerHalAdpfPidDUnder, 0.0); |
||||
static const int64_t sPidIInit = |
||||
(sPidI == 0) ? 0 |
||||
: static_cast<int64_t>(::android::base::GetIntProperty<int64_t>( |
||||
kPowerHalAdpfPidIInit, 200) / |
||||
sPidI); |
||||
static const int64_t sPidIHighLimit = |
||||
(sPidI == 0) ? 0 |
||||
: static_cast<int64_t>(::android::base::GetIntProperty<int64_t>( |
||||
kPowerHalAdpfPidIHighLimit, 512) / |
||||
sPidI); |
||||
static const int64_t sPidILowLimit = |
||||
(sPidI == 0) ? 0 |
||||
: static_cast<int64_t>(::android::base::GetIntProperty<int64_t>( |
||||
kPowerHalAdpfPidILowLimit, -30) / |
||||
sPidI); |
||||
static const int32_t sUclampMinHighLimit = |
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfUclampMinHighLimit, 384); |
||||
static const int32_t sUclampMinLowLimit = |
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfUclampMinLowLimit, 2); |
||||
static const uint32_t sUclampMinGranularity = |
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfUclampMinGranularity, 5); |
||||
static const int64_t sStaleTimeFactor = |
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfStaleTimeFactor, 20); |
||||
static const int64_t sPSamplingWindow = |
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfPSamplingWindow, 1); |
||||
static const int64_t sISamplingWindow = |
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfISamplingWindow, 0); |
||||
static const int64_t sDSamplingWindow = |
||||
::android::base::GetUintProperty<uint32_t>(kPowerHalAdpfDSamplingWindow, 1); |
||||
|
||||
} // namespace
|
||||
|
||||
PowerHintSession::PowerHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds, |
||||
int64_t durationNanos, const nanoseconds adpfRate) |
||||
: kAdpfRate(adpfRate) { |
||||
mDescriptor = new AppHintDesc(tgid, uid, threadIds); |
||||
mDescriptor->duration = std::chrono::nanoseconds(durationNanos); |
||||
mStaleHandler = sp<StaleHandler>(new StaleHandler(this)); |
||||
mPowerManagerHandler = PowerSessionManager::getInstance(); |
||||
|
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-target", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); |
||||
sz = StringPrintf("adpf.%s-active", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), mDescriptor->is_active.load()); |
||||
sz = StringPrintf("adpf.%s-stale", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), isStale()); |
||||
} |
||||
PowerSessionManager::getInstance()->addPowerSession(this); |
||||
// init boost
|
||||
setUclamp(sUclampMinHighLimit); |
||||
ALOGV("PowerHintSession created: %s", mDescriptor->toString().c_str()); |
||||
} |
||||
|
||||
PowerHintSession::~PowerHintSession() { |
||||
close(); |
||||
ALOGV("PowerHintSession deleted: %s", mDescriptor->toString().c_str()); |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-target", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), 0); |
||||
sz = StringPrintf("adpf.%s-actl_last", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), 0); |
||||
sz = sz = StringPrintf("adpf.%s-active", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), 0); |
||||
} |
||||
delete mDescriptor; |
||||
} |
||||
|
||||
std::string PowerHintSession::getIdString() const { |
||||
std::string idstr = StringPrintf("%" PRId32 "-%" PRId32 "-%" PRIxPTR, mDescriptor->tgid, |
||||
mDescriptor->uid, reinterpret_cast<uintptr_t>(this) & 0xffff); |
||||
return idstr; |
||||
} |
||||
|
||||
void PowerHintSession::updateUniveralBoostMode() { |
||||
PowerHintMonitor::getInstance()->getLooper()->sendMessage(mPowerManagerHandler, NULL); |
||||
} |
||||
|
||||
int PowerHintSession::setUclamp(int32_t min, int32_t max) { |
||||
std::lock_guard<std::mutex> guard(mLock); |
||||
min = std::max(0, min); |
||||
min = std::min(min, max); |
||||
max = std::max(0, max); |
||||
max = std::max(min, max); |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-min", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), min); |
||||
} |
||||
for (const auto tid : mDescriptor->threadIds) { |
||||
sched_attr attr = {}; |
||||
attr.size = sizeof(attr); |
||||
|
||||
attr.sched_flags = (SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP); |
||||
attr.sched_util_min = min; |
||||
attr.sched_util_max = max; |
||||
|
||||
int ret = sched_setattr(tid, &attr, 0); |
||||
if (ret) { |
||||
ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno); |
||||
} |
||||
ALOGV("PowerHintSession tid: %d, uclamp(%d, %d)", tid, min, max); |
||||
} |
||||
mDescriptor->current_min = min; |
||||
return 0; |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerHintSession::pause() { |
||||
if (!mDescriptor->is_active.load()) |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
||||
// Reset to default uclamp value.
|
||||
setUclamp(0); |
||||
mDescriptor->is_active.store(false); |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-active", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), mDescriptor->is_active.load()); |
||||
} |
||||
updateUniveralBoostMode(); |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerHintSession::resume() { |
||||
if (mDescriptor->is_active.load()) |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
||||
mDescriptor->is_active.store(true); |
||||
mDescriptor->integral_error = std::max(sPidIInit, mDescriptor->integral_error); |
||||
// resume boost
|
||||
setUclamp(sUclampMinHighLimit); |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-active", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), mDescriptor->is_active.load()); |
||||
} |
||||
updateUniveralBoostMode(); |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerHintSession::close() { |
||||
bool sessionClosedExpectedToBe = false; |
||||
if (!mSessionClosed.compare_exchange_strong(sessionClosedExpectedToBe, true)) { |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
||||
} |
||||
PowerHintMonitor::getInstance()->getLooper()->removeMessages(mStaleHandler); |
||||
setUclamp(0); |
||||
PowerSessionManager::getInstance()->removePowerSession(this); |
||||
updateUniveralBoostMode(); |
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) { |
||||
if (targetDurationNanos <= 0) { |
||||
ALOGE("Error: targetDurationNanos(%" PRId64 ") should bigger than 0", targetDurationNanos); |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); |
||||
} |
||||
ALOGV("update target duration: %" PRId64 " ns", targetDurationNanos); |
||||
double ratio = |
||||
targetDurationNanos == 0 ? 1.0 : mDescriptor->duration.count() / targetDurationNanos; |
||||
mDescriptor->integral_error = |
||||
std::max(sPidIInit, static_cast<int64_t>(mDescriptor->integral_error * ratio)); |
||||
|
||||
mDescriptor->duration = std::chrono::nanoseconds(targetDurationNanos); |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-target", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); |
||||
} |
||||
|
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
ndk::ScopedAStatus PowerHintSession::reportActualWorkDuration( |
||||
const std::vector<WorkDuration> &actualDurations) { |
||||
if (mDescriptor->duration.count() == 0LL) { |
||||
ALOGE("Expect to call updateTargetWorkDuration() first."); |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
||||
} |
||||
if (actualDurations.size() == 0) { |
||||
ALOGE("Error: duration.size() shouldn't be %zu.", actualDurations.size()); |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); |
||||
} |
||||
if (!mDescriptor->is_active.load()) { |
||||
ALOGE("Error: shouldn't report duration during pause state."); |
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
||||
} |
||||
if (PowerHintMonitor::getInstance()->isRunning() && isStale()) { |
||||
mDescriptor->integral_error = std::max(sPidIInit, mDescriptor->integral_error); |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-wakeup", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), mDescriptor->integral_error); |
||||
ATRACE_INT(sz.c_str(), 0); |
||||
} |
||||
} |
||||
int64_t targetDurationNanos = (int64_t)mDescriptor->duration.count(); |
||||
int64_t length = actualDurations.size(); |
||||
int64_t p_start = |
||||
sPSamplingWindow == 0 || sPSamplingWindow > length ? 0 : length - sPSamplingWindow; |
||||
int64_t i_start = |
||||
sISamplingWindow == 0 || sISamplingWindow > length ? 0 : length - sISamplingWindow; |
||||
int64_t d_start = |
||||
sDSamplingWindow == 0 || sDSamplingWindow > length ? 0 : length - sDSamplingWindow; |
||||
int64_t dt = ns_to_100us(targetDurationNanos); |
||||
int64_t err_sum = 0; |
||||
int64_t derivative_sum = 0; |
||||
for (int64_t i = std::min({p_start, i_start, d_start}); i < length; i++) { |
||||
int64_t actualDurationNanos = actualDurations[i].durationNanos; |
||||
if (std::abs(actualDurationNanos) > targetDurationNanos * 20) { |
||||
ALOGW("The actual duration is way far from the target (%" PRId64 " >> %" PRId64 ")", |
||||
actualDurationNanos, targetDurationNanos); |
||||
} |
||||
// PID control algorithm
|
||||
int64_t error = ns_to_100us(actualDurationNanos - targetDurationNanos); |
||||
if (i >= d_start) { |
||||
derivative_sum += error - mDescriptor->previous_error; |
||||
} |
||||
if (i >= p_start) { |
||||
err_sum += error; |
||||
} |
||||
if (i >= i_start) { |
||||
mDescriptor->integral_error = mDescriptor->integral_error + error * dt; |
||||
mDescriptor->integral_error = std::min(sPidIHighLimit, mDescriptor->integral_error); |
||||
mDescriptor->integral_error = std::max(sPidILowLimit, mDescriptor->integral_error); |
||||
} |
||||
mDescriptor->previous_error = error; |
||||
} |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-err", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), err_sum / (length - p_start)); |
||||
sz = StringPrintf("adpf.%s-integral", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), mDescriptor->integral_error); |
||||
sz = StringPrintf("adpf.%s-derivative", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), derivative_sum / dt / (length - d_start)); |
||||
} |
||||
int64_t pOut = static_cast<int64_t>((err_sum > 0 ? sPidPOver : sPidPUnder) * err_sum / |
||||
(length - p_start)); |
||||
int64_t iOut = static_cast<int64_t>(sPidI * mDescriptor->integral_error); |
||||
int64_t dOut = static_cast<int64_t>((derivative_sum > 0 ? sPidDOver : sPidDUnder) * |
||||
derivative_sum / dt / (length - d_start)); |
||||
|
||||
int64_t output = pOut + iOut + dOut; |
||||
|
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-actl_last", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), actualDurations[length - 1].durationNanos); |
||||
sz = StringPrintf("adpf.%s-target", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), (int64_t)mDescriptor->duration.count()); |
||||
sz = StringPrintf("adpf.%s-sample_size", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), length); |
||||
sz = StringPrintf("adpf.%s-pid.count", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), mDescriptor->update_count); |
||||
sz = StringPrintf("adpf.%s-pid.pOut", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), pOut); |
||||
sz = StringPrintf("adpf.%s-pid.iOut", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), iOut); |
||||
sz = StringPrintf("adpf.%s-pid.dOut", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), dOut); |
||||
sz = StringPrintf("adpf.%s-pid.output", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), output); |
||||
sz = StringPrintf("adpf.%s-stale", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), isStale()); |
||||
sz = StringPrintf("adpf.%s-pid.overtime", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), err_sum > 0); |
||||
} |
||||
mDescriptor->update_count++; |
||||
|
||||
mStaleHandler->updateStaleTimer(); |
||||
|
||||
/* apply to all the threads in the group */ |
||||
if (output != 0) { |
||||
int next_min = std::min(sUclampMinHighLimit, static_cast<int>(output)); |
||||
next_min = std::max(sUclampMinLowLimit, next_min); |
||||
if (std::abs(mDescriptor->current_min - next_min) > sUclampMinGranularity) { |
||||
setUclamp(next_min); |
||||
} |
||||
} |
||||
|
||||
return ndk::ScopedAStatus::ok(); |
||||
} |
||||
|
||||
std::string AppHintDesc::toString() const { |
||||
std::string out = |
||||
StringPrintf("session %" PRIxPTR "\n", reinterpret_cast<uintptr_t>(this) & 0xffff); |
||||
const int64_t durationNanos = duration.count(); |
||||
out.append(StringPrintf(" duration: %" PRId64 " ns\n", durationNanos)); |
||||
out.append(StringPrintf(" uclamp.min: %d \n", current_min)); |
||||
out.append(StringPrintf(" uid: %d, tgid: %d\n", uid, tgid)); |
||||
|
||||
out.append(" threadIds: ["); |
||||
bool first = true; |
||||
for (int tid : threadIds) { |
||||
if (!first) { |
||||
out.append(", "); |
||||
} |
||||
out.append(std::to_string(tid)); |
||||
first = false; |
||||
} |
||||
out.append("]\n"); |
||||
return out; |
||||
} |
||||
|
||||
bool PowerHintSession::isActive() { |
||||
return mDescriptor->is_active.load(); |
||||
} |
||||
|
||||
bool PowerHintSession::isStale() { |
||||
auto now = std::chrono::steady_clock::now(); |
||||
return now >= mStaleHandler->getStaleTime(); |
||||
} |
||||
|
||||
const std::vector<int> &PowerHintSession::getTidList() const { |
||||
return mDescriptor->threadIds; |
||||
} |
||||
|
||||
void PowerHintSession::setStale() { |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-stale", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), 1); |
||||
} |
||||
// Reset to default uclamp value.
|
||||
setUclamp(0); |
||||
// Deliver a task to check if all sessions are inactive.
|
||||
updateUniveralBoostMode(); |
||||
} |
||||
|
||||
void PowerHintSession::StaleHandler::updateStaleTimer() { |
||||
std::lock_guard<std::mutex> guard(mStaleLock); |
||||
if (PowerHintMonitor::getInstance()->isRunning()) { |
||||
auto when = getStaleTime(); |
||||
auto now = std::chrono::steady_clock::now(); |
||||
mLastUpdatedTime.store(now); |
||||
if (now > when) { |
||||
mSession->updateUniveralBoostMode(); |
||||
} |
||||
if (!mIsMonitoringStale.load()) { |
||||
auto next = getStaleTime(); |
||||
PowerHintMonitor::getInstance()->getLooper()->sendMessageDelayed( |
||||
duration_cast<nanoseconds>(next - now).count(), this, NULL); |
||||
mIsMonitoringStale.store(true); |
||||
} |
||||
if (ATRACE_ENABLED()) { |
||||
const std::string idstr = mSession->getIdString(); |
||||
std::string sz = StringPrintf("adpf.%s-stale", idstr.c_str()); |
||||
ATRACE_INT(sz.c_str(), 0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
time_point<steady_clock> PowerHintSession::StaleHandler::getStaleTime() { |
||||
return mLastUpdatedTime.load() + |
||||
std::chrono::duration_cast<milliseconds>(mSession->kAdpfRate) * sStaleTimeFactor; |
||||
} |
||||
|
||||
void PowerHintSession::StaleHandler::handleMessage(const Message &) { |
||||
std::lock_guard<std::mutex> guard(mStaleLock); |
||||
auto now = std::chrono::steady_clock::now(); |
||||
auto when = getStaleTime(); |
||||
// Check if the session is stale based on the last_updated_time.
|
||||
if (now > when) { |
||||
mSession->setStale(); |
||||
mIsMonitoringStale.store(false); |
||||
return; |
||||
} |
||||
// Schedule for the next checking time.
|
||||
PowerHintMonitor::getInstance()->getLooper()->sendMessageDelayed( |
||||
duration_cast<nanoseconds>(when - now).count(), this, NULL); |
||||
} |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,119 @@ |
||||
/*
|
||||
* Copyright 2021 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 <aidl/android/hardware/power/BnPowerHintSession.h> |
||||
#include <aidl/android/hardware/power/WorkDuration.h> |
||||
#include <utils/Looper.h> |
||||
#include <utils/Thread.h> |
||||
|
||||
#include <mutex> |
||||
#include <unordered_map> |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
using aidl::android::hardware::power::BnPowerHintSession; |
||||
using aidl::android::hardware::power::WorkDuration; |
||||
using ::android::Message; |
||||
using ::android::MessageHandler; |
||||
using ::android::sp; |
||||
using std::chrono::milliseconds; |
||||
using std::chrono::nanoseconds; |
||||
using std::chrono::steady_clock; |
||||
using std::chrono::time_point; |
||||
|
||||
static const int32_t kMaxUclampValue = 1024; |
||||
struct AppHintDesc { |
||||
AppHintDesc(int32_t tgid, int32_t uid, std::vector<int> threadIds) |
||||
: tgid(tgid), |
||||
uid(uid), |
||||
threadIds(std::move(threadIds)), |
||||
duration(0LL), |
||||
current_min(0), |
||||
is_active(true), |
||||
update_count(0), |
||||
integral_error(0), |
||||
previous_error(0) {} |
||||
std::string toString() const; |
||||
const int32_t tgid; |
||||
const int32_t uid; |
||||
const std::vector<int> threadIds; |
||||
nanoseconds duration; |
||||
int current_min; |
||||
// status
|
||||
std::atomic<bool> is_active; |
||||
// pid
|
||||
uint64_t update_count; |
||||
int64_t integral_error; |
||||
int64_t previous_error; |
||||
}; |
||||
|
||||
class PowerHintSession : public BnPowerHintSession { |
||||
public: |
||||
explicit PowerHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t> &threadIds, |
||||
int64_t durationNanos, nanoseconds adpfRate); |
||||
~PowerHintSession(); |
||||
ndk::ScopedAStatus close() override; |
||||
ndk::ScopedAStatus pause() override; |
||||
ndk::ScopedAStatus resume() override; |
||||
ndk::ScopedAStatus updateTargetWorkDuration(int64_t targetDurationNanos) override; |
||||
ndk::ScopedAStatus reportActualWorkDuration( |
||||
const std::vector<WorkDuration> &actualDurations) override; |
||||
bool isActive(); |
||||
bool isStale(); |
||||
const std::vector<int> &getTidList() const; |
||||
|
||||
private: |
||||
class StaleHandler : public MessageHandler { |
||||
public: |
||||
StaleHandler(PowerHintSession *session) |
||||
: mSession(session), mIsMonitoringStale(false), mLastUpdatedTime(steady_clock::now()) {} |
||||
void handleMessage(const Message &message) override; |
||||
void updateStaleTimer(); |
||||
time_point<steady_clock> getStaleTime(); |
||||
|
||||
private: |
||||
PowerHintSession *mSession; |
||||
std::atomic<bool> mIsMonitoringStale; |
||||
std::atomic<time_point<steady_clock>> mLastUpdatedTime; |
||||
std::mutex mStaleLock; |
||||
}; |
||||
|
||||
private: |
||||
void setStale(); |
||||
void updateUniveralBoostMode(); |
||||
int setUclamp(int32_t min, int32_t max = kMaxUclampValue); |
||||
std::string getIdString() const; |
||||
AppHintDesc *mDescriptor = nullptr; |
||||
sp<StaleHandler> mStaleHandler; |
||||
sp<MessageHandler> mPowerManagerHandler; |
||||
std::mutex mLock; |
||||
const nanoseconds kAdpfRate; |
||||
std::atomic<bool> mSessionClosed = false; |
||||
}; |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,163 @@ |
||||
/*
|
||||
* Copyright 2021 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 <log/log.h> |
||||
#include <processgroup/processgroup.h> |
||||
#include <utils/Trace.h> |
||||
|
||||
#include "PowerSessionManager.h" |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
void PowerSessionManager::setHintManager(std::shared_ptr<HintManager> const &hint_manager) { |
||||
// Only initialize hintmanager instance if hint is supported.
|
||||
if (hint_manager->IsHintSupported(kDisableBoostHintName)) { |
||||
mHintManager = hint_manager; |
||||
} |
||||
} |
||||
|
||||
void PowerSessionManager::updateHintMode(const std::string &mode, bool enabled) { |
||||
ALOGV("PowerSessionManager::updateHintMode: mode: %s, enabled: %d", mode.c_str(), enabled); |
||||
if (enabled && mode.compare(0, 8, "REFRESH_") == 0) { |
||||
if (mode.compare("REFRESH_120FPS") == 0) { |
||||
mDisplayRefreshRate = 120; |
||||
} else if (mode.compare("REFRESH_90FPS") == 0) { |
||||
mDisplayRefreshRate = 90; |
||||
} else if (mode.compare("REFRESH_60FPS") == 0) { |
||||
mDisplayRefreshRate = 60; |
||||
} |
||||
} |
||||
} |
||||
|
||||
int PowerSessionManager::getDisplayRefreshRate() { |
||||
return mDisplayRefreshRate; |
||||
} |
||||
|
||||
void PowerSessionManager::addPowerSession(PowerHintSession *session) { |
||||
std::lock_guard<std::mutex> guard(mLock); |
||||
for (auto t : session->getTidList()) { |
||||
if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) { |
||||
if (!SetTaskProfiles(t, {"ResetUclampGrp"})) { |
||||
ALOGW("Failed to set ResetUclampGrp task profile for tid:%d", t); |
||||
} else { |
||||
mTidRefCountMap[t] = 1; |
||||
} |
||||
continue; |
||||
} |
||||
if (mTidRefCountMap[t] <= 0) { |
||||
ALOGE("Error! Unexpected zero/negative RefCount:%d for tid:%d", mTidRefCountMap[t], t); |
||||
continue; |
||||
} |
||||
mTidRefCountMap[t]++; |
||||
} |
||||
mSessions.insert(session); |
||||
} |
||||
|
||||
void PowerSessionManager::removePowerSession(PowerHintSession *session) { |
||||
std::lock_guard<std::mutex> guard(mLock); |
||||
for (auto t : session->getTidList()) { |
||||
if (mTidRefCountMap.find(t) == mTidRefCountMap.end()) { |
||||
ALOGE("Unexpected Error! Failed to look up tid:%d in TidRefCountMap", t); |
||||
continue; |
||||
} |
||||
mTidRefCountMap[t]--; |
||||
if (mTidRefCountMap[t] <= 0) { |
||||
if (!SetTaskProfiles(t, {"NoResetUclampGrp"})) { |
||||
ALOGW("Failed to set NoResetUclampGrp task profile for tid:%d", t); |
||||
} |
||||
mTidRefCountMap.erase(t); |
||||
} |
||||
} |
||||
mSessions.erase(session); |
||||
} |
||||
|
||||
std::optional<bool> PowerSessionManager::isAnySessionActive() { |
||||
std::lock_guard<std::mutex> guard(mLock); |
||||
bool active = false; |
||||
for (PowerHintSession *s : mSessions) { |
||||
// session active and not stale is actually active.
|
||||
if (s->isActive() && !s->isStale()) { |
||||
active = true; |
||||
break; |
||||
} |
||||
} |
||||
if (active == mActive) { |
||||
return std::nullopt; |
||||
} else { |
||||
mActive = active; |
||||
} |
||||
|
||||
return active; |
||||
} |
||||
|
||||
void PowerSessionManager::handleMessage(const Message &) { |
||||
auto active = isAnySessionActive(); |
||||
if (!active.has_value()) { |
||||
return; |
||||
} |
||||
if (active.value()) { |
||||
disableSystemTopAppBoost(); |
||||
} else { |
||||
enableSystemTopAppBoost(); |
||||
} |
||||
} |
||||
|
||||
void PowerSessionManager::enableSystemTopAppBoost() { |
||||
if (mHintManager) { |
||||
ALOGV("PowerSessionManager::enableSystemTopAppBoost!!"); |
||||
mHintManager->EndHint(kDisableBoostHintName); |
||||
} |
||||
} |
||||
|
||||
void PowerSessionManager::disableSystemTopAppBoost() { |
||||
if (mHintManager) { |
||||
ALOGV("PowerSessionManager::disableSystemTopAppBoost!!"); |
||||
mHintManager->DoHint(kDisableBoostHintName); |
||||
} |
||||
} |
||||
|
||||
// =========== PowerHintMonitor implementation start from here ===========
|
||||
void PowerHintMonitor::start() { |
||||
if (!isRunning()) { |
||||
run("PowerHintMonitor", ::android::PRIORITY_HIGHEST); |
||||
} |
||||
} |
||||
|
||||
bool PowerHintMonitor::threadLoop() { |
||||
while (true) { |
||||
mLooper->pollOnce(-1); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
sp<Looper> PowerHintMonitor::getLooper() { |
||||
return mLooper; |
||||
} |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,108 @@ |
||||
/*
|
||||
* Copyright 2021 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 "PowerHintSession.h" |
||||
|
||||
#include <android-base/properties.h> |
||||
#include <perfmgr/HintManager.h> |
||||
#include <utils/Looper.h> |
||||
|
||||
#include <mutex> |
||||
#include <optional> |
||||
#include <unordered_set> |
||||
|
||||
namespace aidl { |
||||
namespace google { |
||||
namespace hardware { |
||||
namespace power { |
||||
namespace impl { |
||||
namespace pixel { |
||||
|
||||
using ::android::Looper; |
||||
using ::android::Message; |
||||
using ::android::MessageHandler; |
||||
using ::android::Thread; |
||||
using ::android::perfmgr::HintManager; |
||||
|
||||
constexpr char kPowerHalAdpfDisableTopAppBoost[] = "vendor.powerhal.adpf.disable.hint"; |
||||
|
||||
class PowerSessionManager : public MessageHandler { |
||||
public: |
||||
// current hint info
|
||||
void updateHintMode(const std::string &mode, bool enabled); |
||||
int getDisplayRefreshRate(); |
||||
// monitoring session status
|
||||
void addPowerSession(PowerHintSession *session); |
||||
void removePowerSession(PowerHintSession *session); |
||||
|
||||
void handleMessage(const Message &message) override; |
||||
void setHintManager(std::shared_ptr<HintManager> const &hint_manager); |
||||
|
||||
// Singleton
|
||||
static sp<PowerSessionManager> getInstance() { |
||||
static sp<PowerSessionManager> instance = new PowerSessionManager(); |
||||
return instance; |
||||
} |
||||
|
||||
private: |
||||
std::optional<bool> isAnySessionActive(); |
||||
void disableSystemTopAppBoost(); |
||||
void enableSystemTopAppBoost(); |
||||
const std::string kDisableBoostHintName; |
||||
std::shared_ptr<HintManager> mHintManager; |
||||
std::unordered_set<PowerHintSession *> mSessions; // protected by mLock
|
||||
std::unordered_map<int, int> mTidRefCountMap; // protected by mLock
|
||||
std::mutex mLock; |
||||
int mDisplayRefreshRate; |
||||
bool mActive; // protected by mLock
|
||||
// Singleton
|
||||
PowerSessionManager() |
||||
: kDisableBoostHintName(::android::base::GetProperty(kPowerHalAdpfDisableTopAppBoost, |
||||
"ADPF_DISABLE_TA_BOOST")), |
||||
mHintManager(nullptr), |
||||
mDisplayRefreshRate(60), |
||||
mActive(false) {} |
||||
PowerSessionManager(PowerSessionManager const &) = delete; |
||||
void operator=(PowerSessionManager const &) = delete; |
||||
}; |
||||
|
||||
class PowerHintMonitor : public Thread { |
||||
public: |
||||
void start(); |
||||
bool threadLoop() override; |
||||
sp<Looper> getLooper(); |
||||
// Singleton
|
||||
static sp<PowerHintMonitor> getInstance() { |
||||
static sp<PowerHintMonitor> instance = new PowerHintMonitor(); |
||||
return instance; |
||||
} |
||||
PowerHintMonitor(PowerHintMonitor const &) = delete; |
||||
void operator=(PowerHintMonitor const &) = delete; |
||||
|
||||
private: |
||||
sp<Looper> mLooper; |
||||
// Singleton
|
||||
PowerHintMonitor() : Thread(false), mLooper(new Looper(true)) {} |
||||
}; |
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace google
|
||||
} // namespace aidl
|
@ -0,0 +1,28 @@ |
||||
service vendor.power-hal-aidl /vendor/bin/hw/android.hardware.power-service.exynos9810-libperfmgr |
||||
class hal |
||||
user root |
||||
group system radio |
||||
priority -20 |
||||
|
||||
on late-fs |
||||
start vendor.power-hal-aidl |
||||
|
||||
# restart powerHAL when framework died |
||||
on property:init.svc.zygote=restarting && property:vendor.powerhal.state=* |
||||
setprop vendor.powerhal.state "" |
||||
setprop vendor.powerhal.audio "" |
||||
setprop vendor.powerhal.rendering "" |
||||
restart vendor.power-hal-aidl |
||||
|
||||
# Clean up after b/163539793 resolved |
||||
on property:vendor.powerhal.dalvik.vm.dex2oat-threads=* |
||||
setprop dalvik.vm.dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads} |
||||
setprop dalvik.vm.restore-dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads} |
||||
|
||||
on property:vendor.powerhal.dalvik.vm.dex2oat-cpu-set=* |
||||
setprop dalvik.vm.dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set} |
||||
setprop dalvik.vm.restore-dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set} |
||||
|
||||
# initialize powerHAL when boot is completed |
||||
on property:sys.boot_completed=1 |
||||
setprop vendor.powerhal.init 1 |
@ -0,0 +1,7 @@ |
||||
<manifest version="1.0" type="device"> |
||||
<hal format="aidl" override="true"> |
||||
<name>android.hardware.power</name> |
||||
<version>2</version> |
||||
<fqname>IPower/default</fqname> |
||||
</hal> |
||||
</manifest> |
@ -0,0 +1,441 @@ |
||||
{ |
||||
"Nodes": [ |
||||
{ |
||||
"Name": "CPULittleClusterMaxFreq", |
||||
"Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", |
||||
"Values": [ |
||||
"9999999", |
||||
"1113600" |
||||
], |
||||
"DefaultIndex": 0, |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "CPULittleClusterMinFreq", |
||||
"Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", |
||||
"Values": [ |
||||
"9999999", |
||||
"1113600", |
||||
"576000" |
||||
], |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "CPUBigClusterMaxFreq", |
||||
"Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq", |
||||
"Values": [ |
||||
"9999999", |
||||
"2016000", |
||||
"1497600", |
||||
"1401600" |
||||
], |
||||
"DefaultIndex": 0, |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "CPUBigClusterMinFreq", |
||||
"Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq", |
||||
"Values": [ |
||||
"9999999", |
||||
"1497600", |
||||
"1401600", |
||||
"1286400", |
||||
"0" |
||||
], |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "CPUBigPlusClusterMaxFreq", |
||||
"Path": "/sys/devices/system/cpu/cpu7/cpufreq/scaling_max_freq", |
||||
"Values": [ |
||||
"9999999", |
||||
"2016000", |
||||
"1497600", |
||||
"1401600" |
||||
], |
||||
"DefaultIndex": 0, |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "CPUBigPlusClusterMinFreq", |
||||
"Path": "/sys/devices/system/cpu/cpu7/cpufreq/scaling_min_freq", |
||||
"Values": [ |
||||
"9999999", |
||||
"1497600", |
||||
"1401600", |
||||
"1286400", |
||||
"0" |
||||
], |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "GPUMaxFreq", |
||||
"Path": "/sys/class/kgsl/kgsl-3d0/devfreq/max_freq", |
||||
"Values": [ |
||||
"585000000", |
||||
"427000000" |
||||
], |
||||
"DefaultIndex": 0, |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "GPUMinFreq", |
||||
"Path": "/sys/class/kgsl/kgsl-3d0/devfreq/min_freq", |
||||
"Values": [ |
||||
"585000000", |
||||
"427000000", |
||||
"345000000", |
||||
"257000000" |
||||
], |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "TASchedtuneBoost", |
||||
"Path": "/dev/stune/top-app/schedtune.boost", |
||||
"Values": [ |
||||
"30", |
||||
"10" |
||||
], |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "PMQoSCpuDmaLatency", |
||||
"Path": "/dev/cpu_dma_latency", |
||||
"Values": [ |
||||
"44", |
||||
"100" |
||||
], |
||||
"HoldFd": true |
||||
}, |
||||
{ |
||||
"Name": "TouchscreenEnable", |
||||
"Path": "/sys/class/input/input3/enabled", |
||||
"Values": [ |
||||
"1", |
||||
"0" |
||||
], |
||||
"ResetOnInit": true |
||||
}, |
||||
{ |
||||
"Name": "DoubleTapToWakeEnable", |
||||
"Path": "/sys/class/sec/tsp/cmd", |
||||
"Values": [ |
||||
"aot_enable,0", |
||||
"aot_enable,1" |
||||
], |
||||
"DefaultIndex": 0 |
||||
}, |
||||
{ |
||||
"Name": "PowerHALMainState", |
||||
"Path": "vendor.powerhal.state", |
||||
"Values": [ |
||||
"SUSTAINED_PERFORMANCE", |
||||
"VR_MODE", |
||||
"VR_SUSTAINED_PERFORMANCE", |
||||
"" |
||||
], |
||||
"Type": "Property" |
||||
}, |
||||
{ |
||||
"Name": "PowerHALAudioState", |
||||
"Path": "vendor.powerhal.audio", |
||||
"Values": [ |
||||
"AUDIO_STREAMING_LOW_LATENCY", |
||||
"" |
||||
], |
||||
"Type": "Property" |
||||
}, |
||||
{ |
||||
"Name": "PowerHALRenderingState", |
||||
"Path": "vendor.powerhal.rendering", |
||||
"Values": [ |
||||
"EXPENSIVE_RENDERING", |
||||
"" |
||||
], |
||||
"Type": "Property" |
||||
}, |
||||
{ |
||||
"Name": "PowerHALPerfProfileState", |
||||
"Path": "vendor.powerhal.perf_profile", |
||||
"Values": [ |
||||
"POWER_SAVE", |
||||
"BIAS_POWER_SAVE", |
||||
"BIAS_PERFORMANCE", |
||||
"HIGH_PERFORMANCE" |
||||
], |
||||
"Type": "Property" |
||||
} |
||||
], |
||||
"Actions": [ |
||||
{ |
||||
"PowerHint": "INTERACTION", |
||||
"Node": "CPUBigClusterMinFreq", |
||||
"Duration": 0, |
||||
"Value": "1286400" |
||||
}, |
||||
{ |
||||
"PowerHint": "INTERACTION", |
||||
"Node": "CPUBigPlusClusterMinFreq", |
||||
"Duration": 0, |
||||
"Value": "1286400" |
||||
}, |
||||
{ |
||||
"PowerHint": "INTERACTION", |
||||
"Node": "CPULittleClusterMinFreq", |
||||
"Duration": 0, |
||||
"Value": "1113600" |
||||
}, |
||||
{ |
||||
"PowerHint": "INTERACTION", |
||||
"Node": "TASchedtuneBoost", |
||||
"Duration": 0, |
||||
"Value": "30" |
||||
}, |
||||
{ |
||||
"PowerHint": "LAUNCH", |
||||
"Node": "CPUBigClusterMaxFreq", |
||||
"Duration": 5000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "LAUNCH", |
||||
"Node": "CPUBigPlusClusterMaxFreq", |
||||
"Duration": 5000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "LAUNCH", |
||||
"Node": "CPUBigClusterMinFreq", |
||||
"Duration": 5000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "LAUNCH", |
||||
"Node": "CPUBigPlusClusterMinFreq", |
||||
"Duration": 5000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "LAUNCH", |
||||
"Node": "CPULittleClusterMinFreq", |
||||
"Duration": 5000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "LAUNCH", |
||||
"Node": "PMQoSCpuDmaLatency", |
||||
"Duration": 5000, |
||||
"Value": "44" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_LAUNCH", |
||||
"Node": "CPUBigClusterMaxFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_LAUNCH", |
||||
"Node": "CPUBigPlusClusterMaxFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_LAUNCH", |
||||
"Node": "CPUBigClusterMinFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_LAUNCH", |
||||
"Node": "CPUBigPlusClusterMinFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_LAUNCH", |
||||
"Node": "CPULittleClusterMaxFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_LAUNCH", |
||||
"Node": "CPULittleClusterMinFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_LAUNCH", |
||||
"Node": "PMQoSCpuDmaLatency", |
||||
"Duration": 1000, |
||||
"Value": "44" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_STREAMING_MID", |
||||
"Node": "CPUBigClusterMaxFreq", |
||||
"Duration": 0, |
||||
"Value": "2016000" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_STREAMING_MID", |
||||
"Node": "CPUBigPlusClusterMaxFreq", |
||||
"Duration": 0, |
||||
"Value": "2016000" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_SHOT", |
||||
"Node": "CPUBigClusterMaxFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_SHOT", |
||||
"Node": "CPUBigPlusClusterMaxFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_SHOT", |
||||
"Node": "CPUBigClusterMinFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_SHOT", |
||||
"Node": "CPUBigPlusClusterMinFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_SHOT", |
||||
"Node": "CPULittleClusterMaxFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_SHOT", |
||||
"Node": "CPULittleClusterMinFreq", |
||||
"Duration": 1000, |
||||
"Value": "9999999" |
||||
}, |
||||
{ |
||||
"PowerHint": "CAMERA_SHOT", |
||||
"Node": "PMQoSCpuDmaLatency", |
||||
"Duration": 1000, |
||||
"Value": "44" |
||||
}, |
||||
{ |
||||
"PowerHint": "AUDIO_LAUNCH", |
||||
"Node": "PMQoSCpuDmaLatency", |
||||
"Duration": 2000, |
||||
"Value": "44" |
||||
}, |
||||
{ |
||||
"PowerHint": "AUDIO_STREAMING_LOW_LATENCY", |
||||
"Node": "PowerHALAudioState", |
||||
"Duration": 0, |
||||
"Value": "AUDIO_STREAMING_LOW_LATENCY" |
||||
}, |
||||
{ |
||||
"PowerHint": "AUDIO_STREAMING_LOW_LATENCY", |
||||
"Node": "PMQoSCpuDmaLatency", |
||||
"Duration": 0, |
||||
"Value": "44" |
||||
}, |
||||
{ |
||||
"PowerHint": "SUSTAINED_PERFORMANCE", |
||||
"Node": "PowerHALMainState", |
||||
"Duration": 0, |
||||
"Value": "SUSTAINED_PERFORMANCE" |
||||
}, |
||||
{ |
||||
"PowerHint": "SUSTAINED_PERFORMANCE", |
||||
"Node": "CPUBigClusterMaxFreq", |
||||
"Duration": 0, |
||||
"Value": "1401600" |
||||
}, |
||||
{ |
||||
"PowerHint": "SUSTAINED_PERFORMANCE", |
||||
"Node": "CPUBigPlusClusterMaxFreq", |
||||
"Duration": 0, |
||||
"Value": "1401600" |
||||
}, |
||||
{ |
||||
"PowerHint": "SUSTAINED_PERFORMANCE", |
||||
"Node": "CPULittleClusterMaxFreq", |
||||
"Duration": 0, |
||||
"Value": "1113600" |
||||
}, |
||||
{ |
||||
"PowerHint": "SUSTAINED_PERFORMANCE", |
||||
"Node": "GPUMaxFreq", |
||||
"Duration": 0, |
||||
"Value": "427000000" |
||||
}, |
||||
{ |
||||
"PowerHint": "VR_MODE", |
||||
"Node": "PowerHALMainState", |
||||
"Duration": 0, |
||||
"Value": "VR_MODE" |
||||
}, |
||||
{ |
||||
"PowerHint": "VR_SUSTAINED_PERFORMANCE", |
||||
"Node": "PowerHALMainState", |
||||
"Duration": 0, |
||||
"Value": "VR_SUSTAINED_PERFORMANCE" |
||||
}, |
||||
{ |
||||
"PowerHint": "EXPENSIVE_RENDERING", |
||||
"Node": "PowerHALRenderingState", |
||||
"Duration": 0, |
||||
"Value": "EXPENSIVE_RENDERING" |
||||
}, |
||||
{ |
||||
"PowerHint": "EXPENSIVE_RENDERING", |
||||
"Node": "GPUMinFreq", |
||||
"Duration": 0, |
||||
"Value": "427000000" |
||||
}, |
||||
{ |
||||
"PowerHint": "EXPENSIVE_RENDERING", |
||||
"Node": "GPUMaxFreq", |
||||
"Duration": 0, |
||||
"Value": "585000000" |
||||
}, |
||||
{ |
||||
"PowerHint": "INTERACTIVE", |
||||
"Node": "TouchscreenEnable", |
||||
"Duration": 0, |
||||
"Value": "1" |
||||
}, |
||||
{ |
||||
"PowerHint": "DOUBLE_TAP_TO_WAKE", |
||||
"Node": "DoubleTapToWakeEnable", |
||||
"Duration": 0, |
||||
"Value": "aot_enable,1" |
||||
}, |
||||
{ |
||||
"PowerHint": "PROFILE_POWER_SAVE", |
||||
"Node": "PowerHALPerfProfileState", |
||||
"Duration": 0, |
||||
"Value": "POWER_SAVE" |
||||
}, |
||||
{ |
||||
"PowerHint": "PROFILE_BIAS_POWER_SAVE", |
||||
"Node": "PowerHALPerfProfileState", |
||||
"Duration": 0, |
||||
"Value": "BIAS_POWER_SAVE" |
||||
}, |
||||
{ |
||||
"PowerHint": "PROFILE_BIAS_PERFORMANCE", |
||||
"Node": "PowerHALPerfProfileState", |
||||
"Duration": 0, |
||||
"Value": "BIAS_PERFORMANCE" |
||||
}, |
||||
{ |
||||
"PowerHint": "PROFILE_HIGH_PERFORMANCE", |
||||
"Node": "PowerHALPerfProfileState", |
||||
"Duration": 0, |
||||
"Value": "HIGH_PERFORMANCE" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,87 @@ |
||||
/*
|
||||
* Copyright (C) 2020 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" |
||||
|
||||
#include <thread> |
||||
|
||||
#include <android-base/logging.h> |
||||
#include <android-base/properties.h> |
||||
#include <android/binder_manager.h> |
||||
#include <android/binder_process.h> |
||||
|
||||
#include "Power.h" |
||||
#include "PowerExt.h" |
||||
#include "PowerSessionManager.h" |
||||
|
||||
using aidl::google::hardware::power::impl::pixel::Power; |
||||
using aidl::google::hardware::power::impl::pixel::PowerExt; |
||||
using aidl::google::hardware::power::impl::pixel::PowerHintMonitor; |
||||
using aidl::google::hardware::power::impl::pixel::PowerSessionManager; |
||||
using ::android::perfmgr::HintManager; |
||||
|
||||
constexpr std::string_view kPowerHalInitProp("vendor.powerhal.init"); |
||||
constexpr std::string_view kConfigProperty("vendor.powerhal.config"); |
||||
constexpr std::string_view kConfigDefaultFileName("powerhint.json"); |
||||
|
||||
int main() { |
||||
const std::string config_path = |
||||
"/vendor/etc/" + |
||||
android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()); |
||||
LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting with config: " |
||||
<< config_path; |
||||
|
||||
// Parse config but do not start the looper
|
||||
std::shared_ptr<HintManager> hm = HintManager::GetFromJSON(config_path, false); |
||||
if (!hm) { |
||||
LOG(FATAL) << "Invalid config: " << config_path; |
||||
} |
||||
|
||||
// single thread
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0); |
||||
|
||||
// core service
|
||||
std::shared_ptr<Power> pw = ndk::SharedRefBase::make<Power>(hm); |
||||
ndk::SpAIBinder pwBinder = pw->asBinder(); |
||||
|
||||
// extension service
|
||||
std::shared_ptr<PowerExt> pwExt = ndk::SharedRefBase::make<PowerExt>(hm); |
||||
|
||||
// attach the extension to the same binder we will be registering
|
||||
CHECK(STATUS_OK == AIBinder_setExtension(pwBinder.get(), pwExt->asBinder().get())); |
||||
|
||||
const std::string instance = std::string() + Power::descriptor + "/default"; |
||||
binder_status_t status = AServiceManager_addService(pw->asBinder().get(), instance.c_str()); |
||||
CHECK(status == STATUS_OK); |
||||
LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is started."; |
||||
|
||||
if (::android::base::GetIntProperty("vendor.powerhal.adpf.rate", -1) != -1) { |
||||
PowerHintMonitor::getInstance()->start(); |
||||
PowerSessionManager::getInstance()->setHintManager(hm); |
||||
} |
||||
|
||||
std::thread initThread([&]() { |
||||
::android::base::WaitForProperty(kPowerHalInitProp.data(), "1"); |
||||
hm->Start(); |
||||
}); |
||||
initThread.detach(); |
||||
|
||||
ABinderProcess_joinThreadPool(); |
||||
|
||||
// should not reach
|
||||
LOG(ERROR) << "Pixel Power HAL AIDL Service with Extension just died."; |
||||
return EXIT_FAILURE; |
||||
} |
Loading…
Reference in new issue