sdm845-common: Migrate to Xiaomi power AIDL HAL
Change-Id: I42170d51a517170b58d532addd9c38496e43457c
This commit is contained in:
parent
0c18729c97
commit
8d92bd277b
@ -1,5 +1,7 @@
|
||||
soong_namespace {
|
||||
imports: [
|
||||
"hardware/google/interfaces",
|
||||
"hardware/google/pixel",
|
||||
"hardware/xiaomi",
|
||||
],
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
//
|
||||
// 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.
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr",
|
||||
relative_install_path: "hw",
|
||||
init_rc: ["android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr.rc"],
|
||||
srcs: ["service.cpp", "Power.cpp", "InteractionHandler.cpp", "power-helper.c"],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libhidlbase",
|
||||
"libhidltransport",
|
||||
"liblog",
|
||||
"libutils",
|
||||
"libcutils",
|
||||
"android.hardware.power@1.0",
|
||||
"android.hardware.power@1.1",
|
||||
"android.hardware.power@1.2",
|
||||
"android.hardware.power@1.3",
|
||||
"libperfmgr",
|
||||
],
|
||||
proprietary: true,
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
/*
|
||||
* 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_NDEBUG 0
|
||||
|
||||
#define LOG_TAG "android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr"
|
||||
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include "InteractionHandler.h"
|
||||
|
||||
#define FB_IDLE_PATH "/sys/class/drm/card0/device/idle_state"
|
||||
#define MAX_LENGTH 64
|
||||
|
||||
#define MSINSEC 1000L
|
||||
#define USINMS 1000000L
|
||||
|
||||
InteractionHandler::InteractionHandler(std::shared_ptr<HintManager> const & hint_manager)
|
||||
: mState(INTERACTION_STATE_UNINITIALIZED),
|
||||
mWaitMs(100),
|
||||
mMinDurationMs(1400),
|
||||
mMaxDurationMs(5650),
|
||||
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;
|
||||
|
||||
mIdleFd = open(FB_IDLE_PATH, O_RDONLY);
|
||||
if (mIdleFd < 0) {
|
||||
ALOGE("Unable to open idle state path (%d)", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
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__);
|
||||
}
|
||||
ATRACE_INT("interaction_lock", 1);
|
||||
}
|
||||
|
||||
void InteractionHandler::PerfRel() {
|
||||
ALOGV("%s: releasing perf lock", __func__);
|
||||
if (!mHintManager->EndHint("INTERACTION")) {
|
||||
ALOGE("%s: end hint INTERACTION failed", __func__);
|
||||
}
|
||||
ATRACE_INT("interaction_lock", 0);
|
||||
}
|
||||
|
||||
long long InteractionHandler::CalcTimespecDiffMs(struct timespec start,
|
||||
struct timespec end) {
|
||||
long long diff_in_us = 0;
|
||||
diff_in_us += (end.tv_sec - start.tv_sec) * MSINSEC;
|
||||
diff_in_us += (end.tv_nsec - start.tv_nsec) / USINMS;
|
||||
return diff_in_us;
|
||||
}
|
||||
|
||||
void InteractionHandler::Acquire(int32_t duration) {
|
||||
ATRACE_CALL();
|
||||
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
if (mState == INTERACTION_STATE_UNINITIALIZED) {
|
||||
ALOGW("%s: called while uninitialized", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
int inputDuration = duration + 650;
|
||||
int finalDuration;
|
||||
if (inputDuration > mMaxDurationMs)
|
||||
finalDuration = mMaxDurationMs;
|
||||
else if (inputDuration > mMinDurationMs)
|
||||
finalDuration = inputDuration;
|
||||
else
|
||||
finalDuration = mMinDurationMs;
|
||||
|
||||
struct timespec cur_timespec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
|
||||
if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
|
||||
long long 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__, mDurationMs, finalDuration, 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() {
|
||||
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(mWaitMs, mDurationMs);
|
||||
Release();
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef INTERACTIONHANDLER_H
|
||||
#define INTERACTIONHANDLER_H
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <perfmgr/HintManager.h>
|
||||
|
||||
using ::android::perfmgr::HintManager;
|
||||
|
||||
enum interaction_state {
|
||||
INTERACTION_STATE_UNINITIALIZED,
|
||||
INTERACTION_STATE_IDLE,
|
||||
INTERACTION_STATE_INTERACTION,
|
||||
INTERACTION_STATE_WAITING,
|
||||
};
|
||||
|
||||
struct InteractionHandler {
|
||||
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();
|
||||
|
||||
long long CalcTimespecDiffMs(struct timespec start, struct timespec end);
|
||||
|
||||
enum interaction_state mState;
|
||||
|
||||
int mIdleFd;
|
||||
int mEventFd;
|
||||
|
||||
int32_t mWaitMs;
|
||||
int32_t mMinDurationMs;
|
||||
int32_t mMaxDurationMs;
|
||||
int32_t mDurationMs;
|
||||
|
||||
struct timespec mLastTimespec;
|
||||
|
||||
std::unique_ptr<std::thread> mThread;
|
||||
std::mutex mLock;
|
||||
std::condition_variable mCond;
|
||||
std::shared_ptr<HintManager> mHintManager;
|
||||
};
|
||||
|
||||
#endif //INTERACTIONHANDLER_H
|
@ -1,489 +0,0 @@
|
||||
/*
|
||||
* 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 ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
|
||||
#define LOG_TAG "android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr"
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Trace.h>
|
||||
|
||||
#include "Power.h"
|
||||
#include "power-helper.h"
|
||||
|
||||
/* RPM runs at 19.2Mhz. Divide by 19200 for msec */
|
||||
#define RPM_CLK 19200
|
||||
|
||||
extern struct stats_section master_sections[];
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace power {
|
||||
namespace V1_3 {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::hardware::power::V1_0::Feature;
|
||||
using ::android::hardware::power::V1_0::PowerStatePlatformSleepState;
|
||||
using ::android::hardware::power::V1_0::Status;
|
||||
using ::android::hardware::power::V1_1::PowerStateSubsystem;
|
||||
using ::android::hardware::power::V1_1::PowerStateSubsystemSleepState;
|
||||
using ::android::hardware::hidl_vec;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::hardware::Void;
|
||||
|
||||
Power::Power() :
|
||||
mHintManager(nullptr),
|
||||
mInteractionHandler(nullptr),
|
||||
mVRModeOn(false),
|
||||
mSustainedPerfModeOn(false),
|
||||
mCameraStreamingModeOn(false),
|
||||
mReady(false) {
|
||||
|
||||
mInitThread =
|
||||
std::thread([this](){
|
||||
android::base::WaitForProperty(kPowerHalInitProp, "1");
|
||||
mHintManager = HintManager::GetFromJSON(kPowerHalConfigPath);
|
||||
if (!mHintManager) {
|
||||
LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath;
|
||||
}
|
||||
mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager);
|
||||
mInteractionHandler->Init();
|
||||
std::string state = android::base::GetProperty(kPowerHalStateProp, "");
|
||||
if (state == "CAMERA_STREAMING") {
|
||||
ALOGI("Initialize with CAMERA_STREAMING on");
|
||||
mHintManager->DoHint("CAMERA_STREAMING");
|
||||
mCameraStreamingModeOn = true;
|
||||
} else if (state == "SUSTAINED_PERFORMANCE") {
|
||||
ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
|
||||
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
|
||||
mSustainedPerfModeOn = true;
|
||||
} else if (state == "VR_MODE") {
|
||||
ALOGI("Initialize with VR_MODE on");
|
||||
mHintManager->DoHint("VR_MODE");
|
||||
mVRModeOn = true;
|
||||
} else if (state == "VR_SUSTAINED_PERFORMANCE") {
|
||||
ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR_MODE on");
|
||||
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
|
||||
mSustainedPerfModeOn = true;
|
||||
mVRModeOn = true;
|
||||
} else {
|
||||
ALOGI("Initialize PowerHAL");
|
||||
}
|
||||
|
||||
state = android::base::GetProperty(kPowerHalAudioProp, "");
|
||||
if (state == "AUDIO_LOW_LATENCY") {
|
||||
ALOGI("Initialize with AUDIO_LOW_LATENCY on");
|
||||
mHintManager->DoHint("AUDIO_LOW_LATENCY");
|
||||
}
|
||||
|
||||
state = android::base::GetProperty(kPowerHalRenderingProp, "");
|
||||
if (state == "EXPENSIVE_RENDERING") {
|
||||
ALOGI("Initialize with EXPENSIVE_RENDERING on");
|
||||
mHintManager->DoHint("EXPENSIVE_RENDERING");
|
||||
}
|
||||
// Now start to take powerhint
|
||||
mReady.store(true);
|
||||
});
|
||||
mInitThread.detach();
|
||||
|
||||
}
|
||||
|
||||
// Methods from ::android::hardware::power::V1_0::IPower follow.
|
||||
Return<void> Power::setInteractive(bool /* interactive */) {
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> Power::powerHint(PowerHint_1_0 hint, int32_t data) {
|
||||
if (!isSupportedGovernor() || !mReady) {
|
||||
return Void();
|
||||
}
|
||||
|
||||
switch(hint) {
|
||||
case PowerHint_1_0::INTERACTION:
|
||||
if (mVRModeOn || mSustainedPerfModeOn) {
|
||||
ALOGV("%s: ignoring due to other active perf hints", __func__);
|
||||
} else {
|
||||
mInteractionHandler->Acquire(data);
|
||||
}
|
||||
break;
|
||||
case PowerHint_1_0::SUSTAINED_PERFORMANCE:
|
||||
if (data && !mSustainedPerfModeOn) {
|
||||
ALOGD("SUSTAINED_PERFORMANCE ON");
|
||||
if (!mVRModeOn) { // Sustained mode only.
|
||||
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
|
||||
} else { // Sustained + VR mode.
|
||||
mHintManager->EndHint("VR_MODE");
|
||||
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
|
||||
}
|
||||
mSustainedPerfModeOn = true;
|
||||
} else if (!data && mSustainedPerfModeOn) {
|
||||
ALOGD("SUSTAINED_PERFORMANCE OFF");
|
||||
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
|
||||
mHintManager->EndHint("SUSTAINED_PERFORMANCE");
|
||||
if (mVRModeOn) { // Switch back to VR Mode.
|
||||
mHintManager->DoHint("VR_MODE");
|
||||
}
|
||||
mSustainedPerfModeOn = false;
|
||||
}
|
||||
break;
|
||||
case PowerHint_1_0::VR_MODE:
|
||||
if (data && !mVRModeOn) {
|
||||
ALOGD("VR_MODE ON");
|
||||
if (!mSustainedPerfModeOn) { // VR mode only.
|
||||
mHintManager->DoHint("VR_MODE");
|
||||
} else { // Sustained + VR mode.
|
||||
mHintManager->EndHint("SUSTAINED_PERFORMANCE");
|
||||
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
|
||||
}
|
||||
mVRModeOn = true;
|
||||
} else if (!data && mVRModeOn) {
|
||||
ALOGD("VR_MODE OFF");
|
||||
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
|
||||
mHintManager->EndHint("VR_MODE");
|
||||
if (mSustainedPerfModeOn) { // Switch back to sustained Mode.
|
||||
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
|
||||
}
|
||||
mVRModeOn = false;
|
||||
}
|
||||
break;
|
||||
case PowerHint_1_0::LAUNCH:
|
||||
ATRACE_BEGIN("launch");
|
||||
if (mVRModeOn || mSustainedPerfModeOn) {
|
||||
ALOGV("%s: ignoring due to other active perf hints", __func__);
|
||||
} else {
|
||||
if (data) {
|
||||
// Hint until canceled
|
||||
ATRACE_INT("launch_lock", 1);
|
||||
mHintManager->DoHint("LAUNCH");
|
||||
ALOGD("LAUNCH ON");
|
||||
} else {
|
||||
ATRACE_INT("launch_lock", 0);
|
||||
mHintManager->EndHint("LAUNCH");
|
||||
ALOGD("LAUNCH OFF");
|
||||
}
|
||||
}
|
||||
ATRACE_END();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> Power::setFeature(Feature /*feature*/, bool /*activate*/) {
|
||||
//Nothing to do
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
|
||||
|
||||
hidl_vec<PowerStatePlatformSleepState> states;
|
||||
uint64_t stats[SYSTEM_SLEEP_STATE_COUNT * SYSTEM_STATE_STATS_COUNT] = {0};
|
||||
uint64_t *state_stats;
|
||||
struct PowerStatePlatformSleepState *state;
|
||||
|
||||
states.resize(SYSTEM_SLEEP_STATE_COUNT);
|
||||
|
||||
if (extract_system_stats(stats, ARRAY_SIZE(stats)) != 0) {
|
||||
states.resize(0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Update statistics for AOSD */
|
||||
state = &states[SYSTEM_STATE_AOSD];
|
||||
state->name = "AOSD";
|
||||
state_stats = &stats[SYSTEM_STATE_AOSD * SYSTEM_STATE_STATS_COUNT];
|
||||
|
||||
state->residencyInMsecSinceBoot = state_stats[ACCUMULATED_TIME_MS];
|
||||
state->totalTransitions = state_stats[TOTAL_COUNT];
|
||||
state->supportedOnlyInSuspend = false;
|
||||
state->voters.resize(0);
|
||||
|
||||
/* Update statistics for CXSD */
|
||||
state = &states[SYSTEM_STATE_CXSD];
|
||||
state->name = "CXSD";
|
||||
state_stats = &stats[SYSTEM_STATE_CXSD * SYSTEM_STATE_STATS_COUNT];
|
||||
|
||||
state->residencyInMsecSinceBoot = state_stats[ACCUMULATED_TIME_MS];
|
||||
state->totalTransitions = state_stats[TOTAL_COUNT];
|
||||
state->supportedOnlyInSuspend = false;
|
||||
state->voters.resize(0);
|
||||
|
||||
done:
|
||||
_hidl_cb(states, Status::SUCCESS);
|
||||
return Void();
|
||||
}
|
||||
|
||||
static int get_master_low_power_stats(hidl_vec<PowerStateSubsystem> *subsystems) {
|
||||
uint64_t all_stats[MASTER_COUNT * MASTER_STATS_COUNT] = {0};
|
||||
uint64_t *section_stats;
|
||||
struct PowerStateSubsystem *subsystem;
|
||||
struct PowerStateSubsystemSleepState *state;
|
||||
|
||||
if (extract_master_stats(all_stats, ARRAY_SIZE(all_stats)) != 0) {
|
||||
for (size_t i = 0; i < MASTER_COUNT; i++) {
|
||||
(*subsystems)[i].name = master_sections[i].label;
|
||||
(*subsystems)[i].states.resize(0);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < MASTER_COUNT; i++) {
|
||||
subsystem = &(*subsystems)[i];
|
||||
subsystem->name = master_sections[i].label;
|
||||
subsystem->states.resize(MASTER_SLEEP_STATE_COUNT);
|
||||
|
||||
state = &(subsystem->states[MASTER_SLEEP]);
|
||||
section_stats = &all_stats[i * MASTER_STATS_COUNT];
|
||||
|
||||
state->name = "Sleep";
|
||||
state->totalTransitions = section_stats[SLEEP_ENTER_COUNT];
|
||||
state->residencyInMsecSinceBoot = section_stats[SLEEP_CUMULATIVE_DURATION_MS] / RPM_CLK;
|
||||
state->lastEntryTimestampMs = section_stats[SLEEP_LAST_ENTER_TSTAMP_MS] / RPM_CLK;
|
||||
state->supportedOnlyInSuspend = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_wlan_low_power_stats(struct PowerStateSubsystem *subsystem) {
|
||||
uint64_t stats[WLAN_STATS_COUNT] = {0};
|
||||
struct PowerStateSubsystemSleepState *state;
|
||||
|
||||
subsystem->name = "wlan";
|
||||
|
||||
if (extract_wlan_stats(stats, ARRAY_SIZE(stats)) != 0) {
|
||||
subsystem->states.resize(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
subsystem->states.resize(WLAN_SLEEP_STATE_COUNT);
|
||||
|
||||
/* Update statistics for Active State */
|
||||
state = &subsystem->states[WLAN_STATE_ACTIVE];
|
||||
state->name = "Active";
|
||||
state->residencyInMsecSinceBoot = stats[CUMULATIVE_TOTAL_ON_TIME_MS];
|
||||
state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
|
||||
state->lastEntryTimestampMs = 0; //FIXME need a new value from Qcom
|
||||
state->supportedOnlyInSuspend = false;
|
||||
|
||||
/* Update statistics for Deep-Sleep state */
|
||||
state = &subsystem->states[WLAN_STATE_DEEP_SLEEP];
|
||||
state->name = "Deep-Sleep";
|
||||
state->residencyInMsecSinceBoot = stats[CUMULATIVE_SLEEP_TIME_MS];
|
||||
state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
|
||||
state->lastEntryTimestampMs = stats[LAST_DEEP_SLEEP_ENTER_TSTAMP_MS];
|
||||
state->supportedOnlyInSuspend = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Methods from ::android::hardware::power::V1_1::IPower follow.
|
||||
Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
|
||||
hidl_vec<PowerStateSubsystem> subsystems;
|
||||
|
||||
subsystems.resize(STATS_SOURCE_COUNT);
|
||||
|
||||
// Get low power stats for all of the system masters.
|
||||
if (get_master_low_power_stats(&subsystems) != 0) {
|
||||
ALOGE("%s: failed to process master stats", __func__);
|
||||
}
|
||||
|
||||
// Get WLAN subsystem low power stats.
|
||||
if (get_wlan_low_power_stats(&subsystems[SUBSYSTEM_WLAN]) != 0) {
|
||||
ALOGE("%s: failed to process wlan stats", __func__);
|
||||
}
|
||||
|
||||
_hidl_cb(subsystems, Status::SUCCESS);
|
||||
return Void();
|
||||
}
|
||||
|
||||
bool Power::isSupportedGovernor() {
|
||||
std::string buf;
|
||||
if (android::base::ReadFileToString("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", &buf)) {
|
||||
buf = android::base::Trim(buf);
|
||||
}
|
||||
// Only support EAS 1.2, legacy EAS
|
||||
if (buf == "schedutil" || buf == "sched") {
|
||||
return true;
|
||||
} else {
|
||||
LOG(ERROR) << "Governor not supported by powerHAL, skipping";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Return<void> Power::powerHintAsync(PowerHint_1_0 hint, int32_t data) {
|
||||
// just call the normal power hint in this oneway function
|
||||
return powerHint(hint, data);
|
||||
}
|
||||
|
||||
// Methods from ::android::hardware::power::V1_2::IPower follow.
|
||||
Return<void> Power::powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) {
|
||||
if (!isSupportedGovernor() || !mReady) {
|
||||
return Void();
|
||||
}
|
||||
|
||||
switch(hint) {
|
||||
case PowerHint_1_2::AUDIO_LOW_LATENCY:
|
||||
ATRACE_BEGIN("audio_low_latency");
|
||||
if (data) {
|
||||
// Hint until canceled
|
||||
ATRACE_INT("audio_low_latency_lock", 1);
|
||||
mHintManager->DoHint("AUDIO_LOW_LATENCY");
|
||||
ALOGD("AUDIO LOW LATENCY ON");
|
||||
} else {
|
||||
ATRACE_INT("audio_low_latency_lock", 0);
|
||||
mHintManager->EndHint("AUDIO_LOW_LATENCY");
|
||||
ALOGD("AUDIO LOW LATENCY OFF");
|
||||
}
|
||||
ATRACE_END();
|
||||
break;
|
||||
case PowerHint_1_2::AUDIO_STREAMING:
|
||||
ATRACE_BEGIN("audio_streaming");
|
||||
if (mVRModeOn || mSustainedPerfModeOn) {
|
||||
ALOGV("%s: ignoring due to other active perf hints", __func__);
|
||||
} else {
|
||||
if (data) {
|
||||
// Hint until canceled
|
||||
ATRACE_INT("audio_streaming_lock", 1);
|
||||
mHintManager->DoHint("AUDIO_STREAMING");
|
||||
ALOGD("AUDIO STREAMING ON");
|
||||
} else {
|
||||
ATRACE_INT("audio_streaming_lock", 0);
|
||||
mHintManager->EndHint("AUDIO_STREAMING");
|
||||
ALOGD("AUDIO STREAMING OFF");
|
||||
}
|
||||
}
|
||||
ATRACE_END();
|
||||
break;
|
||||
case PowerHint_1_2::CAMERA_LAUNCH:
|
||||
ATRACE_BEGIN("camera_launch");
|
||||
if (data > 0) {
|
||||
ATRACE_INT("camera_launch_lock", 1);
|
||||
mHintManager->DoHint("CAMERA_LAUNCH", std::chrono::milliseconds(data));
|
||||
ALOGD("CAMERA LAUNCH ON: %d MS, LAUNCH ON: 2500 MS", data);
|
||||
// boosts 2.5s for launching
|
||||
mHintManager->DoHint("LAUNCH", std::chrono::milliseconds(2500));
|
||||
} else if (data == 0) {
|
||||
ATRACE_INT("camera_launch_lock", 0);
|
||||
mHintManager->EndHint("CAMERA_LAUNCH");
|
||||
ALOGD("CAMERA LAUNCH OFF");
|
||||
} else {
|
||||
ALOGE("CAMERA LAUNCH INVALID DATA: %d", data);
|
||||
}
|
||||
ATRACE_END();
|
||||
break;
|
||||
case PowerHint_1_2::CAMERA_STREAMING:
|
||||
ATRACE_BEGIN("camera_streaming");
|
||||
if (data > 0) {
|
||||
ATRACE_INT("camera_streaming_lock", 1);
|
||||
mHintManager->DoHint("CAMERA_STREAMING");
|
||||
ALOGD("CAMERA STREAMING ON");
|
||||
mCameraStreamingModeOn = true;
|
||||
} else if (data == 0) {
|
||||
ATRACE_INT("camera_streaming_lock", 0);
|
||||
mHintManager->EndHint("CAMERA_STREAMING");
|
||||
ALOGD("CAMERA STREAMING OFF");
|
||||
mCameraStreamingModeOn = false;
|
||||
} else {
|
||||
ALOGE("CAMERA STREAMING INVALID DATA: %d", data);
|
||||
}
|
||||
ATRACE_END();
|
||||
break;
|
||||
case PowerHint_1_2::CAMERA_SHOT:
|
||||
ATRACE_BEGIN("camera_shot");
|
||||
if (data > 0) {
|
||||
ATRACE_INT("camera_shot_lock", 1);
|
||||
mHintManager->DoHint("CAMERA_SHOT", std::chrono::milliseconds(data));
|
||||
ALOGD("CAMERA SHOT ON: %d MS", data);
|
||||
} else if (data == 0) {
|
||||
ATRACE_INT("camera_shot_lock", 0);
|
||||
mHintManager->EndHint("CAMERA_SHOT");
|
||||
ALOGD("CAMERA SHOT OFF");
|
||||
} else {
|
||||
ALOGE("CAMERA SHOT INVALID DATA: %d", data);
|
||||
}
|
||||
ATRACE_END();
|
||||
break;
|
||||
default:
|
||||
return powerHint(static_cast<PowerHint_1_0>(hint), data);
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
// Methods from ::android::hardware::power::V1_3::IPower follow.
|
||||
Return<void> Power::powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) {
|
||||
if (!isSupportedGovernor() || !mReady) {
|
||||
return Void();
|
||||
}
|
||||
|
||||
if (hint == PowerHint_1_3::EXPENSIVE_RENDERING) {
|
||||
if (mVRModeOn || mSustainedPerfModeOn) {
|
||||
ALOGV("%s: ignoring due to other active perf hints", __func__);
|
||||
return Void();
|
||||
}
|
||||
|
||||
if (data > 0) {
|
||||
ATRACE_INT("EXPENSIVE_RENDERING", 1);
|
||||
mHintManager->DoHint("EXPENSIVE_RENDERING");
|
||||
} else {
|
||||
ATRACE_INT("EXPENSIVE_RENDERING", 0);
|
||||
mHintManager->EndHint("EXPENSIVE_RENDERING");
|
||||
}
|
||||
} else {
|
||||
return powerHintAsync_1_2(static_cast<PowerHint_1_2>(hint), data);
|
||||
}
|
||||
|
||||
return Void();
|
||||
}
|
||||
|
||||
constexpr const char* boolToString(bool b) {
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
Return<void> Power::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
|
||||
if (handle != nullptr && handle->numFds >= 1 && mReady) {
|
||||
int fd = handle->data[0];
|
||||
|
||||
std::string buf(android::base::StringPrintf("HintManager Running: %s\n"
|
||||
"VRMode: %s\n"
|
||||
"CameraStreamingMode: %s\n"
|
||||
"SustainedPerformanceMode: %s\n",
|
||||
boolToString(mHintManager->IsRunning()),
|
||||
boolToString(mVRModeOn),
|
||||
boolToString(mCameraStreamingModeOn),
|
||||
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 Void();
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_3
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace android
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HARDWARE_POWER_V1_3_POWER_H
|
||||
#define ANDROID_HARDWARE_POWER_V1_3_POWER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include <android/hardware/power/1.3/IPower.h>
|
||||
#include <hidl/MQDescriptor.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <perfmgr/HintManager.h>
|
||||
|
||||
#include "InteractionHandler.h"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace power {
|
||||
namespace V1_3 {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::hardware::power::V1_0::Feature;
|
||||
using ::android::hardware::power::V1_3::IPower;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::hardware::Void;
|
||||
using ::InteractionHandler;
|
||||
using PowerHint_1_0 = ::android::hardware::power::V1_0::PowerHint;
|
||||
using PowerHint_1_2 = ::android::hardware::power::V1_2::PowerHint;
|
||||
using PowerHint_1_3 = ::android::hardware::power::V1_3::PowerHint;
|
||||
using ::android::perfmgr::HintManager;
|
||||
|
||||
constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
|
||||
constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
|
||||
constexpr char kPowerHalInitProp[] = "vendor.powerhal.init";
|
||||
constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
|
||||
constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json";
|
||||
|
||||
struct Power : public IPower {
|
||||
// Methods from ::android::hardware::power::V1_0::IPower follow.
|
||||
|
||||
Power();
|
||||
|
||||
Return<void> setInteractive(bool /* interactive */) override;
|
||||
Return<void> powerHint(PowerHint_1_0 hint, int32_t data) override;
|
||||
Return<void> setFeature(Feature feature, bool activate) override;
|
||||
Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override;
|
||||
|
||||
// Methods from ::android::hardware::power::V1_1::IPower follow.
|
||||
Return<void> getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) override;
|
||||
Return<void> powerHintAsync(PowerHint_1_0 hint, int32_t data) override;
|
||||
|
||||
// Methods from ::android::hardware::power::V1_2::IPower follow.
|
||||
Return<void> powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) override;
|
||||
|
||||
// Methods from ::android::hardware::power::V1_3::IPower follow.
|
||||
Return<void> powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) override;
|
||||
|
||||
// Methods from ::android::hidl::base::V1_0::IBase follow.
|
||||
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
|
||||
|
||||
private:
|
||||
static bool isSupportedGovernor();
|
||||
|
||||
std::shared_ptr<HintManager> mHintManager;
|
||||
std::unique_ptr<InteractionHandler> mInteractionHandler;
|
||||
std::atomic<bool> mVRModeOn;
|
||||
std::atomic<bool> mSustainedPerfModeOn;
|
||||
std::atomic<bool> mCameraStreamingModeOn;
|
||||
std::atomic<bool> mReady;
|
||||
std::thread mInitThread;
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_3
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
|
||||
#endif // ANDROID_HARDWARE_POWER_V1_3_POWER_H
|
@ -1,21 +0,0 @@
|
||||
service vendor.power-hal-1-3 /vendor/bin/hw/android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr
|
||||
class hal
|
||||
user root
|
||||
group system
|
||||
|
||||
# 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-1-3
|
||||
|
||||
# restart powerHAL when cameraHAL died
|
||||
on property:init.svc.vendor.camera-provider-2-4=restarting && property:vendor.powerhal.state=CAMERA_STREAMING
|
||||
setprop vendor.powerhal.state ""
|
||||
restart vendor.power-hal-1-3
|
||||
|
||||
# restart powerHAL when audioHAL died
|
||||
on property:init.svc.vendor.audio-hal-2-0=restarting && property:vendor.powerhal.audio=AUDIO_LOW_LATENCY
|
||||
setprop vendor.powerhal.audio ""
|
||||
restart vendor.power-hal-1-3
|
@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define LOG_NIDEBUG 0
|
||||
#define LOG_TAG "android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr"
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
#include "power-helper.h"
|
||||
|
||||
#ifndef MASTER_STATS_FILE
|
||||
#define MASTER_STATS_FILE "/sys/power/rpmh_stats/master_stats"
|
||||
#endif
|
||||
|
||||
#ifndef WLAN_STATS_FILE
|
||||
#define WLAN_STATS_FILE "/d/wlan0/power_stats"
|
||||
#endif
|
||||
|
||||
#ifndef SYSTEM_STATS_FILE
|
||||
#define SYSTEM_STATS_FILE "/sys/power/system_sleep/stats"
|
||||
#endif
|
||||
|
||||
#define LINE_SIZE 128
|
||||
|
||||
const char *master_stats_labels[MASTER_STATS_COUNT] = {
|
||||
"Sleep Accumulated Duration",
|
||||
"Sleep Count",
|
||||
"Sleep Last Entered At",
|
||||
};
|
||||
|
||||
struct stats_section master_sections[MASTER_COUNT] = {
|
||||
{ MASTER_APSS, "APSS", master_stats_labels, ARRAY_SIZE(master_stats_labels) },
|
||||
{ MASTER_MPSS, "MPSS", master_stats_labels, ARRAY_SIZE(master_stats_labels) },
|
||||
{ MASTER_ADSP, "ADSP", master_stats_labels, ARRAY_SIZE(master_stats_labels) },
|
||||
{ MASTER_SLPI, "SLPI", master_stats_labels, ARRAY_SIZE(master_stats_labels) },
|
||||
// The following masters are currently unused
|
||||
//{ MASTER_CDSP, "CDSP", master_stats_labels, ARRAY_SIZE(master_stats_labels) },
|
||||
//{ MASTER_GPU, "GPU", master_stats_labels, ARRAY_SIZE(master_stats_labels) },
|
||||
//{ MASTER_DISPLAY, "DISPLAY", master_stats_labels, ARRAY_SIZE(master_stats_labels) },
|
||||
};
|
||||
|
||||
const char *wlan_stats_labels[WLAN_STATS_COUNT] = {
|
||||
"cumulative_sleep_time_ms",
|
||||
"cumulative_total_on_time_ms",
|
||||
"deep_sleep_enter_counter",
|
||||
"last_deep_sleep_enter_tstamp_ms"
|
||||
};
|
||||
|
||||
struct stats_section wlan_sections[] = {
|
||||
{ SUBSYSTEM_WLAN, "POWER DEBUG STATS", wlan_stats_labels, ARRAY_SIZE(wlan_stats_labels) },
|
||||
};
|
||||
|
||||
const char *system_stats_labels[SYSTEM_STATE_STATS_COUNT] = {
|
||||
"count",
|
||||
"actual last sleep(msec)"
|
||||
};
|
||||
|
||||
struct stats_section system_sections[] = {
|
||||
{ SYSTEM_STATES, "RPM Mode:aosd", system_stats_labels, ARRAY_SIZE(system_stats_labels) },
|
||||
{ SYSTEM_STATES, "RPM Mode:cxsd", system_stats_labels, ARRAY_SIZE(system_stats_labels) },
|
||||
};
|
||||
|
||||
static int parse_stats(const char **stat_labels, size_t num_stats,
|
||||
uint64_t *list, FILE *fp) {
|
||||
ssize_t nread;
|
||||
size_t len = LINE_SIZE;
|
||||
char *line;
|
||||
size_t stats_read = 0;
|
||||
size_t i;
|
||||
|
||||
line = malloc(len);
|
||||
if (!line) {
|
||||
ALOGE("%s: no memory to hold line", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while ((stats_read < num_stats) &&
|
||||
(nread = getline(&line, &len, fp) > 0)) {
|
||||
char *key = line + strspn(line, " \t");
|
||||
char *value = strchr(key, ':');
|
||||
if (!value || (value > (line + len)))
|
||||
continue;
|
||||
*value++ = '\0';
|
||||
|
||||
for (i = 0; i < num_stats; i++) {
|
||||
if (!strncmp(key, stat_labels[i], strlen(stat_labels[i]))) {
|
||||
list[i] = strtoull(value, NULL, 0);
|
||||
stats_read++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
return stats_read;
|
||||
}
|
||||
|
||||
|
||||
static int extract_stats(uint64_t *stats_list, size_t entries_per_section, char *file,
|
||||
struct stats_section *sections, size_t num_sections) {
|
||||
FILE *fp;
|
||||
ssize_t read;
|
||||
size_t len = LINE_SIZE;
|
||||
char *line;
|
||||
size_t i;
|
||||
size_t sections_read = 0;
|
||||
size_t stats_read = 0;
|
||||
int ret = 0;
|
||||
|
||||
fp = fopen(file, "re");
|
||||
if (fp == NULL) {
|
||||
ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
line = malloc(len);
|
||||
if (!line) {
|
||||
ALOGE("%s: no memory to hold line", __func__);
|
||||
fclose(fp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
// Ensure that any missing stats default to 0
|
||||
for (i = 0; i < (entries_per_section * num_sections); i++) {
|
||||
stats_list[i] = 0L;
|
||||
}
|
||||
|
||||
// Iterate over the sections we expect to find in the file, calling parse_stats()
|
||||
// to process each section as we detect section headers
|
||||
while ((sections_read < num_sections) && (read = getline(&line, &len, fp) != -1)) {
|
||||
size_t begin = strspn(line, " \t");
|
||||
|
||||
for (i = 0; i < num_sections; i++) {
|
||||
if (!strncmp(line + begin, sections[i].label, strlen(sections[i].label))) {
|
||||
sections_read++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == num_sections) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stats_read = parse_stats(sections[i].stats_labels, sections[i].num_stats,
|
||||
&stats_list[i * entries_per_section], fp);
|
||||
// If we don't find all of the stats we expect in this section, our understanding of
|
||||
// the input is wrong, and we can't just carry on as if everything is okay. Better
|
||||
// to log the error and give up than potentially return incorrect data as stats.
|
||||
if (stats_read != sections[i].num_stats) {
|
||||
ALOGE("%s: failed to read all stats for %s section (%zu of %zu)", __func__,
|
||||
sections[i].label, stats_read, sections[i].num_stats);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(line);
|
||||
fclose(fp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int extract_master_stats(uint64_t *list, size_t list_length) {
|
||||
size_t entries_per_section = list_length / ARRAY_SIZE(master_sections);
|
||||
if (list_length % entries_per_section != 0) {
|
||||
ALOGW("%s: stats list size not an even multiple of section count", __func__);
|
||||
}
|
||||
|
||||
return extract_stats(list, entries_per_section, MASTER_STATS_FILE,
|
||||
master_sections, ARRAY_SIZE(master_sections));
|
||||
}
|
||||
|
||||
int extract_wlan_stats(uint64_t *list, size_t list_length) {
|
||||
size_t entries_per_section = list_length / ARRAY_SIZE(wlan_sections);
|
||||
if (list_length % entries_per_section != 0) {
|
||||
ALOGW("%s: stats list size not an even multiple of section count", __func__);
|
||||
}
|
||||
|
||||
return extract_stats(list, entries_per_section, WLAN_STATS_FILE,
|
||||
wlan_sections, ARRAY_SIZE(wlan_sections));
|
||||
}
|
||||
|
||||
int extract_system_stats(uint64_t *list, size_t list_length) {
|
||||
size_t entries_per_section = list_length / ARRAY_SIZE(system_sections);
|
||||
if (list_length % entries_per_section != 0) {
|
||||
ALOGW("%s: stats list size not an even multiple of section count", __func__);
|
||||
}
|
||||
|
||||
return extract_stats(list, entries_per_section, SYSTEM_STATS_FILE,
|
||||
system_sections, ARRAY_SIZE(system_sections));
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __POWER_HELPER_H__
|
||||
#define __POWER_HELPER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// These values are used as indices in getSubsystemLowPowerStats(), as source IDs
|
||||
// in stats_section instances, and (in the case of the _COUNT values) to dimension
|
||||
// containers. The values used as indices need to be contiguous, but others do
|
||||
// not (which is why SYSTEM_STATES is all the way at the end; it is not used as
|
||||
// an index, but only as a source ID).
|
||||
enum stats_source {
|
||||
// Master stats
|
||||
MASTER_APSS = 0,
|
||||
MASTER_MPSS,
|
||||
MASTER_ADSP,
|
||||
MASTER_SLPI,
|
||||
// The following 3 masters are supported by the RPMh stats driver, but not
|
||||
// in use on our devices.
|
||||
// MASTER_CDSP,
|
||||
// MASTER_GPU,
|
||||
// MASTER_DISPLAY,
|
||||
MASTER_COUNT, // Total master sources
|
||||
|
||||
// Subsystem stats. (Numbering starts at MASTER_COUNT to preserve
|
||||
// contiguous source numbering.)
|
||||
SUBSYSTEM_WLAN = MASTER_COUNT,
|
||||
// Uncomment when Citadel returns
|
||||
//SUBSYSTEM_CITADEL,
|
||||
|
||||
// Don't add any lines after this line
|
||||
STATS_SOURCE_COUNT, // Total sources of any kind excluding system states
|
||||
SUBSYSTEM_COUNT = STATS_SOURCE_COUNT - MASTER_COUNT,
|
||||
|
||||
SYSTEM_STATES
|
||||
};
|
||||
|
||||
enum master_sleep_states {
|
||||
MASTER_SLEEP = 0,
|
||||
|
||||
//Don't add any lines after this line
|
||||
MASTER_SLEEP_STATE_COUNT
|
||||
};
|
||||
|
||||
enum master_stats {
|
||||
SLEEP_CUMULATIVE_DURATION_MS = 0,
|
||||
SLEEP_ENTER_COUNT,
|
||||
SLEEP_LAST_ENTER_TSTAMP_MS,
|
||||
|
||||
//Don't add any lines after this line
|
||||
MASTER_STATS_COUNT
|
||||
};
|
||||
|
||||
enum wlan_sleep_states {
|
||||
WLAN_STATE_ACTIVE = 0,
|
||||
WLAN_STATE_DEEP_SLEEP,
|
||||
|
||||
//Don't add any lines after this line
|
||||
WLAN_SLEEP_STATE_COUNT
|
||||
};
|
||||
|
||||
// Note that stats for both WLAN sleep states are in a single section of the
|
||||
// source file, so there's only 1 stats section despite having 2 states
|
||||
enum wlan_stats {
|
||||
CUMULATIVE_SLEEP_TIME_MS = 0,
|
||||
CUMULATIVE_TOTAL_ON_TIME_MS,
|
||||
DEEP_SLEEP_ENTER_COUNTER,
|
||||
LAST_DEEP_SLEEP_ENTER_TSTAMP_MS,
|
||||
|
||||
//Don't add any lines after this line
|
||||
WLAN_STATS_COUNT
|
||||
};
|
||||
|
||||
enum system_sleep_states {
|
||||
SYSTEM_STATE_AOSD = 0,
|
||||
SYSTEM_STATE_CXSD,
|
||||
|
||||
//Don't add any lines after this line
|
||||
SYSTEM_SLEEP_STATE_COUNT
|
||||
};
|
||||
|
||||
enum system_state_stats {
|
||||
TOTAL_COUNT = 0,
|
||||
ACCUMULATED_TIME_MS,
|
||||
|
||||
//Don't add any lines after this line
|
||||
SYSTEM_STATE_STATS_COUNT
|
||||
};
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
struct stats_section {
|
||||
enum stats_source source;
|
||||
const char *label;
|
||||
const char **stats_labels;
|
||||
size_t num_stats;
|
||||
};
|
||||
|
||||
int extract_master_stats(uint64_t *list, size_t list_length);
|
||||
int extract_wlan_stats(uint64_t *list, size_t list_length);
|
||||
int extract_system_stats(uint64_t *list, size_t list_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__POWER_HELPER_H__
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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 "android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr"
|
||||
|
||||
#include <android/log.h>
|
||||
#include <hidl/HidlTransportSupport.h>
|
||||
|
||||
#include "Power.h"
|
||||
|
||||
using android::sp;
|
||||
using android::status_t;
|
||||
using android::OK;
|
||||
|
||||
// libhwbinder:
|
||||
using android::hardware::configureRpcThreadpool;
|
||||
using android::hardware::joinRpcThreadpool;
|
||||
|
||||
// Generated HIDL files
|
||||
using android::hardware::power::V1_3::IPower;
|
||||
using android::hardware::power::V1_3::implementation::Power;
|
||||
|
||||
int main(int /* argc */, char** /* argv */) {
|
||||
ALOGI("Power HAL Service 1.3 is starting.");
|
||||
|
||||
android::sp<IPower> service = new Power();
|
||||
if (service == nullptr) {
|
||||
ALOGE("Can not create an instance of Power HAL Iface, exiting.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
configureRpcThreadpool(1, true /*callerWillJoin*/);
|
||||
|
||||
status_t status = service->registerAsService();
|
||||
if (status != OK) {
|
||||
ALOGE("Could not register service for Power HAL Iface (%d), exiting.", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ALOGI("Power Service is ready");
|
||||
joinRpcThreadpool();
|
||||
|
||||
// In normal operation, we don't expect the thread pool to exit
|
||||
ALOGE("Power Service is shutting down");
|
||||
return 1;
|
||||
}
|
@ -57,10 +57,11 @@ int open_ts_input() {
|
||||
} // anonymous namespace
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace google {
|
||||
namespace hardware {
|
||||
namespace power {
|
||||
namespace impl {
|
||||
namespace pixel {
|
||||
|
||||
static constexpr int kInputEventWakeupModeOff = 4;
|
||||
static constexpr int kInputEventWakeupModeOn = 5;
|
||||
@ -99,8 +100,9 @@ bool setDeviceSpecificMode(Mode type, bool enabled) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pixel
|
||||
} // namespace impl
|
||||
} // namespace power
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace google
|
||||
} // namespace aidl
|
||||
|
@ -248,7 +248,7 @@ PRODUCT_PACKAGES += \
|
||||
|
||||
# Power
|
||||
PRODUCT_PACKAGES += \
|
||||
android.hardware.power@1.3-service.xiaomi_sdm845-libperfmgr
|
||||
android.hardware.power-service.xiaomi-libperfmgr
|
||||
|
||||
PRODUCT_COPY_FILES += \
|
||||
$(LOCAL_PATH)/power/configs/powerhint.json:$(TARGET_COPY_OUT_VENDOR)/etc/powerhint.json
|
||||
@ -292,6 +292,8 @@ PRODUCT_PACKAGES += \
|
||||
# Soong namespaces
|
||||
PRODUCT_SOONG_NAMESPACES += \
|
||||
$(LOCAL_PATH) \
|
||||
hardware/google/interfaces \
|
||||
hardware/google/pixel \
|
||||
hardware/xiaomi
|
||||
|
||||
# Telephony
|
||||
|
2
sepolicy/vendor/file_contexts
vendored
2
sepolicy/vendor/file_contexts
vendored
@ -44,7 +44,7 @@
|
||||
/vendor/bin/hw/android\.hardware\.biometrics\.fingerprint@2\.1-service\.xiaomi_sdm845 u:object_r:hal_fingerprint_default_exec:s0
|
||||
/vendor/bin/hw/android\.hardware\.light@2\.0-service\.xiaomi_sdm845 u:object_r:hal_light_default_exec:s0
|
||||
/vendor/bin/hw/android\.hardware\.neuralnetworks@1\.2-service-qti u:object_r:hal_neuralnetworks_default_exec:s0
|
||||
/vendor/bin/hw/android\.hardware\.power@1\.3-service\.xiaomi_sdm845-libperfmgr u:object_r:hal_power_default_exec:s0
|
||||
/vendor/bin/hw/android\.hardware\.power-service\.xiaomi-libperfmgr u:object_r:hal_power_default_exec:s0
|
||||
/vendor/bin/hw/vendor\.lineage\.biometrics\.fingerprint\.inscreen@1.0-service\.xiaomi_sdm845 u:object_r:hal_lineage_fod_sdm845_exec:s0
|
||||
/vendor/bin/hw/vendor\.lineage\.livedisplay@2\.0-service\.xiaomi_sdm845 u:object_r:hal_lineage_livedisplay_qti_exec:s0
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user